# HG changeset patch # User Chris Cannam # Date 1495443697 -3600 # Node ID 45360b968bf4859a4e455eafec608629e2401e53 # Parent 206f0eb279b8db930c3970bfd1fe01d19870dced Cap'n Proto v0.6 + build for OSX diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/any.h --- a/osx/include/capnp/any.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/any.h Mon May 22 10:01:37 2017 +0100 @@ -1,1047 +1,1073 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_ANY_H_ -#define CAPNP_ANY_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "layout.h" -#include "pointer-helpers.h" -#include "orphan.h" -#include "list.h" - -namespace capnp { - -class StructSchema; -class ListSchema; -class InterfaceSchema; -class Orphanage; -class ClientHook; -class PipelineHook; -struct PipelineOp; -struct AnyPointer; - -struct AnyList { - AnyList() = delete; - - class Reader; - class Builder; -}; - -struct AnyStruct { - AnyStruct() = delete; - - class Reader; - class Builder; - class Pipeline; -}; - -template<> -struct List { - List() = delete; - - class Reader; - class Builder; -}; - -namespace _ { // private -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -} // namespace _ (private) - -// ======================================================================================= -// AnyPointer! - -enum class Equality { - NOT_EQUAL, - EQUAL, - UNKNOWN_CONTAINS_CAPS -}; - -kj::StringPtr KJ_STRINGIFY(Equality res); - -struct AnyPointer { - // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary - // object. - - AnyPointer() = delete; - - class Reader { - public: - typedef AnyPointer Reads; - - Reader() = default; - inline Reader(_::PointerReader reader): reader(reader) {} - - inline MessageSize targetSize() const; - // Get the total size of the target object and all its children. - - inline PointerType getPointerType() const; - - inline bool isNull() const { return getPointerType() == PointerType::NULL_; } - inline bool isStruct() const { return getPointerType() == PointerType::STRUCT; } - inline bool isList() const { return getPointerType() == PointerType::LIST; } - inline bool isCapability() const { return getPointerType() == PointerType::CAPABILITY; } - - Equality equals(AnyPointer::Reader right); - bool operator==(AnyPointer::Reader right); - inline bool operator!=(AnyPointer::Reader right) { - return !(*this == right); - } - - template - inline ReaderFor getAs() const; - // Valid for T = any generated struct type, interface type, List, Text, or Data. - - template - inline ReaderFor getAs(StructSchema schema) const; - // Only valid for T = DynamicStruct. Requires `#include `. - - template - inline ReaderFor getAs(ListSchema schema) const; - // Only valid for T = DynamicList. Requires `#include `. - - template - inline ReaderFor getAs(InterfaceSchema schema) const; - // Only valid for T = DynamicCapability. Requires `#include `. - -#if !CAPNP_LITE - kj::Own getPipelinedCap(kj::ArrayPtr ops) const; - // Used by RPC system to implement pipelining. Applications generally shouldn't use this - // directly. -#endif // !CAPNP_LITE - - private: - _::PointerReader reader; - friend struct AnyPointer; - friend class Orphanage; - friend class CapReaderContext; - friend struct _::PointerHelpers; - }; - - class Builder { - public: - typedef AnyPointer Builds; - - Builder() = delete; - inline Builder(decltype(nullptr)) {} - inline Builder(_::PointerBuilder builder): builder(builder) {} - - inline MessageSize targetSize() const; - // Get the total size of the target object and all its children. - - inline PointerType getPointerType(); - - inline bool isNull() { return getPointerType() == PointerType::NULL_; } - inline bool isStruct() { return getPointerType() == PointerType::STRUCT; } - inline bool isList() { return getPointerType() == PointerType::LIST; } - inline bool isCapability() { return getPointerType() == PointerType::CAPABILITY; } - - inline Equality equals(AnyPointer::Reader right) { - return asReader().equals(right); - } - inline bool operator==(AnyPointer::Reader right) { - return asReader() == right; - } - inline bool operator!=(AnyPointer::Reader right) { - return !(*this == right); - } - - inline void clear(); - // Set to null. - - template - inline BuilderFor getAs(); - // Valid for T = any generated struct type, List, Text, or Data. - - template - inline BuilderFor getAs(StructSchema schema); - // Only valid for T = DynamicStruct. Requires `#include `. - - template - inline BuilderFor getAs(ListSchema schema); - // Only valid for T = DynamicList. Requires `#include `. - - template - inline BuilderFor getAs(InterfaceSchema schema); - // Only valid for T = DynamicCapability. Requires `#include `. - - template - inline BuilderFor initAs(); - // Valid for T = any generated struct type. - - template - inline BuilderFor initAs(uint elementCount); - // Valid for T = List, Text, or Data. - - template - inline BuilderFor initAs(StructSchema schema); - // Only valid for T = DynamicStruct. Requires `#include `. - - template - inline BuilderFor initAs(ListSchema schema, uint elementCount); - // Only valid for T = DynamicList. Requires `#include `. - - inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount); - // Note: Does not accept INLINE_COMPOSITE for elementSize. - - inline List::Builder initAsListOfAnyStruct( - uint dataWordCount, uint pointerCount, uint elementCount); - - inline AnyStruct::Builder initAsAnyStruct(uint dataWordCount, uint pointerCount); - - template - inline void setAs(ReaderFor value); - // Valid for ReaderType = T::Reader for T = any generated struct type, List, Text, Data, - // DynamicStruct, or DynamicList (the dynamic types require `#include `). - - template - inline void setAs(std::initializer_list>> list); - // Valid for T = List. - - template - inline void setCanonicalAs(ReaderFor value); - - inline void set(Reader value) { builder.copyFrom(value.reader); } - // Set to a copy of another AnyPointer. - - inline void setCanonical(Reader value) { builder.copyFrom(value.reader, true); } - - template - inline void adopt(Orphan&& orphan); - // Valid for T = any generated struct type, List, Text, Data, DynamicList, DynamicStruct, - // or DynamicValue (the dynamic types require `#include `). - - template - inline Orphan disownAs(); - // Valid for T = any generated struct type, List, Text, Data. - - template - inline Orphan disownAs(StructSchema schema); - // Only valid for T = DynamicStruct. Requires `#include `. - - template - inline Orphan disownAs(ListSchema schema); - // Only valid for T = DynamicList. Requires `#include `. - - template - inline Orphan disownAs(InterfaceSchema schema); - // Only valid for T = DynamicCapability. Requires `#include `. - - inline Orphan disown(); - // Disown without a type. - - inline Reader asReader() const { return Reader(builder.asReader()); } - inline operator Reader() const { return Reader(builder.asReader()); } - - private: - _::PointerBuilder builder; - friend class Orphanage; - friend class CapBuilderContext; - friend struct _::PointerHelpers; - }; - -#if !CAPNP_LITE - class Pipeline { - public: - typedef AnyPointer Pipelines; - - inline Pipeline(decltype(nullptr)) {} - inline explicit Pipeline(kj::Own&& hook): hook(kj::mv(hook)) {} - - Pipeline noop(); - // Just make a copy. - - Pipeline getPointerField(uint16_t pointerIndex); - // Deprecated. In the future, we should use .asAnyStruct.getPointerField. - - inline AnyStruct::Pipeline asAnyStruct(); - - kj::Own asCap(); - // Expect that the result is a capability and construct a pipelined version of it now. - - inline kj::Own releasePipelineHook() { return kj::mv(hook); } - // For use by RPC implementations. - - template ) == Kind::INTERFACE>> - inline operator T() { return T(asCap()); } - - private: - kj::Own hook; - kj::Array ops; - - inline Pipeline(kj::Own&& hook, kj::Array&& ops) - : hook(kj::mv(hook)), ops(kj::mv(ops)) {} - - friend class LocalClient; - friend class PipelineHook; - friend class AnyStruct::Pipeline; - }; -#endif // !CAPNP_LITE -}; - -template <> -class Orphan { - // An orphaned object of unknown type. - -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - inline Orphan(_::OrphanBuilder&& builder) - : builder(kj::mv(builder)) {} - - Orphan& operator=(Orphan&&) = default; - - template - inline Orphan(Orphan&& other): builder(kj::mv(other.builder)) {} - template - inline Orphan& operator=(Orphan&& other) { builder = kj::mv(other.builder); return *this; } - // Cast from typed orphan. - - // It's not possible to get an AnyPointer::{Reader,Builder} directly since there is no - // underlying pointer (the pointer would normally live in the parent, but this object is - // orphaned). It is possible, however, to request typed readers/builders. - - template - inline BuilderFor getAs(); - template - inline BuilderFor getAs(StructSchema schema); - template - inline BuilderFor getAs(ListSchema schema); - template - inline typename T::Client getAs(InterfaceSchema schema); - template - inline ReaderFor getAsReader() const; - template - inline ReaderFor getAsReader(StructSchema schema) const; - template - inline ReaderFor getAsReader(ListSchema schema) const; - template - inline typename T::Client getAsReader(InterfaceSchema schema) const; - - template - inline Orphan releaseAs(); - template - inline Orphan releaseAs(StructSchema schema); - template - inline Orphan releaseAs(ListSchema schema); - template - inline Orphan releaseAs(InterfaceSchema schema); - // Down-cast the orphan to a specific type. - - inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } - -private: - _::OrphanBuilder builder; - - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend class Orphan; - friend class AnyPointer::Builder; -}; - -template struct AnyTypeFor_; -template <> struct AnyTypeFor_ { typedef AnyStruct Type; }; -template <> struct AnyTypeFor_ { typedef AnyList Type; }; - -template -using AnyTypeFor = typename AnyTypeFor_::Type; - -template -inline ReaderFor>> toAny(T&& value) { - return ReaderFor>>( - _::PointerHelpers>::getInternalReader(value)); -} -template -inline BuilderFor>> toAny(T&& value) { - return BuilderFor>>( - _::PointerHelpers>::getInternalBuilder(kj::mv(value))); -} - -template <> -struct List { - // Note: This cannot be used for a list of structs, since such lists are not encoded as pointer - // lists! Use List. - - List() = delete; - - class Reader { - public: - typedef List Reads; - - inline Reader(): reader(ElementSize::POINTER) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline AnyPointer::Reader operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS)); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List Builds; - - Builder() = delete; - inline Builder(decltype(nullptr)): builder(ElementSize::POINTER) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline AnyPointer::Builder operator[](uint index) { - KJ_IREQUIRE(index < size()); - return AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS)); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; - }; -}; - -class AnyStruct::Reader { -public: - typedef AnyStruct Reads; - - Reader() = default; - inline Reader(_::StructReader reader): _reader(reader) {} - - template ) == Kind::STRUCT>> - inline Reader(T&& value) - : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} - - kj::ArrayPtr getDataSection() { - return _reader.getDataSectionAsBlob(); - } - List::Reader getPointerSection() { - return List::Reader(_reader.getPointerSectionAsList()); - } - - kj::Array canonicalize() { - return _reader.canonicalize(); - } - - Equality equals(AnyStruct::Reader right); - bool operator==(AnyStruct::Reader right); - inline bool operator!=(AnyStruct::Reader right) { - return !(*this == right); - } - - template - ReaderFor as() const { - // T must be a struct type. - return typename T::Reader(_reader); - } -private: - _::StructReader _reader; - - template - friend struct _::PointerHelpers; - friend class Orphanage; -}; - -class AnyStruct::Builder { -public: - typedef AnyStruct Builds; - - inline Builder(decltype(nullptr)) {} - inline Builder(_::StructBuilder builder): _builder(builder) {} - -#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. - template ) == Kind::STRUCT>> - inline Builder(T&& value) - : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} -#endif - - inline kj::ArrayPtr getDataSection() { - return _builder.getDataSectionAsBlob(); - } - List::Builder getPointerSection() { - return List::Builder(_builder.getPointerSectionAsList()); - } - - inline Equality equals(AnyStruct::Reader right) { - return asReader().equals(right); - } - inline bool operator==(AnyStruct::Reader right) { - return asReader() == right; - } - inline bool operator!=(AnyStruct::Reader right) { - return !(*this == right); - } - - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return Reader(_builder.asReader()); } - - template - BuilderFor as() { - // T must be a struct type. - return typename T::Builder(_builder); - } -private: - _::StructBuilder _builder; - friend class Orphanage; - friend class CapBuilderContext; -}; - -#if !CAPNP_LITE -class AnyStruct::Pipeline { -public: - inline Pipeline(decltype(nullptr)): typeless(nullptr) {} - inline explicit Pipeline(AnyPointer::Pipeline&& typeless) - : typeless(kj::mv(typeless)) {} - - inline AnyPointer::Pipeline getPointerField(uint16_t pointerIndex) { - // Return a new Promise representing a sub-object of the result. `pointerIndex` is the index - // of the sub-object within the pointer section of the result (the result must be a struct). - // - // TODO(perf): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies. - // Also make `ops` into a Vector to optimize this. - return typeless.getPointerField(pointerIndex); - } - -private: - AnyPointer::Pipeline typeless; -}; -#endif // !CAPNP_LITE - -class List::Reader { -public: - typedef List Reads; - - inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline AnyStruct::Reader operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return AnyStruct::Reader(reader.getStructElement(index * ELEMENTS)); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; -}; - -class List::Builder { -public: - typedef List Builds; - - Builder() = delete; - inline Builder(decltype(nullptr)): builder(ElementSize::INLINE_COMPOSITE) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline AnyStruct::Builder operator[](uint index) { - KJ_IREQUIRE(index < size()); - return AnyStruct::Builder(builder.getStructElement(index * ELEMENTS)); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - -private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; -}; - -class AnyList::Reader { -public: - typedef AnyList Reads; - - inline Reader(): _reader(ElementSize::VOID) {} - inline Reader(_::ListReader reader): _reader(reader) {} - -#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. - template ) == Kind::LIST>> - inline Reader(T&& value) - : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} -#endif - - inline ElementSize getElementSize() { return _reader.getElementSize(); } - inline uint size() { return _reader.size() / ELEMENTS; } - - inline kj::ArrayPtr getRawBytes() { return _reader.asRawBytes(); } - - Equality equals(AnyList::Reader right); - bool operator==(AnyList::Reader right); - inline bool operator!=(AnyList::Reader right) { - return !(*this == right); - } - - template ReaderFor as() { - // T must be List. - return ReaderFor(_reader); - } -private: - _::ListReader _reader; - - template - friend struct _::PointerHelpers; - friend class Orphanage; -}; - -class AnyList::Builder { -public: - typedef AnyList Builds; - - inline Builder(decltype(nullptr)): _builder(ElementSize::VOID) {} - inline Builder(_::ListBuilder builder): _builder(builder) {} - -#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. - template ) == Kind::LIST>> - inline Builder(T&& value) - : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} -#endif - - inline ElementSize getElementSize() { return _builder.getElementSize(); } - inline uint size() { return _builder.size() / ELEMENTS; } - - Equality equals(AnyList::Reader right); - inline bool operator==(AnyList::Reader right) { - return asReader() == right; - } - inline bool operator!=(AnyList::Reader right) { - return !(*this == right); - } - - template BuilderFor as() { - // T must be List. - return BuilderFor(_builder); - } - - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return Reader(_builder.asReader()); } - -private: - _::ListBuilder _builder; - - friend class Orphanage; -}; - -// ======================================================================================= -// Pipeline helpers -// -// These relate to capabilities, but we don't declare them in capability.h because generated code -// for structs needs to know about these, even in files that contain no interfaces. - -#if !CAPNP_LITE - -struct PipelineOp { - // Corresponds to rpc.capnp's PromisedAnswer.Op. - - enum Type { - NOOP, // for convenience - - GET_POINTER_FIELD - - // There may be other types in the future... - }; - - Type type; - union { - uint16_t pointerIndex; // for GET_POINTER_FIELD - }; -}; - -class PipelineHook { - // Represents a currently-running call, and implements pipelined requests on its result. - -public: - virtual kj::Own addRef() = 0; - // Increment this object's reference count. - - virtual kj::Own getPipelinedCap(kj::ArrayPtr ops) = 0; - // Extract a promised Capability from the results. - - virtual kj::Own getPipelinedCap(kj::Array&& ops); - // Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases. - // Default implementation just calls the other version. - - template > - static inline kj::Own from(Pipeline&& pipeline); - -private: - template struct FromImpl; -}; - -#endif // !CAPNP_LITE - -// ======================================================================================= -// Inline implementation details - -inline MessageSize AnyPointer::Reader::targetSize() const { - return reader.targetSize().asPublic(); -} - -inline PointerType AnyPointer::Reader::getPointerType() const { - return reader.getPointerType(); -} - -template -inline ReaderFor AnyPointer::Reader::getAs() const { - return _::PointerHelpers::get(reader); -} - -inline MessageSize AnyPointer::Builder::targetSize() const { - return asReader().targetSize(); -} - -inline PointerType AnyPointer::Builder::getPointerType() { - return builder.getPointerType(); -} - -inline void AnyPointer::Builder::clear() { - return builder.clear(); -} - -template -inline BuilderFor AnyPointer::Builder::getAs() { - return _::PointerHelpers::get(builder); -} - -template -inline BuilderFor AnyPointer::Builder::initAs() { - return _::PointerHelpers::init(builder); -} - -template -inline BuilderFor AnyPointer::Builder::initAs(uint elementCount) { - return _::PointerHelpers::init(builder, elementCount); -} - -inline AnyList::Builder AnyPointer::Builder::initAsAnyList( - ElementSize elementSize, uint elementCount) { - return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS)); -} - -inline List::Builder AnyPointer::Builder::initAsListOfAnyStruct( - uint dataWordCount, uint pointerCount, uint elementCount) { - return List::Builder(builder.initStructList(elementCount * ELEMENTS, - _::StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); -} - -inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(uint dataWordCount, uint pointerCount) { - return AnyStruct::Builder(builder.initStruct( - _::StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); -} - -template -inline void AnyPointer::Builder::setAs(ReaderFor value) { - return _::PointerHelpers::set(builder, value); -} - -template -inline void AnyPointer::Builder::setCanonicalAs(ReaderFor value) { - return _::PointerHelpers::setCanonical(builder, value); -} - -template -inline void AnyPointer::Builder::setAs( - std::initializer_list>> list) { - return _::PointerHelpers::set(builder, list); -} - -template -inline void AnyPointer::Builder::adopt(Orphan&& orphan) { - _::PointerHelpers::adopt(builder, kj::mv(orphan)); -} - -template -inline Orphan AnyPointer::Builder::disownAs() { - return _::PointerHelpers::disown(builder); -} - -inline Orphan AnyPointer::Builder::disown() { - return Orphan(builder.disown()); -} - -template <> struct ReaderFor_ { typedef AnyPointer::Reader Type; }; -template <> struct BuilderFor_ { typedef AnyPointer::Builder Type; }; -template <> struct ReaderFor_ { typedef AnyStruct::Reader Type; }; -template <> struct BuilderFor_ { typedef AnyStruct::Builder Type; }; - -template <> -struct Orphanage::GetInnerReader { - static inline _::PointerReader apply(const AnyPointer::Reader& t) { - return t.reader; - } -}; - -template <> -struct Orphanage::GetInnerBuilder { - static inline _::PointerBuilder apply(AnyPointer::Builder& t) { - return t.builder; - } -}; - -template <> -struct Orphanage::GetInnerReader { - static inline _::StructReader apply(const AnyStruct::Reader& t) { - return t._reader; - } -}; - -template <> -struct Orphanage::GetInnerBuilder { - static inline _::StructBuilder apply(AnyStruct::Builder& t) { - return t._builder; - } -}; - -template <> -struct Orphanage::GetInnerReader { - static inline _::ListReader apply(const AnyList::Reader& t) { - return t._reader; - } -}; - -template <> -struct Orphanage::GetInnerBuilder { - static inline _::ListBuilder apply(AnyList::Builder& t) { - return t._builder; - } -}; - -template -inline BuilderFor Orphan::getAs() { - return _::OrphanGetImpl::apply(builder); -} -template -inline ReaderFor Orphan::getAsReader() const { - return _::OrphanGetImpl::applyReader(builder); -} -template -inline Orphan Orphan::releaseAs() { - return Orphan(kj::mv(builder)); -} - -// Using AnyPointer as the template type should work... - -template <> -inline typename AnyPointer::Reader AnyPointer::Reader::getAs() const { - return *this; -} -template <> -inline typename AnyPointer::Builder AnyPointer::Builder::getAs() { - return *this; -} -template <> -inline typename AnyPointer::Builder AnyPointer::Builder::initAs() { - clear(); - return *this; -} -template <> -inline void AnyPointer::Builder::setAs(AnyPointer::Reader value) { - return builder.copyFrom(value.reader); -} -template <> -inline void AnyPointer::Builder::adopt(Orphan&& orphan) { - builder.adopt(kj::mv(orphan.builder)); -} -template <> -inline Orphan AnyPointer::Builder::disownAs() { - return Orphan(builder.disown()); -} -template <> -inline Orphan Orphan::releaseAs() { - return kj::mv(*this); -} - -namespace _ { // private - -// Specialize PointerHelpers for AnyPointer. - -template <> -struct PointerHelpers { - static inline AnyPointer::Reader get(PointerReader reader, - const void* defaultValue = nullptr, - uint defaultBytes = 0) { - return AnyPointer::Reader(reader); - } - static inline AnyPointer::Builder get(PointerBuilder builder, - const void* defaultValue = nullptr, - uint defaultBytes = 0) { - return AnyPointer::Builder(builder); - } - static inline void set(PointerBuilder builder, AnyPointer::Reader value) { - AnyPointer::Builder(builder).set(value); - } - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder) { - return Orphan(builder.disown()); - } - static inline _::PointerReader getInternalReader(const AnyPointer::Reader& reader) { - return reader.reader; - } - static inline _::PointerBuilder getInternalBuilder(AnyPointer::Builder&& builder) { - return builder.builder; - } -}; - -template <> -struct PointerHelpers { - static inline AnyStruct::Reader get( - PointerReader reader, const word* defaultValue = nullptr) { - return AnyStruct::Reader(reader.getStruct(defaultValue)); - } - static inline AnyStruct::Builder get( - PointerBuilder builder, const word* defaultValue = nullptr) { - // TODO(someday): Allow specifying the size somehow? - return AnyStruct::Builder(builder.getStruct( - _::StructSize(0 * WORDS, 0 * POINTERS), defaultValue)); - } - static inline void set(PointerBuilder builder, AnyStruct::Reader value) { - builder.setStruct(value._reader); - } - static inline AnyStruct::Builder init( - PointerBuilder builder, uint dataWordCount, uint pointerCount) { - return AnyStruct::Builder(builder.initStruct( - StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); - } - - // TODO(soon): implement these - static void adopt(PointerBuilder builder, Orphan&& value); - static Orphan disown(PointerBuilder builder); -}; - -template <> -struct PointerHelpers { - static inline AnyList::Reader get( - PointerReader reader, const word* defaultValue = nullptr) { - return AnyList::Reader(reader.getListAnySize(defaultValue)); - } - static inline AnyList::Builder get( - PointerBuilder builder, const word* defaultValue = nullptr) { - return AnyList::Builder(builder.getListAnySize(defaultValue)); - } - static inline void set(PointerBuilder builder, AnyList::Reader value) { - builder.setList(value._reader); - } - static inline AnyList::Builder init( - PointerBuilder builder, ElementSize elementSize, uint elementCount) { - return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS)); - } - static inline AnyList::Builder init( - PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) { - return AnyList::Builder(builder.initStructList( - elementCount * ELEMENTS, StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); - } - - // TODO(soon): implement these - static void adopt(PointerBuilder builder, Orphan&& value); - static Orphan disown(PointerBuilder builder); -}; - -template <> -struct OrphanGetImpl { - static inline AnyStruct::Builder apply(_::OrphanBuilder& builder) { - return AnyStruct::Builder(builder.asStruct(_::StructSize(0 * WORDS, 0 * POINTERS))); - } - static inline AnyStruct::Reader applyReader(const _::OrphanBuilder& builder) { - return AnyStruct::Reader(builder.asStructReader(_::StructSize(0 * WORDS, 0 * POINTERS))); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, _::StructSize(0 * WORDS, 0 * POINTERS)); - } -}; - -} // namespace _ (private) - -#if !CAPNP_LITE - -template -struct PipelineHook::FromImpl { - static inline kj::Own apply(typename T::Pipeline&& pipeline) { - return from(kj::mv(pipeline._typeless)); - } -}; - -template <> -struct PipelineHook::FromImpl { - static inline kj::Own apply(AnyPointer::Pipeline&& pipeline) { - return kj::mv(pipeline.hook); - } -}; - -template -inline kj::Own PipelineHook::from(Pipeline&& pipeline) { - return FromImpl::apply(kj::fwd(pipeline)); -} - -#endif // !CAPNP_LITE - -} // namespace capnp - -#endif // CAPNP_ANY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ANY_H_ +#define CAPNP_ANY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "pointer-helpers.h" +#include "orphan.h" +#include "list.h" + +namespace capnp { + +class StructSchema; +class ListSchema; +class InterfaceSchema; +class Orphanage; +class ClientHook; +class PipelineHook; +struct PipelineOp; +struct AnyPointer; + +struct AnyList { + AnyList() = delete; + + class Reader; + class Builder; +}; + +struct AnyStruct { + AnyStruct() = delete; + + class Reader; + class Builder; + class Pipeline; +}; + +template<> +struct List { + List() = delete; + + class Reader; + class Builder; +}; + +namespace _ { // private +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +} // namespace _ (private) + +// ======================================================================================= +// AnyPointer! + +enum class Equality { + NOT_EQUAL, + EQUAL, + UNKNOWN_CONTAINS_CAPS +}; + +kj::StringPtr KJ_STRINGIFY(Equality res); + +struct AnyPointer { + // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary + // object. + + AnyPointer() = delete; + + class Reader { + public: + typedef AnyPointer Reads; + + Reader() = default; + inline Reader(_::PointerReader reader): reader(reader) {} + + inline MessageSize targetSize() const; + // Get the total size of the target object and all its children. + + inline PointerType getPointerType() const; + + inline bool isNull() const { return getPointerType() == PointerType::NULL_; } + inline bool isStruct() const { return getPointerType() == PointerType::STRUCT; } + inline bool isList() const { return getPointerType() == PointerType::LIST; } + inline bool isCapability() const { return getPointerType() == PointerType::CAPABILITY; } + + Equality equals(AnyPointer::Reader right); + bool operator==(AnyPointer::Reader right); + inline bool operator!=(AnyPointer::Reader right) { + return !(*this == right); + } + + template + inline ReaderFor getAs() const; + // Valid for T = any generated struct type, interface type, List, Text, or Data. + + template + inline ReaderFor getAs(StructSchema schema) const; + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline ReaderFor getAs(ListSchema schema) const; + // Only valid for T = DynamicList. Requires `#include `. + + template + inline ReaderFor getAs(InterfaceSchema schema) const; + // Only valid for T = DynamicCapability. Requires `#include `. + +#if !CAPNP_LITE + kj::Own getPipelinedCap(kj::ArrayPtr ops) const; + // Used by RPC system to implement pipelining. Applications generally shouldn't use this + // directly. +#endif // !CAPNP_LITE + + private: + _::PointerReader reader; + friend struct AnyPointer; + friend class Orphanage; + friend class CapReaderContext; + friend struct _::PointerHelpers; + }; + + class Builder { + public: + typedef AnyPointer Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)) {} + inline Builder(_::PointerBuilder builder): builder(builder) {} + + inline MessageSize targetSize() const; + // Get the total size of the target object and all its children. + + inline PointerType getPointerType(); + + inline bool isNull() { return getPointerType() == PointerType::NULL_; } + inline bool isStruct() { return getPointerType() == PointerType::STRUCT; } + inline bool isList() { return getPointerType() == PointerType::LIST; } + inline bool isCapability() { return getPointerType() == PointerType::CAPABILITY; } + + inline Equality equals(AnyPointer::Reader right) { + return asReader().equals(right); + } + inline bool operator==(AnyPointer::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyPointer::Reader right) { + return !(*this == right); + } + + inline void clear(); + // Set to null. + + template + inline BuilderFor getAs(); + // Valid for T = any generated struct type, List, Text, or Data. + + template + inline BuilderFor getAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline BuilderFor getAs(ListSchema schema); + // Only valid for T = DynamicList. Requires `#include `. + + template + inline BuilderFor getAs(InterfaceSchema schema); + // Only valid for T = DynamicCapability. Requires `#include `. + + template + inline BuilderFor initAs(); + // Valid for T = any generated struct type. + + template + inline BuilderFor initAs(uint elementCount); + // Valid for T = List, Text, or Data. + + template + inline BuilderFor initAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline BuilderFor initAs(ListSchema schema, uint elementCount); + // Only valid for T = DynamicList. Requires `#include `. + + inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount); + // Note: Does not accept INLINE_COMPOSITE for elementSize. + + inline List::Builder initAsListOfAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount, uint elementCount); + + inline AnyStruct::Builder initAsAnyStruct(uint16_t dataWordCount, uint16_t pointerCount); + + template + inline void setAs(ReaderFor value); + // Valid for ReaderType = T::Reader for T = any generated struct type, List, Text, Data, + // DynamicStruct, or DynamicList (the dynamic types require `#include `). + + template + inline void setAs(std::initializer_list>> list); + // Valid for T = List. + + template + inline void setCanonicalAs(ReaderFor value); + + inline void set(Reader value) { builder.copyFrom(value.reader); } + // Set to a copy of another AnyPointer. + + inline void setCanonical(Reader value) { builder.copyFrom(value.reader, true); } + + template + inline void adopt(Orphan&& orphan); + // Valid for T = any generated struct type, List, Text, Data, DynamicList, DynamicStruct, + // or DynamicValue (the dynamic types require `#include `). + + template + inline Orphan disownAs(); + // Valid for T = any generated struct type, List, Text, Data. + + template + inline Orphan disownAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline Orphan disownAs(ListSchema schema); + // Only valid for T = DynamicList. Requires `#include `. + + template + inline Orphan disownAs(InterfaceSchema schema); + // Only valid for T = DynamicCapability. Requires `#include `. + + inline Orphan disown(); + // Disown without a type. + + inline Reader asReader() const { return Reader(builder.asReader()); } + inline operator Reader() const { return Reader(builder.asReader()); } + + private: + _::PointerBuilder builder; + friend class Orphanage; + friend class CapBuilderContext; + friend struct _::PointerHelpers; + }; + +#if !CAPNP_LITE + class Pipeline { + public: + typedef AnyPointer Pipelines; + + inline Pipeline(decltype(nullptr)) {} + inline explicit Pipeline(kj::Own&& hook): hook(kj::mv(hook)) {} + + Pipeline noop(); + // Just make a copy. + + Pipeline getPointerField(uint16_t pointerIndex); + // Deprecated. In the future, we should use .asAnyStruct.getPointerField. + + inline AnyStruct::Pipeline asAnyStruct(); + + kj::Own asCap(); + // Expect that the result is a capability and construct a pipelined version of it now. + + inline kj::Own releasePipelineHook() { return kj::mv(hook); } + // For use by RPC implementations. + + template ) == Kind::INTERFACE>> + inline operator T() { return T(asCap()); } + + private: + kj::Own hook; + kj::Array ops; + + inline Pipeline(kj::Own&& hook, kj::Array&& ops) + : hook(kj::mv(hook)), ops(kj::mv(ops)) {} + + friend class LocalClient; + friend class PipelineHook; + friend class AnyStruct::Pipeline; + }; +#endif // !CAPNP_LITE +}; + +template <> +class Orphan { + // An orphaned object of unknown type. + +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + inline Orphan(_::OrphanBuilder&& builder) + : builder(kj::mv(builder)) {} + + Orphan& operator=(Orphan&&) = default; + + template + inline Orphan(Orphan&& other): builder(kj::mv(other.builder)) {} + template + inline Orphan& operator=(Orphan&& other) { builder = kj::mv(other.builder); return *this; } + // Cast from typed orphan. + + // It's not possible to get an AnyPointer::{Reader,Builder} directly since there is no + // underlying pointer (the pointer would normally live in the parent, but this object is + // orphaned). It is possible, however, to request typed readers/builders. + + template + inline BuilderFor getAs(); + template + inline BuilderFor getAs(StructSchema schema); + template + inline BuilderFor getAs(ListSchema schema); + template + inline typename T::Client getAs(InterfaceSchema schema); + template + inline ReaderFor getAsReader() const; + template + inline ReaderFor getAsReader(StructSchema schema) const; + template + inline ReaderFor getAsReader(ListSchema schema) const; + template + inline typename T::Client getAsReader(InterfaceSchema schema) const; + + template + inline Orphan releaseAs(); + template + inline Orphan releaseAs(StructSchema schema); + template + inline Orphan releaseAs(ListSchema schema); + template + inline Orphan releaseAs(InterfaceSchema schema); + // Down-cast the orphan to a specific type. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + _::OrphanBuilder builder; + + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend class Orphan; + friend class AnyPointer::Builder; +}; + +template struct AnyTypeFor_; +template <> struct AnyTypeFor_ { typedef AnyStruct Type; }; +template <> struct AnyTypeFor_ { typedef AnyList Type; }; + +template +using AnyTypeFor = typename AnyTypeFor_::Type; + +template +inline ReaderFor>> toAny(T&& value) { + return ReaderFor>>( + _::PointerHelpers>::getInternalReader(value)); +} +template +inline BuilderFor>> toAny(T&& value) { + return BuilderFor>>( + _::PointerHelpers>::getInternalBuilder(kj::mv(value))); +} + +template <> +struct List { + // Note: This cannot be used for a list of structs, since such lists are not encoded as pointer + // lists! Use List. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline AnyPointer::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)): builder(ElementSize::POINTER) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline AnyPointer::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return AnyPointer::Builder(builder.getPointerElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; +}; + +class AnyStruct::Reader { +public: + typedef AnyStruct Reads; + + Reader() = default; + inline Reader(_::StructReader reader): _reader(reader) {} + + template ) == Kind::STRUCT>> + inline Reader(T&& value) + : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} + + kj::ArrayPtr getDataSection() { + return _reader.getDataSectionAsBlob(); + } + List::Reader getPointerSection() { + return List::Reader(_reader.getPointerSectionAsList()); + } + + kj::Array canonicalize() { + return _reader.canonicalize(); + } + + Equality equals(AnyStruct::Reader right); + bool operator==(AnyStruct::Reader right); + inline bool operator!=(AnyStruct::Reader right) { + return !(*this == right); + } + + template + ReaderFor as() const { + // T must be a struct type. + return typename T::Reader(_reader); + } +private: + _::StructReader _reader; + + template + friend struct _::PointerHelpers; + friend class Orphanage; +}; + +class AnyStruct::Builder { +public: + typedef AnyStruct Builds; + + inline Builder(decltype(nullptr)) {} + inline Builder(_::StructBuilder builder): _builder(builder) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::STRUCT>> + inline Builder(T&& value) + : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} +#endif + + inline kj::ArrayPtr getDataSection() { + return _builder.getDataSectionAsBlob(); + } + List::Builder getPointerSection() { + return List::Builder(_builder.getPointerSectionAsList()); + } + + inline Equality equals(AnyStruct::Reader right) { + return asReader().equals(right); + } + inline bool operator==(AnyStruct::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyStruct::Reader right) { + return !(*this == right); + } + + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return Reader(_builder.asReader()); } + + template + BuilderFor as() { + // T must be a struct type. + return typename T::Builder(_builder); + } +private: + _::StructBuilder _builder; + friend class Orphanage; + friend class CapBuilderContext; +}; + +#if !CAPNP_LITE +class AnyStruct::Pipeline { +public: + inline Pipeline(decltype(nullptr)): typeless(nullptr) {} + inline explicit Pipeline(AnyPointer::Pipeline&& typeless) + : typeless(kj::mv(typeless)) {} + + inline AnyPointer::Pipeline getPointerField(uint16_t pointerIndex) { + // Return a new Promise representing a sub-object of the result. `pointerIndex` is the index + // of the sub-object within the pointer section of the result (the result must be a struct). + // + // TODO(perf): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies. + // Also make `ops` into a Vector to optimize this. + return typeless.getPointerField(pointerIndex); + } + +private: + AnyPointer::Pipeline typeless; +}; +#endif // !CAPNP_LITE + +class List::Reader { +public: + typedef List Reads; + + inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline AnyStruct::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return AnyStruct::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; +}; + +class List::Builder { +public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)): builder(ElementSize::INLINE_COMPOSITE) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline AnyStruct::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return AnyStruct::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + +private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; +}; + +class AnyList::Reader { +public: + typedef AnyList Reads; + + inline Reader(): _reader(ElementSize::VOID) {} + inline Reader(_::ListReader reader): _reader(reader) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::LIST>> + inline Reader(T&& value) + : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} +#endif + + inline ElementSize getElementSize() { return _reader.getElementSize(); } + inline uint size() { return unbound(_reader.size() / ELEMENTS); } + + inline kj::ArrayPtr getRawBytes() { return _reader.asRawBytes(); } + + Equality equals(AnyList::Reader right); + bool operator==(AnyList::Reader right); + inline bool operator!=(AnyList::Reader right) { + return !(*this == right); + } + + template ReaderFor as() { + // T must be List. + return ReaderFor(_reader); + } +private: + _::ListReader _reader; + + template + friend struct _::PointerHelpers; + friend class Orphanage; +}; + +class AnyList::Builder { +public: + typedef AnyList Builds; + + inline Builder(decltype(nullptr)): _builder(ElementSize::VOID) {} + inline Builder(_::ListBuilder builder): _builder(builder) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::LIST>> + inline Builder(T&& value) + : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} +#endif + + inline ElementSize getElementSize() { return _builder.getElementSize(); } + inline uint size() { return unbound(_builder.size() / ELEMENTS); } + + Equality equals(AnyList::Reader right); + inline bool operator==(AnyList::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyList::Reader right) { + return !(*this == right); + } + + template BuilderFor as() { + // T must be List. + return BuilderFor(_builder); + } + + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return Reader(_builder.asReader()); } + +private: + _::ListBuilder _builder; + + friend class Orphanage; +}; + +// ======================================================================================= +// Pipeline helpers +// +// These relate to capabilities, but we don't declare them in capability.h because generated code +// for structs needs to know about these, even in files that contain no interfaces. + +#if !CAPNP_LITE + +struct PipelineOp { + // Corresponds to rpc.capnp's PromisedAnswer.Op. + + enum Type { + NOOP, // for convenience + + GET_POINTER_FIELD + + // There may be other types in the future... + }; + + Type type; + union { + uint16_t pointerIndex; // for GET_POINTER_FIELD + }; +}; + +class PipelineHook { + // Represents a currently-running call, and implements pipelined requests on its result. + +public: + virtual kj::Own addRef() = 0; + // Increment this object's reference count. + + virtual kj::Own getPipelinedCap(kj::ArrayPtr ops) = 0; + // Extract a promised Capability from the results. + + virtual kj::Own getPipelinedCap(kj::Array&& ops); + // Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases. + // Default implementation just calls the other version. + + template > + static inline kj::Own from(Pipeline&& pipeline); + +private: + template struct FromImpl; +}; + +#endif // !CAPNP_LITE + +// ======================================================================================= +// Inline implementation details + +inline MessageSize AnyPointer::Reader::targetSize() const { + return reader.targetSize().asPublic(); +} + +inline PointerType AnyPointer::Reader::getPointerType() const { + return reader.getPointerType(); +} + +template +inline ReaderFor AnyPointer::Reader::getAs() const { + return _::PointerHelpers::get(reader); +} + +inline MessageSize AnyPointer::Builder::targetSize() const { + return asReader().targetSize(); +} + +inline PointerType AnyPointer::Builder::getPointerType() { + return builder.getPointerType(); +} + +inline void AnyPointer::Builder::clear() { + return builder.clear(); +} + +template +inline BuilderFor AnyPointer::Builder::getAs() { + return _::PointerHelpers::get(builder); +} + +template +inline BuilderFor AnyPointer::Builder::initAs() { + return _::PointerHelpers::init(builder); +} + +template +inline BuilderFor AnyPointer::Builder::initAs(uint elementCount) { + return _::PointerHelpers::init(builder, elementCount); +} + +inline AnyList::Builder AnyPointer::Builder::initAsAnyList( + ElementSize elementSize, uint elementCount) { + return AnyList::Builder(builder.initList(elementSize, bounded(elementCount) * ELEMENTS)); +} + +inline List::Builder AnyPointer::Builder::initAsListOfAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { + return List::Builder(builder.initStructList(bounded(elementCount) * ELEMENTS, + _::StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); +} + +inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount) { + return AnyStruct::Builder(builder.initStruct( + _::StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); +} + +template +inline void AnyPointer::Builder::setAs(ReaderFor value) { + return _::PointerHelpers::set(builder, value); +} + +template +inline void AnyPointer::Builder::setCanonicalAs(ReaderFor value) { + return _::PointerHelpers::setCanonical(builder, value); +} + +template +inline void AnyPointer::Builder::setAs( + std::initializer_list>> list) { + return _::PointerHelpers::set(builder, list); +} + +template +inline void AnyPointer::Builder::adopt(Orphan&& orphan) { + _::PointerHelpers::adopt(builder, kj::mv(orphan)); +} + +template +inline Orphan AnyPointer::Builder::disownAs() { + return _::PointerHelpers::disown(builder); +} + +inline Orphan AnyPointer::Builder::disown() { + return Orphan(builder.disown()); +} + +template <> struct ReaderFor_ { typedef AnyPointer::Reader Type; }; +template <> struct BuilderFor_ { typedef AnyPointer::Builder Type; }; +template <> struct ReaderFor_ { typedef AnyStruct::Reader Type; }; +template <> struct BuilderFor_ { typedef AnyStruct::Builder Type; }; + +template <> +struct Orphanage::GetInnerReader { + static inline _::PointerReader apply(const AnyPointer::Reader& t) { + return t.reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::PointerBuilder apply(AnyPointer::Builder& t) { + return t.builder; + } +}; + +template <> +struct Orphanage::GetInnerReader { + static inline _::StructReader apply(const AnyStruct::Reader& t) { + return t._reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(AnyStruct::Builder& t) { + return t._builder; + } +}; + +template <> +struct Orphanage::GetInnerReader { + static inline _::ListReader apply(const AnyList::Reader& t) { + return t._reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(AnyList::Builder& t) { + return t._builder; + } +}; + +template +inline BuilderFor Orphan::getAs() { + return _::OrphanGetImpl::apply(builder); +} +template +inline ReaderFor Orphan::getAsReader() const { + return _::OrphanGetImpl::applyReader(builder); +} +template +inline Orphan Orphan::releaseAs() { + return Orphan(kj::mv(builder)); +} + +// Using AnyPointer as the template type should work... + +template <> +inline typename AnyPointer::Reader AnyPointer::Reader::getAs() const { + return *this; +} +template <> +inline typename AnyPointer::Builder AnyPointer::Builder::getAs() { + return *this; +} +template <> +inline typename AnyPointer::Builder AnyPointer::Builder::initAs() { + clear(); + return *this; +} +template <> +inline void AnyPointer::Builder::setAs(AnyPointer::Reader value) { + return builder.copyFrom(value.reader); +} +template <> +inline void AnyPointer::Builder::adopt(Orphan&& orphan) { + builder.adopt(kj::mv(orphan.builder)); +} +template <> +inline Orphan AnyPointer::Builder::disownAs() { + return Orphan(builder.disown()); +} +template <> +inline Orphan Orphan::releaseAs() { + return kj::mv(*this); +} + +namespace _ { // private + +// Specialize PointerHelpers for AnyPointer. + +template <> +struct PointerHelpers { + static inline AnyPointer::Reader get(PointerReader reader, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return AnyPointer::Reader(reader); + } + static inline AnyPointer::Builder get(PointerBuilder builder, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return AnyPointer::Builder(builder); + } + static inline void set(PointerBuilder builder, AnyPointer::Reader value) { + AnyPointer::Builder(builder).set(value); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } + static inline _::PointerReader getInternalReader(const AnyPointer::Reader& reader) { + return reader.reader; + } + static inline _::PointerBuilder getInternalBuilder(AnyPointer::Builder&& builder) { + return builder.builder; + } +}; + +template <> +struct PointerHelpers { + static inline AnyStruct::Reader get( + PointerReader reader, const word* defaultValue = nullptr) { + return AnyStruct::Reader(reader.getStruct(defaultValue)); + } + static inline AnyStruct::Builder get( + PointerBuilder builder, const word* defaultValue = nullptr) { + // TODO(someday): Allow specifying the size somehow? + return AnyStruct::Builder(builder.getStruct( + _::StructSize(ZERO * WORDS, ZERO * POINTERS), defaultValue)); + } + static inline void set(PointerBuilder builder, AnyStruct::Reader value) { + builder.setStruct(value._reader); + } + static inline AnyStruct::Builder init( + PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount) { + return AnyStruct::Builder(builder.initStruct( + StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); + } + + static void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +template <> +struct PointerHelpers { + static inline AnyList::Reader get( + PointerReader reader, const word* defaultValue = nullptr) { + return AnyList::Reader(reader.getListAnySize(defaultValue)); + } + static inline AnyList::Builder get( + PointerBuilder builder, const word* defaultValue = nullptr) { + return AnyList::Builder(builder.getListAnySize(defaultValue)); + } + static inline void set(PointerBuilder builder, AnyList::Reader value) { + builder.setList(value._reader); + } + static inline AnyList::Builder init( + PointerBuilder builder, ElementSize elementSize, uint elementCount) { + return AnyList::Builder(builder.initList( + elementSize, bounded(elementCount) * ELEMENTS)); + } + static inline AnyList::Builder init( + PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { + return AnyList::Builder(builder.initStructList( + bounded(elementCount) * ELEMENTS, + StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); + } + + static void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +template <> +struct OrphanGetImpl { + static inline AnyStruct::Builder apply(_::OrphanBuilder& builder) { + return AnyStruct::Builder(builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + static inline AnyStruct::Reader applyReader(const _::OrphanBuilder& builder) { + return AnyStruct::Reader(builder.asStructReader(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::StructSize(ZERO * WORDS, ZERO * POINTERS)); + } +}; + +template <> +struct OrphanGetImpl { + static inline AnyList::Builder apply(_::OrphanBuilder& builder) { + return AnyList::Builder(builder.asListAnySize()); + } + static inline AnyList::Reader applyReader(const _::OrphanBuilder& builder) { + return AnyList::Reader(builder.asListReaderAnySize()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +} // namespace _ (private) + +#if !CAPNP_LITE + +template +struct PipelineHook::FromImpl { + static inline kj::Own apply(typename T::Pipeline&& pipeline) { + return from(kj::mv(pipeline._typeless)); + } +}; + +template <> +struct PipelineHook::FromImpl { + static inline kj::Own apply(AnyPointer::Pipeline&& pipeline) { + return kj::mv(pipeline.hook); + } +}; + +template +inline kj::Own PipelineHook::from(Pipeline&& pipeline) { + return FromImpl::apply(kj::fwd(pipeline)); +} + +#endif // !CAPNP_LITE + +} // namespace capnp + +#endif // CAPNP_ANY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/arena.h --- a/osx/include/capnp/arena.h Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,457 +0,0 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_ARENA_H_ -#define CAPNP_ARENA_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#ifndef CAPNP_PRIVATE -#error "This header is only meant to be included by Cap'n Proto's own source code." -#endif - -#include -#include -#include -#include -#include "common.h" -#include "message.h" -#include "layout.h" -#include - -#if !CAPNP_LITE -#include "capability.h" -#endif // !CAPNP_LITE - -namespace capnp { - -#if !CAPNP_LITE -class ClientHook; -#endif // !CAPNP_LITE - -namespace _ { // private - -class SegmentReader; -class SegmentBuilder; -class Arena; -class BuilderArena; -class ReadLimiter; - -class Segment; -typedef kj::Id SegmentId; - -class ReadLimiter { - // Used to keep track of how much data has been processed from a message, and cut off further - // processing if and when a particular limit is reached. This is primarily intended to guard - // against maliciously-crafted messages which contain cycles or overlapping structures. Cycles - // and overlapping are not permitted by the Cap'n Proto format because in many cases they could - // be used to craft a deceptively small message which could consume excessive server resources to - // process, perhaps even sending it into an infinite loop. Actually detecting overlaps would be - // time-consuming, so instead we just keep track of how many words worth of data structures the - // receiver has actually dereferenced and error out if this gets too high. - // - // This counting takes place as you call getters (for non-primitive values) on the message - // readers. If you call the same getter twice, the data it returns may be double-counted. This - // should not be a big deal in most cases -- just set the read limit high enough that it will - // only trigger in unreasonable cases. - // - // This class is "safe" to use from multiple threads for its intended use case. Threads may - // overwrite each others' changes to the counter, but this is OK because it only means that the - // limit is enforced a bit less strictly -- it will still kick in eventually. - -public: - inline explicit ReadLimiter(); // No limit. - inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words. - - inline void reset(WordCount64 limit); - - KJ_ALWAYS_INLINE(bool canRead(WordCount amount, Arena* arena)); - - void unread(WordCount64 amount); - // Adds back some words to the limit. Useful when the caller knows they are double-reading - // some data. - -private: - volatile uint64_t limit; - // Current limit, decremented each time catRead() is called. Volatile because multiple threads - // could be trying to modify it at once. (This is not real thread-safety, but good enough for - // the purpose of this class. See class comment.) - - KJ_DISALLOW_COPY(ReadLimiter); -}; - -#if !CAPNP_LITE -class BrokenCapFactory { - // Callback for constructing broken caps. We use this so that we can avoid arena.c++ having a - // link-time dependency on capability code that lives in libcapnp-rpc. - -public: - virtual kj::Own newBrokenCap(kj::StringPtr description) = 0; - virtual kj::Own newNullCap() = 0; -}; -#endif // !CAPNP_LITE - -class SegmentReader { -public: - inline SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr ptr, - ReadLimiter* readLimiter); - - KJ_ALWAYS_INLINE(bool containsInterval(const void* from, const void* to)); - - KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); - // Indicates that the reader should pretend that `virtualAmount` additional data was read even - // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer - // where the element sizes are zero -- the sender could set the list size arbitrarily high and - // cause the receiver to iterate over this list even though the message itself is small, so we - // need to defend against DoS attacks based on this. - - inline Arena* getArena(); - inline SegmentId getSegmentId(); - - inline const word* getStartPtr(); - inline WordCount getOffsetTo(const word* ptr); - inline WordCount getSize(); - - inline kj::ArrayPtr getArray(); - - inline void unread(WordCount64 amount); - // Add back some words to the ReadLimiter. - -private: - Arena* arena; - SegmentId id; - kj::ArrayPtr ptr; - ReadLimiter* readLimiter; - - KJ_DISALLOW_COPY(SegmentReader); - - friend class SegmentBuilder; -}; - -class SegmentBuilder: public SegmentReader { -public: - inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr ptr, - ReadLimiter* readLimiter, size_t wordsUsed = 0); - inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr ptr, - ReadLimiter* readLimiter); - inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), - ReadLimiter* readLimiter); - - KJ_ALWAYS_INLINE(word* allocate(WordCount amount)); - - KJ_ALWAYS_INLINE(void checkWritable()); - // Throw an exception if the segment is read-only (meaning it is a reference to external data). - - KJ_ALWAYS_INLINE(word* getPtrUnchecked(WordCount offset)); - // Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e. - // a reference to external immutable data). - - inline BuilderArena* getArena(); - - inline kj::ArrayPtr currentlyAllocated(); - - inline void reset(); - - inline bool isWritable() { return !readOnly; } - - inline void tryTruncate(word* from, word* to); - // If `from` points just past the current end of the segment, then move the end back to `to`. - // Otherwise, do nothing. - - inline bool tryExtend(word* from, word* to); - // If `from` points just past the current end of the segment, and `to` is within the segment - // boundaries, then move the end up to `to` and return true. Otherwise, do nothing and return - // false. - -private: - word* pos; - // Pointer to a pointer to the current end point of the segment, i.e. the location where the - // next object should be allocated. - - bool readOnly; - - void throwNotWritable(); - - KJ_DISALLOW_COPY(SegmentBuilder); -}; - -class Arena { -public: - virtual ~Arena() noexcept(false); - - virtual SegmentReader* tryGetSegment(SegmentId id) = 0; - // Gets the segment with the given ID, or return nullptr if no such segment exists. - - virtual void reportReadLimitReached() = 0; - // Called to report that the read limit has been reached. See ReadLimiter, below. This invokes - // the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller - // will need to continue with default values. -}; - -class ReaderArena final: public Arena { -public: - ReaderArena(MessageReader* message); - ~ReaderArena() noexcept(false); - KJ_DISALLOW_COPY(ReaderArena); - - // implements Arena ------------------------------------------------ - SegmentReader* tryGetSegment(SegmentId id) override; - void reportReadLimitReached() override; - -private: - MessageReader* message; - ReadLimiter readLimiter; - - // Optimize for single-segment messages so that small messages are handled quickly. - SegmentReader segment0; - - typedef std::unordered_map> SegmentMap; - kj::MutexGuarded>> moreSegments; - // We need to mutex-guard the segment map because we lazily initialize segments when they are - // first requested, but a Reader is allowed to be used concurrently in multiple threads. Luckily - // this only applies to large messages. - // - // TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data - // in a different way, where you have to construct a new MessageReader in each thread (but - // possibly backed by the same data)? -}; - -class BuilderArena final: public Arena { - // A BuilderArena that does not allow the injection of capabilities. - -public: - explicit BuilderArena(MessageBuilder* message); - BuilderArena(MessageBuilder* message, kj::ArrayPtr segments); - ~BuilderArena() noexcept(false); - KJ_DISALLOW_COPY(BuilderArena); - - inline SegmentBuilder* getRootSegment() { return &segment0; } - - kj::ArrayPtr> getSegmentsForOutput(); - // Get an array of all the segments, suitable for writing out. This only returns the allocated - // portion of each segment, whereas tryGetSegment() returns something that includes - // not-yet-allocated space. - - inline CapTableBuilder* getLocalCapTable() { - // Return a CapTableBuilder that merely implements local loopback. That is, you can set - // capabilities, then read the same capabilities back, but there is no intent ever to transmit - // these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this - // by default. - // - // TODO(cleanup): It's sort of a hack that this exists. In theory, perhaps, unimbued - // MessageBuilders should throw exceptions on any attempt to access capability fields, like - // unimbued MessageReaders do. However, lots of code exists which uses MallocMessageBuilder - // as a temporary holder for data to be copied in and out (without being serialized), and it - // is expected that such data can include capabilities, which is admittedly reasonable. - // Therefore, all MessageBuilders must have a cap table by default. Arguably we should - // deprecate this usage and instead define a new helper type for this exact purpose. - - return &localCapTable; - } - - SegmentBuilder* getSegment(SegmentId id); - // Get the segment with the given id. Crashes or throws an exception if no such segment exists. - - struct AllocateResult { - SegmentBuilder* segment; - word* words; - }; - - AllocateResult allocate(WordCount amount); - // Find a segment with at least the given amount of space available and allocate the space. - // Note that allocating directly from a particular segment is much faster, but allocating from - // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific - // segment first if there is one, then fall back to the arena. - - SegmentBuilder* addExternalSegment(kj::ArrayPtr content); - // Add a new segment to the arena which points to some existing memory region. The segment is - // assumed to be completley full; the arena will never allocate from it. In fact, the segment - // is considered read-only. Any attempt to get a Builder pointing into this segment will throw - // an exception. Readers are allowed, however. - // - // This can be used to inject some external data into a message without a copy, e.g. embedding a - // large mmap'd file into a message as `Data` without forcing that data to actually be read in - // from disk (until the message itself is written out). `Orphanage` provides the public API for - // this feature. - - // implements Arena ------------------------------------------------ - SegmentReader* tryGetSegment(SegmentId id) override; - void reportReadLimitReached() override; - -private: - MessageBuilder* message; - ReadLimiter dummyLimiter; - - class LocalCapTable: public CapTableBuilder { -#if !CAPNP_LITE - public: - kj::Maybe> extractCap(uint index) override; - uint injectCap(kj::Own&& cap) override; - void dropCap(uint index) override; - - private: - kj::Vector>> capTable; -#endif // ! CAPNP_LITE - }; - - LocalCapTable localCapTable; - - SegmentBuilder segment0; - kj::ArrayPtr segment0ForOutput; - - struct MultiSegmentState { - kj::Vector> builders; - kj::Vector> forOutput; - }; - kj::Maybe> moreSegments; - - SegmentBuilder* segmentWithSpace = nullptr; - // When allocating, look for space in this segment first before resorting to allocating a new - // segment. This is not necessarily the last segment because addExternalSegment() may add a - // segment that is already-full, in which case we don't update this pointer. - - template // Can be `word` or `const word`. - SegmentBuilder* addSegmentInternal(kj::ArrayPtr content); -}; - -// ======================================================================================= - -inline ReadLimiter::ReadLimiter() - : limit(kj::maxValue) {} - -inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit / WORDS) {} - -inline void ReadLimiter::reset(WordCount64 limit) { this->limit = limit / WORDS; } - -inline bool ReadLimiter::canRead(WordCount amount, Arena* arena) { - // Be careful not to store an underflowed value into `limit`, even if multiple threads are - // decrementing it. - uint64_t current = limit; - if (KJ_UNLIKELY(amount / WORDS > current)) { - arena->reportReadLimitReached(); - return false; - } else { - limit = current - amount / WORDS; - return true; - } -} - -// ------------------------------------------------------------------- - -inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr ptr, - ReadLimiter* readLimiter) - : arena(arena), id(id), ptr(ptr), readLimiter(readLimiter) {} - -inline bool SegmentReader::containsInterval(const void* from, const void* to) { - return from >= this->ptr.begin() && to <= this->ptr.end() && from <= to && - readLimiter->canRead( - intervalLength(reinterpret_cast(from), - reinterpret_cast(to)) / BYTES_PER_WORD, - arena); -} - -inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { - return readLimiter->canRead(virtualAmount, arena); -} - -inline Arena* SegmentReader::getArena() { return arena; } -inline SegmentId SegmentReader::getSegmentId() { return id; } -inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } -inline WordCount SegmentReader::getOffsetTo(const word* ptr) { - return intervalLength(this->ptr.begin(), ptr); -} -inline WordCount SegmentReader::getSize() { return ptr.size() * WORDS; } -inline kj::ArrayPtr SegmentReader::getArray() { return ptr; } -inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); } - -// ------------------------------------------------------------------- - -inline SegmentBuilder::SegmentBuilder( - BuilderArena* arena, SegmentId id, kj::ArrayPtr ptr, ReadLimiter* readLimiter, - size_t wordsUsed) - : SegmentReader(arena, id, ptr, readLimiter), pos(ptr.begin() + wordsUsed), readOnly(false) {} -inline SegmentBuilder::SegmentBuilder( - BuilderArena* arena, SegmentId id, kj::ArrayPtr ptr, ReadLimiter* readLimiter) - : SegmentReader(arena, id, ptr, readLimiter), - // const_cast is safe here because the member won't ever be dereferenced because it appears - // to point to the end of the segment anyway. - pos(const_cast(ptr.end())), - readOnly(true) {} -inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), - ReadLimiter* readLimiter) - : SegmentReader(arena, id, nullptr, readLimiter), pos(nullptr), readOnly(false) {} - -inline word* SegmentBuilder::allocate(WordCount amount) { - if (intervalLength(pos, ptr.end()) < amount) { - // Not enough space in the segment for this allocation. - return nullptr; - } else { - // Success. - word* result = pos; - pos = pos + amount; - return result; - } -} - -inline void SegmentBuilder::checkWritable() { - if (KJ_UNLIKELY(readOnly)) throwNotWritable(); -} - -inline word* SegmentBuilder::getPtrUnchecked(WordCount offset) { - return const_cast(ptr.begin() + offset); -} - -inline BuilderArena* SegmentBuilder::getArena() { - // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base - // class with an Arena pointer that actually points to a BuilderArena. - return static_cast(arena); -} - -inline kj::ArrayPtr SegmentBuilder::currentlyAllocated() { - return kj::arrayPtr(ptr.begin(), pos - ptr.begin()); -} - -inline void SegmentBuilder::reset() { - word* start = getPtrUnchecked(0 * WORDS); - memset(start, 0, (pos - start) * sizeof(word)); - pos = start; -} - -inline void SegmentBuilder::tryTruncate(word* from, word* to) { - if (pos == from) pos = to; -} - -inline bool SegmentBuilder::tryExtend(word* from, word* to) { - // Careful about overflow. - if (pos == from && to <= ptr.end() && to >= from) { - pos = to; - return true; - } else { - return false; - } -} - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_ARENA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/blob.h --- a/osx/include/capnp/blob.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/blob.h Mon May 22 10:01:37 2017 +0100 @@ -1,220 +1,220 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_BLOB_H_ -#define CAPNP_BLOB_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include -#include "common.h" -#include - -namespace capnp { - -struct Data { - Data() = delete; - class Reader; - class Builder; - class Pipeline {}; -}; - -struct Text { - Text() = delete; - class Reader; - class Builder; - class Pipeline {}; -}; - -class Data::Reader: public kj::ArrayPtr { - // Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple - // pointer which does not own its target, can be passed by value, etc. - -public: - typedef Data Reads; - - Reader() = default; - inline Reader(decltype(nullptr)): ArrayPtr(nullptr) {} - inline Reader(const byte* value, size_t size): ArrayPtr(value, size) {} - inline Reader(const kj::Array& value): ArrayPtr(value) {} - inline Reader(const ArrayPtr& value): ArrayPtr(value) {} - inline Reader(const kj::Array& value): ArrayPtr(value) {} - inline Reader(const ArrayPtr& value): ArrayPtr(value) {} -}; - -class Text::Reader: public kj::StringPtr { - // Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted - // in the size but must be present immediately after the last byte. - // - // Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of - // the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD - // also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares. - -public: - typedef Text Reads; - - Reader() = default; - inline Reader(decltype(nullptr)): StringPtr(nullptr) {} - inline Reader(const char* value): StringPtr(value) {} - inline Reader(const char* value, size_t size): StringPtr(value, size) {} - inline Reader(const kj::String& value): StringPtr(value) {} - inline Reader(const StringPtr& value): StringPtr(value) {} - -#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP - template ().c_str())> - inline Reader(const T& t): StringPtr(t) {} - // Allow implicit conversion from any class that has a c_str() method (namely, std::string). - // We use a template trick to detect std::string in order to avoid including the header for - // those who don't want it. -#endif -}; - -class Data::Builder: public kj::ArrayPtr { - // Like Data::Reader except the pointers aren't const. - -public: - typedef Data Builds; - - Builder() = default; - inline Builder(decltype(nullptr)): ArrayPtr(nullptr) {} - inline Builder(byte* value, size_t size): ArrayPtr(value, size) {} - inline Builder(kj::Array& value): ArrayPtr(value) {} - inline Builder(ArrayPtr value): ArrayPtr(value) {} - - inline Data::Reader asReader() const { return Data::Reader(*this); } - inline operator Reader() const { return asReader(); } -}; - -class Text::Builder: public kj::DisallowConstCopy { - // Basically identical to kj::StringPtr, except that the contents are non-const. - -public: - inline Builder(): content(nulstr, 1) {} - inline Builder(decltype(nullptr)): content(nulstr, 1) {} - inline Builder(char* value): content(value, strlen(value) + 1) {} - inline Builder(char* value, size_t size): content(value, size + 1) { - KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); - } - - inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); } - inline operator Reader() const { return asReader(); } - - inline operator kj::ArrayPtr(); - inline kj::ArrayPtr asArray(); - inline operator kj::ArrayPtr() const; - inline kj::ArrayPtr asArray() const; - inline kj::ArrayPtr asBytes() { return asArray().asBytes(); } - inline kj::ArrayPtr asBytes() const { return asArray().asBytes(); } - // Result does not include NUL terminator. - - inline operator kj::StringPtr() const; - inline kj::StringPtr asString() const; - - inline const char* cStr() const { return content.begin(); } - // Returns NUL-terminated string. - - inline size_t size() const { return content.size() - 1; } - // Result does not include NUL terminator. - - inline char operator[](size_t index) const { return content[index]; } - inline char& operator[](size_t index) { return content[index]; } - - inline char* begin() { return content.begin(); } - inline char* end() { return content.end() - 1; } - inline const char* begin() const { return content.begin(); } - inline const char* end() const { return content.end() - 1; } - - inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } - inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } - - inline bool operator==(Builder other) const { return asString() == other.asString(); } - inline bool operator!=(Builder other) const { return asString() != other.asString(); } - inline bool operator< (Builder other) const { return asString() < other.asString(); } - inline bool operator> (Builder other) const { return asString() > other.asString(); } - inline bool operator<=(Builder other) const { return asString() <= other.asString(); } - inline bool operator>=(Builder other) const { return asString() >= other.asString(); } - - inline kj::StringPtr slice(size_t start) const; - inline kj::ArrayPtr slice(size_t start, size_t end) const; - inline Builder slice(size_t start); - inline kj::ArrayPtr slice(size_t start, size_t end); - // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter - // version that assumes end = size(). - -private: - inline explicit Builder(kj::ArrayPtr content): content(content) {} - - kj::ArrayPtr content; - - static char nulstr[1]; -}; - -inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) { - return builder.asString(); -} - -inline bool operator==(const char* a, const Text::Builder& b) { return a == b.asString(); } -inline bool operator!=(const char* a, const Text::Builder& b) { return a != b.asString(); } - -inline Text::Builder::operator kj::StringPtr() const { - return kj::StringPtr(content.begin(), content.size() - 1); -} - -inline kj::StringPtr Text::Builder::asString() const { - return kj::StringPtr(content.begin(), content.size() - 1); -} - -inline Text::Builder::operator kj::ArrayPtr() { - return content.slice(0, content.size() - 1); -} - -inline kj::ArrayPtr Text::Builder::asArray() { - return content.slice(0, content.size() - 1); -} - -inline Text::Builder::operator kj::ArrayPtr() const { - return content.slice(0, content.size() - 1); -} - -inline kj::ArrayPtr Text::Builder::asArray() const { - return content.slice(0, content.size() - 1); -} - -inline kj::StringPtr Text::Builder::slice(size_t start) const { - return asReader().slice(start); -} -inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) const { - return content.slice(start, end); -} - -inline Text::Builder Text::Builder::slice(size_t start) { - return Text::Builder(content.slice(start, content.size())); -} -inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) { - return content.slice(start, end); -} - -} // namespace capnp - -#endif // CAPNP_BLOB_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_BLOB_H_ +#define CAPNP_BLOB_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include "common.h" +#include + +namespace capnp { + +struct Data { + Data() = delete; + class Reader; + class Builder; + class Pipeline {}; +}; + +struct Text { + Text() = delete; + class Reader; + class Builder; + class Pipeline {}; +}; + +class Data::Reader: public kj::ArrayPtr { + // Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple + // pointer which does not own its target, can be passed by value, etc. + +public: + typedef Data Reads; + + Reader() = default; + inline Reader(decltype(nullptr)): ArrayPtr(nullptr) {} + inline Reader(const byte* value, size_t size): ArrayPtr(value, size) {} + inline Reader(const kj::Array& value): ArrayPtr(value) {} + inline Reader(const ArrayPtr& value): ArrayPtr(value) {} + inline Reader(const kj::Array& value): ArrayPtr(value) {} + inline Reader(const ArrayPtr& value): ArrayPtr(value) {} +}; + +class Text::Reader: public kj::StringPtr { + // Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted + // in the size but must be present immediately after the last byte. + // + // Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of + // the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD + // also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares. + +public: + typedef Text Reads; + + Reader() = default; + inline Reader(decltype(nullptr)): StringPtr(nullptr) {} + inline Reader(const char* value): StringPtr(value) {} + inline Reader(const char* value, size_t size): StringPtr(value, size) {} + inline Reader(const kj::String& value): StringPtr(value) {} + inline Reader(const StringPtr& value): StringPtr(value) {} + +#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP + template ().c_str())> + inline Reader(const T& t): StringPtr(t) {} + // Allow implicit conversion from any class that has a c_str() method (namely, std::string). + // We use a template trick to detect std::string in order to avoid including the header for + // those who don't want it. +#endif +}; + +class Data::Builder: public kj::ArrayPtr { + // Like Data::Reader except the pointers aren't const. + +public: + typedef Data Builds; + + Builder() = default; + inline Builder(decltype(nullptr)): ArrayPtr(nullptr) {} + inline Builder(byte* value, size_t size): ArrayPtr(value, size) {} + inline Builder(kj::Array& value): ArrayPtr(value) {} + inline Builder(ArrayPtr value): ArrayPtr(value) {} + + inline Data::Reader asReader() const { return Data::Reader(*this); } + inline operator Reader() const { return asReader(); } +}; + +class Text::Builder: public kj::DisallowConstCopy { + // Basically identical to kj::StringPtr, except that the contents are non-const. + +public: + inline Builder(): content(nulstr, 1) {} + inline Builder(decltype(nullptr)): content(nulstr, 1) {} + inline Builder(char* value): content(value, strlen(value) + 1) {} + inline Builder(char* value, size_t size): content(value, size + 1) { + KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); + } + + inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); } + inline operator Reader() const { return asReader(); } + + inline operator kj::ArrayPtr(); + inline kj::ArrayPtr asArray(); + inline operator kj::ArrayPtr() const; + inline kj::ArrayPtr asArray() const; + inline kj::ArrayPtr asBytes() { return asArray().asBytes(); } + inline kj::ArrayPtr asBytes() const { return asArray().asBytes(); } + // Result does not include NUL terminator. + + inline operator kj::StringPtr() const; + inline kj::StringPtr asString() const; + + inline const char* cStr() const { return content.begin(); } + // Returns NUL-terminated string. + + inline size_t size() const { return content.size() - 1; } + // Result does not include NUL terminator. + + inline char operator[](size_t index) const { return content[index]; } + inline char& operator[](size_t index) { return content[index]; } + + inline char* begin() { return content.begin(); } + inline char* end() { return content.end() - 1; } + inline const char* begin() const { return content.begin(); } + inline const char* end() const { return content.end() - 1; } + + inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } + inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } + + inline bool operator==(Builder other) const { return asString() == other.asString(); } + inline bool operator!=(Builder other) const { return asString() != other.asString(); } + inline bool operator< (Builder other) const { return asString() < other.asString(); } + inline bool operator> (Builder other) const { return asString() > other.asString(); } + inline bool operator<=(Builder other) const { return asString() <= other.asString(); } + inline bool operator>=(Builder other) const { return asString() >= other.asString(); } + + inline kj::StringPtr slice(size_t start) const; + inline kj::ArrayPtr slice(size_t start, size_t end) const; + inline Builder slice(size_t start); + inline kj::ArrayPtr slice(size_t start, size_t end); + // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter + // version that assumes end = size(). + +private: + inline explicit Builder(kj::ArrayPtr content): content(content) {} + + kj::ArrayPtr content; + + static char nulstr[1]; +}; + +inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) { + return builder.asString(); +} + +inline bool operator==(const char* a, const Text::Builder& b) { return a == b.asString(); } +inline bool operator!=(const char* a, const Text::Builder& b) { return a != b.asString(); } + +inline Text::Builder::operator kj::StringPtr() const { + return kj::StringPtr(content.begin(), content.size() - 1); +} + +inline kj::StringPtr Text::Builder::asString() const { + return kj::StringPtr(content.begin(), content.size() - 1); +} + +inline Text::Builder::operator kj::ArrayPtr() { + return content.slice(0, content.size() - 1); +} + +inline kj::ArrayPtr Text::Builder::asArray() { + return content.slice(0, content.size() - 1); +} + +inline Text::Builder::operator kj::ArrayPtr() const { + return content.slice(0, content.size() - 1); +} + +inline kj::ArrayPtr Text::Builder::asArray() const { + return content.slice(0, content.size() - 1); +} + +inline kj::StringPtr Text::Builder::slice(size_t start) const { + return asReader().slice(start); +} +inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) const { + return content.slice(start, end); +} + +inline Text::Builder Text::Builder::slice(size_t start) { + return Text::Builder(content.slice(start, content.size())); +} +inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) { + return content.slice(start, end); +} + +} // namespace capnp + +#endif // CAPNP_BLOB_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/c++.capnp --- a/osx/include/capnp/c++.capnp Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/c++.capnp Mon May 22 10:01:37 2017 +0100 @@ -1,26 +1,26 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xbdf87d7bb8304e81; -$namespace("capnp::annotations"); - -annotation namespace(file): Text; -annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xbdf87d7bb8304e81; +$namespace("capnp::annotations"); + +annotation namespace(file): Text; +annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/c++.capnp.h --- a/osx/include/capnp/c++.capnp.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/c++.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -1,33 +1,33 @@ -// Generated by Cap'n Proto compiler, DO NOT EDIT -// source: c++.capnp - -#ifndef CAPNP_INCLUDED_bdf87d7bb8304e81_ -#define CAPNP_INCLUDED_bdf87d7bb8304e81_ - -#include - -#if CAPNP_VERSION != 6000 -#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." -#endif - - -namespace capnp { -namespace schemas { - -CAPNP_DECLARE_SCHEMA(b9c6f99ebf805f2c); -CAPNP_DECLARE_SCHEMA(f264a779fef191ce); - -} // namespace schemas -} // namespace capnp - -namespace capnp { -namespace annotations { - -// ======================================================================================= - -// ======================================================================================= - -} // namespace -} // namespace - -#endif // CAPNP_INCLUDED_bdf87d7bb8304e81_ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: c++.capnp + +#ifndef CAPNP_INCLUDED_bdf87d7bb8304e81_ +#define CAPNP_INCLUDED_bdf87d7bb8304e81_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(b9c6f99ebf805f2c); +CAPNP_DECLARE_SCHEMA(f264a779fef191ce); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace annotations { + +// ======================================================================================= + +// ======================================================================================= + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_bdf87d7bb8304e81_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/capability.h --- a/osx/include/capnp/capability.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/capability.h Mon May 22 10:01:37 2017 +0100 @@ -1,885 +1,884 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_CAPABILITY_H_ -#define CAPNP_CAPABILITY_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#if CAPNP_LITE -#error "RPC APIs, including this header, are not available in lite mode." -#endif - -#include -#include -#include "any.h" -#include "pointer-helpers.h" - -namespace capnp { - -template -class Response; - -template -class RemotePromise: public kj::Promise>, public T::Pipeline { - // A Promise which supports pipelined calls. T is typically a struct type. T must declare - // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply - // multiply-inherits that type along with Promise>. T::Pipeline must be movable, - // but does not need to be copyable (i.e. just like Promise). - // - // The promise is for an owned pointer so that the RPC system can allocate the MessageReader - // itself. - -public: - inline RemotePromise(kj::Promise>&& promise, typename T::Pipeline&& pipeline) - : kj::Promise>(kj::mv(promise)), - T::Pipeline(kj::mv(pipeline)) {} - inline RemotePromise(decltype(nullptr)) - : kj::Promise>(nullptr), - T::Pipeline(nullptr) {} - KJ_DISALLOW_COPY(RemotePromise); - RemotePromise(RemotePromise&& other) = default; - RemotePromise& operator=(RemotePromise&& other) = default; -}; - -class LocalClient; -namespace _ { // private -struct RawSchema; -struct RawBrandedSchema; -extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++ -class CapabilityServerSetBase; -} // namespace _ (private) - -struct Capability { - // A capability without type-safe methods. Typed capability clients wrap `Client` and typed - // capability servers subclass `Server` to dispatch to the regular, typed methods. - - class Client; - class Server; - - struct _capnpPrivate { - struct IsInterface; - static constexpr uint64_t typeId = 0x3; - static constexpr Kind kind = Kind::INTERFACE; - static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA; - - static const _::RawBrandedSchema* const brand; - // Can't quite declare this one inline without including generated-header-support.h. Avoiding - // for now by declaring out-of-line. - // TODO(cleanup): Split RawSchema stuff into its own header that can be included here, or - // something. - }; -}; - -// ======================================================================================= -// Capability clients - -class RequestHook; -class ResponseHook; -class PipelineHook; -class ClientHook; - -template -class Request: public Params::Builder { - // A call that hasn't been sent yet. This class extends a Builder for the call's "Params" - // structure with a method send() that actually sends it. - // - // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have - // a method `Request fooRequest()` (as well as a convenience method - // `RemotePromise foo(A::Reader a, B::Reader b)`). - -public: - inline Request(typename Params::Builder builder, kj::Own&& hook) - : Params::Builder(builder), hook(kj::mv(hook)) {} - inline Request(decltype(nullptr)): Params::Builder(nullptr) {} - - RemotePromise send() KJ_WARN_UNUSED_RESULT; - // Send the call and return a promise for the results. - -private: - kj::Own hook; - - friend class Capability::Client; - friend struct DynamicCapability; - template - friend class CallContext; - friend class RequestHook; -}; - -template -class Response: public Results::Reader { - // A completed call. This class extends a Reader for the call's answer structure. The Response - // is move-only -- once it goes out-of-scope, the underlying message will be freed. - -public: - inline Response(typename Results::Reader reader, kj::Own&& hook) - : Results::Reader(reader), hook(kj::mv(hook)) {} - -private: - kj::Own hook; - - template - friend class Request; - friend class ResponseHook; -}; - -class Capability::Client { - // Base type for capability clients. - -public: - typedef Capability Reads; - typedef Capability Calls; - - Client(decltype(nullptr)); - // If you need to declare a Client before you have anything to assign to it (perhaps because - // the assignment is going to occur in an if/else scope), you can start by initializing it to - // `nullptr`. The resulting client is not meant to be called and throws exceptions from all - // methods. - - template ()>> - Client(kj::Own&& server); - // Make a client capability that wraps the given server capability. The server's methods will - // only be executed in the given EventLoop, regardless of what thread calls the client's methods. - - template ()>> - Client(kj::Promise&& promise); - // Make a client from a promise for a future client. The resulting client queues calls until the - // promise resolves. - - Client(kj::Exception&& exception); - // Make a broken client that throws the given exception from all calls. - - Client(Client& other); - Client& operator=(Client& other); - // Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of - // the client must remain in one thread. - - Client(Client&&) = default; - Client& operator=(Client&&) = default; - // Move constructor avoids reference counting. - - explicit Client(kj::Own&& hook); - // For use by the RPC implementation: Wrap a ClientHook. - - template - typename T::Client castAs(); - // Reinterpret the capability as implementing the given interface. Note that no error will occur - // here if the capability does not actually implement this interface, but later method calls will - // fail. It's up to the application to decide how indicate that additional interfaces are - // supported. - // - // TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance. - - template - typename T::Client castAs(InterfaceSchema schema); - // Dynamic version. `T` must be `DynamicCapability`, and you must `#include `. - - kj::Promise whenResolved(); - // If the capability is actually only a promise, the returned promise resolves once the - // capability itself has resolved to its final destination (or propagates the exception if - // the capability promise is rejected). This is mainly useful for error-checking in the case - // where no calls are being made. There is no reason to wait for this before making calls; if - // the capability does not resolve, the call results will propagate the error. - - Request typelessRequest( - uint64_t interfaceId, uint16_t methodId, - kj::Maybe sizeHint); - // Make a request without knowing the types of the params or results. You specify the type ID - // and method number manually. - - // TODO(someday): method(s) for Join - -protected: - Client() = default; - - template - Request newCall(uint64_t interfaceId, uint16_t methodId, - kj::Maybe sizeHint); - -private: - kj::Own hook; - - static kj::Own makeLocalClient(kj::Own&& server); - - template - friend struct _::PointerHelpers; - friend struct DynamicCapability; - friend class Orphanage; - friend struct DynamicStruct; - friend struct DynamicList; - template - friend struct List; - friend class _::CapabilityServerSetBase; - friend class ClientHook; -}; - -// ======================================================================================= -// Capability servers - -class CallContextHook; - -template -class CallContext: public kj::DisallowConstCopy { - // Wrapper around CallContextHook with a specific return type. - // - // Methods of this class may only be called from within the server's event loop, not from other - // threads. - // - // The CallContext becomes invalid as soon as the call reports completion. - -public: - explicit CallContext(CallContextHook& hook); - - typename Params::Reader getParams(); - // Get the params payload. - - void releaseParams(); - // Release the params payload. getParams() will throw an exception after this is called. - // Releasing the params may allow the RPC system to free up buffer space to handle other - // requests. Long-running asynchronous methods should try to call this as early as is - // convenient. - - typename Results::Builder getResults(kj::Maybe sizeHint = nullptr); - typename Results::Builder initResults(kj::Maybe sizeHint = nullptr); - void setResults(typename Results::Reader value); - void adoptResults(Orphan&& value); - Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); - // Manipulate the results payload. The "Return" message (part of the RPC protocol) will - // typically be allocated the first time one of these is called. Some RPC systems may - // allocate these messages in a limited space (such as a shared memory segment), therefore the - // application should delay calling these as long as is convenient to do so (but don't delay - // if doing so would require extra copies later). - // - // `sizeHint` indicates a guess at the message size. This will usually be used to decide how - // much space to allocate for the first message segment (don't worry: only space that is actually - // used will be sent on the wire). If omitted, the system decides. The message root pointer - // should not be included in the size. So, if you are simply going to copy some existing message - // directly into the results, just call `.totalSize()` and pass that in. - - template - kj::Promise tailCall(Request&& tailRequest); - // Resolve the call by making a tail call. `tailRequest` is a request that has been filled in - // but not yet sent. The context will send the call, then fill in the results with the result - // of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called. - // - // The RPC implementation may be able to optimize a tail call to another machine such that the - // results never actually pass through this machine. Even if no such optimization is possible, - // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site. - // - // In general, this should be the last thing a method implementation calls, and the promise - // returned from `tailCall()` should then be returned by the method implementation. - - void allowCancellation(); - // Indicate that it is OK for the RPC system to discard its Promise for this call's result if - // the caller cancels the call, thereby transitively canceling any asynchronous operations the - // call implementation was performing. This is not done by default because it could represent a - // security risk: applications must be carefully written to ensure that they do not end up in - // a bad state if an operation is canceled at an arbitrary point. However, for long-running - // method calls that hold significant resources, prompt cancellation is often useful. - // - // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously - // executing on a local thread. The method must perform an asynchronous operation or call - // `EventLoop::current().evalLater()` to yield control. - // - // Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that - // provide notification when the caller cancels the request without forcefully killing off the - // promise chain. Unfortunately, this composes poorly with promise forking: the canceled - // path may be just one branch of a fork of the result promise. The other branches still want - // the call to continue. Promise forking is used within the Cap'n Proto implementation -- in - // particular each pipelined call forks the result promise. So, if a caller made a pipelined - // call and then dropped the original object, the call should not be canceled, but it would be - // excessively complicated for the framework to avoid notififying of cancellation as long as - // pipelined calls still exist. - -private: - CallContextHook* hook; - - friend class Capability::Server; - friend struct DynamicCapability; -}; - -class Capability::Server { - // Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects - // will instead subclass a typed Server interface which will take care of implementing - // dispatchCall(). - -public: - typedef Capability Serves; - - virtual kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, - CallContext context) = 0; - // Call the given method. `params` is the input struct, and should be released as soon as it - // is no longer needed. `context` may be used to allocate the output struct and deal with - // cancellation. - - // TODO(someday): Method which can optionally be overridden to implement Join when the object is - // a proxy. - -protected: - inline Capability::Client thisCap(); - // Get a capability pointing to this object, much like the `this` keyword. - // - // The effect of this method is undefined if: - // - No capability client has been created pointing to this object. (This is always the case in - // the server's constructor.) - // - The capability client pointing at this object has been destroyed. (This is always the case - // in the server's destructor.) - // - Multiple capability clients have been created around the same server (possible if the server - // is refcounted, which is not recommended since the client itself provides refcounting). - - template - CallContext internalGetTypedContext( - CallContext typeless); - kj::Promise internalUnimplemented(const char* actualInterfaceName, - uint64_t requestedTypeId); - kj::Promise internalUnimplemented(const char* interfaceName, - uint64_t typeId, uint16_t methodId); - kj::Promise internalUnimplemented(const char* interfaceName, const char* methodName, - uint64_t typeId, uint16_t methodId); - -private: - ClientHook* thisHook = nullptr; - friend class LocalClient; -}; - -// ======================================================================================= - -class ReaderCapabilityTable: private _::CapTableReader { - // Class which imbues Readers with the ability to read capabilities. - // - // In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into - // an external table. Since these pointers fundamentally point outside the message, a - // MessageReader by default has no idea what they point at, and therefore reading capabilities - // from such a reader will throw exceptions. - // - // In order to be able to read capabilities, you must first attach a capability table, using - // this class. By "imbuing" a Reader, you get a new Reader which will interpret capability - // pointers by treating them as indexes into the ReaderCapabilityTable. - // - // Note that when using Cap'n Proto's RPC system, this is handled automatically. - -public: - explicit ReaderCapabilityTable(kj::Array>> table); - KJ_DISALLOW_COPY(ReaderCapabilityTable); - - template - T imbue(T reader); - // Return a reader equivalent to `reader` except that when reading capability-valued fields, - // the capabilities are looked up in this table. - -private: - kj::Array>> table; - - kj::Maybe> extractCap(uint index) override; -}; - -class BuilderCapabilityTable: private _::CapTableBuilder { - // Class which imbues Builders with the ability to read and write capabilities. - // - // This is much like ReaderCapabilityTable, except for builders. The table starts out empty, - // but capabilities can be added to it over time. - -public: - BuilderCapabilityTable(); - KJ_DISALLOW_COPY(BuilderCapabilityTable); - - inline kj::ArrayPtr>> getTable() { return table; } - - template - T imbue(T builder); - // Return a builder equivalent to `builder` except that when reading capability-valued fields, - // the capabilities are looked up in this table. - -private: - kj::Vector>> table; - - kj::Maybe> extractCap(uint index) override; - uint injectCap(kj::Own&& cap) override; - void dropCap(uint index) override; -}; - -// ======================================================================================= - -namespace _ { // private - -class CapabilityServerSetBase { -public: - Capability::Client addInternal(kj::Own&& server, void* ptr); - kj::Promise getLocalServerInternal(Capability::Client& client); -}; - -} // namespace _ (private) - -template -class CapabilityServerSet: private _::CapabilityServerSetBase { - // Allows a server to recognize its own capabilities when passed back to it, and obtain the - // underlying Server objects associated with them. - // - // All objects in the set must have the same interface type T. The objects may implement various - // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects), - // but note that if you compile with RTTI disabled then you will not be able to down-cast through - // virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI - // disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type, - // and you server class will need to be directly derived from that, so that you can use - // static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile - // with RTTI, then you can freely dynamic_cast and ignore this issue!) - -public: - CapabilityServerSet() = default; - KJ_DISALLOW_COPY(CapabilityServerSet); - - typename T::Client add(kj::Own&& server); - // Create a new capability Client for the given Server and also add this server to the set. - - kj::Promise> getLocalServer(typename T::Client& client); - // Given a Client pointing to a server previously passed to add(), return the corresponding - // Server. This returns a promise because if the input client is itself a promise, this must - // wait for it to resolve. Keep in mind that the server will be deleted when all clients are - // gone, so the caller should make sure to keep the client alive (hence why this method only - // accepts an lvalue input). -}; - -// ======================================================================================= -// Hook interfaces which must be implemented by the RPC system. Applications never call these -// directly; the RPC system implements them and the types defined earlier in this file wrap them. - -class RequestHook { - // Hook interface implemented by RPC system representing a request being built. - -public: - virtual RemotePromise send() = 0; - // Send the call and return a promise for the result. - - virtual const void* getBrand() = 0; - // Returns a void* that identifies who made this request. This can be used by an RPC adapter to - // discover when tail call is going to be sent over its own connection and therefore can be - // optimized into a remote tail call. - - template - inline static kj::Own from(Request&& request) { - return kj::mv(request.hook); - } -}; - -class ResponseHook { - // Hook interface implemented by RPC system representing a response. - // - // At present this class has no methods. It exists only for garbage collection -- when the - // ResponseHook is destroyed, the results can be freed. - -public: - virtual ~ResponseHook() noexcept(false); - // Just here to make sure the type is dynamic. - - template - inline static kj::Own from(Response&& response) { - return kj::mv(response.hook); - } -}; - -// class PipelineHook is declared in any.h because it is needed there. - -class ClientHook { -public: - ClientHook(); - - virtual Request newCall( - uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) = 0; - // Start a new call, allowing the client to allocate request/response objects as it sees fit. - // This version is used when calls are made from application code in the local process. - - struct VoidPromiseAndPipeline { - kj::Promise promise; - kj::Own pipeline; - }; - - virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, - kj::Own&& context) = 0; - // Call the object, but the caller controls allocation of the request/response objects. If the - // callee insists on allocating these objects itself, it must make a copy. This version is used - // when calls come in over the network via an RPC system. Note that even if the returned - // `Promise` is discarded, the call may continue executing if any pipelined calls are - // waiting for it. - // - // Since the caller of this method chooses the CallContext implementation, it is the caller's - // responsibility to ensure that the returned promise is not canceled unless allowed via - // the context's `allowCancellation()`. - // - // The call must not begin synchronously; the callee must arrange for the call to begin in a - // later turn of the event loop. Otherwise, application code may call back and affect the - // callee's state in an unexpected way. - - virtual kj::Maybe getResolved() = 0; - // If this ClientHook is a promise that has already resolved, returns the inner, resolved version - // of the capability. The caller may permanently replace this client with the resolved one if - // desired. Returns null if the client isn't a promise or hasn't resolved yet -- use - // `whenMoreResolved()` to distinguish between them. - - virtual kj::Maybe>> whenMoreResolved() = 0; - // If this client is a settled reference (not a promise), return nullptr. Otherwise, return a - // promise that eventually resolves to a new client that is closer to being the final, settled - // client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly - // should eventually produce a settled client. - - kj::Promise whenResolved(); - // Repeatedly calls whenMoreResolved() until it returns nullptr. - - virtual kj::Own addRef() = 0; - // Return a new reference to the same capability. - - virtual const void* getBrand() = 0; - // Returns a void* that identifies who made this client. This can be used by an RPC adapter to - // discover when a capability it needs to marshal is one that it created in the first place, and - // therefore it can transfer the capability without proxying. - - static const uint NULL_CAPABILITY_BRAND; - // Value is irrelevant; used for pointer. - - inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; } - // Returns true if the capability was created as a result of assigning a Client to null or by - // reading a null pointer out of a Cap'n Proto message. - - virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet); - // If this is a local capability created through `capServerSet`, return the underlying Server. - // Otherwise, return nullptr. Default implementation (which everyone except LocalClient should - // use) always returns nullptr. - - static kj::Own from(Capability::Client client) { return kj::mv(client.hook); } -}; - -class CallContextHook { - // Hook interface implemented by RPC system to manage a call on the server side. See - // CallContext. - -public: - virtual AnyPointer::Reader getParams() = 0; - virtual void releaseParams() = 0; - virtual AnyPointer::Builder getResults(kj::Maybe sizeHint) = 0; - virtual kj::Promise tailCall(kj::Own&& request) = 0; - virtual void allowCancellation() = 0; - - virtual kj::Promise onTailCall() = 0; - // If `tailCall()` is called, resolves to the PipelineHook from the tail call. An - // implementation of `ClientHook::call()` is allowed to call this at most once. - - virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) = 0; - // Call this when you would otherwise call onTailCall() immediately followed by tailCall(). - // Implementations of tailCall() should typically call directTailCall() and then fulfill the - // promise fulfiller for onTailCall() with the returned pipeline. - - virtual kj::Own addRef() = 0; -}; - -kj::Own newLocalPromiseClient(kj::Promise>&& promise); -// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to -// the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the -// redirection to the eventual replacement client. - -kj::Own newLocalPromisePipeline(kj::Promise>&& promise); -// Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to -// the new pipeline. - -kj::Own newBrokenCap(kj::StringPtr reason); -kj::Own newBrokenCap(kj::Exception&& reason); -// Helper function that creates a capability which simply throws exceptions when called. - -kj::Own newBrokenPipeline(kj::Exception&& reason); -// Helper function that creates a pipeline which simply throws exceptions when called. - -Request newBrokenRequest( - kj::Exception&& reason, kj::Maybe sizeHint); -// Helper function that creates a Request object that simply throws exceptions when sent. - -// ======================================================================================= -// Extend PointerHelpers for interfaces - -namespace _ { // private - -template -struct PointerHelpers { - static inline typename T::Client get(PointerReader reader) { - return typename T::Client(reader.getCapability()); - } - static inline typename T::Client get(PointerBuilder builder) { - return typename T::Client(builder.getCapability()); - } - static inline void set(PointerBuilder builder, typename T::Client&& value) { - builder.setCapability(kj::mv(value.Capability::Client::hook)); - } - static inline void set(PointerBuilder builder, typename T::Client& value) { - builder.setCapability(value.Capability::Client::hook->addRef()); - } - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder) { - return Orphan(builder.disown()); - } -}; - -} // namespace _ (private) - -// ======================================================================================= -// Extend List for interfaces - -template -struct List { - List() = delete; - - class Reader { - public: - typedef List Reads; - - Reader() = default; - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline typename T::Client operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return typename T::Client(reader.getPointerElement(index * ELEMENTS).getCapability()); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List Builds; - - Builder() = delete; - inline Builder(decltype(nullptr)) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline typename T::Client operator[](uint index) { - KJ_IREQUIRE(index < size()); - return typename T::Client(builder.getPointerElement(index * ELEMENTS).getCapability()); - } - inline void set(uint index, typename T::Client value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).setCapability(kj::mv(value.hook)); - } - inline void adopt(uint index, Orphan&& value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value)); - } - inline Orphan disown(uint index) { - KJ_IREQUIRE(index < size()); - return Orphan(builder.getPointerElement(index * ELEMENTS).disown()); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - -private: - inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { - return builder.initList(ElementSize::POINTER, size * ELEMENTS); - } - inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { - return builder.getList(ElementSize::POINTER, defaultValue); - } - inline static _::ListReader getFromPointer( - const _::PointerReader& reader, const word* defaultValue) { - return reader.getList(ElementSize::POINTER, defaultValue); - } - - template - friend struct List; - template - friend struct _::PointerHelpers; -}; - -// ======================================================================================= -// Inline implementation details - -template -RemotePromise Request::send() { - auto typelessPromise = hook->send(); - hook = nullptr; // prevent reuse - - // Convert the Promise to return the correct response type. - // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the - // Pipeline part of the RemotePromise. - auto typedPromise = kj::implicitCast>&>(typelessPromise) - .then([](Response&& response) -> Response { - return Response(response.getAs(), kj::mv(response.hook)); - }); - - // Wrap the typeless pipeline in a typed wrapper. - typename Results::Pipeline typedPipeline( - kj::mv(kj::implicitCast(typelessPromise))); - - return RemotePromise(kj::mv(typedPromise), kj::mv(typedPipeline)); -} - -inline Capability::Client::Client(kj::Own&& hook): hook(kj::mv(hook)) {} -template -inline Capability::Client::Client(kj::Own&& server) - : hook(makeLocalClient(kj::mv(server))) {} -template -inline Capability::Client::Client(kj::Promise&& promise) - : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {} -inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {} -inline Capability::Client& Capability::Client::operator=(Client& other) { - hook = other.hook->addRef(); - return *this; -} -template -inline typename T::Client Capability::Client::castAs() { - return typename T::Client(hook->addRef()); -} -inline kj::Promise Capability::Client::whenResolved() { - return hook->whenResolved(); -} -inline Request Capability::Client::typelessRequest( - uint64_t interfaceId, uint16_t methodId, - kj::Maybe sizeHint) { - return newCall(interfaceId, methodId, sizeHint); -} -template -inline Request Capability::Client::newCall( - uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) { - auto typeless = hook->newCall(interfaceId, methodId, sizeHint); - return Request(typeless.template getAs(), kj::mv(typeless.hook)); -} - -template -inline CallContext::CallContext(CallContextHook& hook): hook(&hook) {} -template -inline typename Params::Reader CallContext::getParams() { - return hook->getParams().template getAs(); -} -template -inline void CallContext::releaseParams() { - hook->releaseParams(); -} -template -inline typename Results::Builder CallContext::getResults( - kj::Maybe sizeHint) { - // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 - return hook->getResults(sizeHint).template getAs(); -} -template -inline typename Results::Builder CallContext::initResults( - kj::Maybe sizeHint) { - // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 - return hook->getResults(sizeHint).template initAs(); -} -template -inline void CallContext::setResults(typename Results::Reader value) { - hook->getResults(value.totalSize()).template setAs(value); -} -template -inline void CallContext::adoptResults(Orphan&& value) { - hook->getResults(nullptr).adopt(kj::mv(value)); -} -template -inline Orphanage CallContext::getResultsOrphanage( - kj::Maybe sizeHint) { - return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); -} -template -template -inline kj::Promise CallContext::tailCall( - Request&& tailRequest) { - return hook->tailCall(kj::mv(tailRequest.hook)); -} -template -inline void CallContext::allowCancellation() { - hook->allowCancellation(); -} - -template -CallContext Capability::Server::internalGetTypedContext( - CallContext typeless) { - return CallContext(*typeless.hook); -} - -Capability::Client Capability::Server::thisCap() { - return Client(thisHook->addRef()); -} - -template -T ReaderCapabilityTable::imbue(T reader) { - return T(_::PointerHelpers>::getInternalReader(reader).imbue(this)); -} - -template -T BuilderCapabilityTable::imbue(T builder) { - return T(_::PointerHelpers>::getInternalBuilder(kj::mv(builder)).imbue(this)); -} - -template -typename T::Client CapabilityServerSet::add(kj::Own&& server) { - void* ptr = reinterpret_cast(server.get()); - // Clang insists that `castAs` is a template-dependent member and therefore we need the - // `template` keyword here, but AFAICT this is wrong: addImpl() is not a template. - return addInternal(kj::mv(server), ptr).template castAs(); -} - -template -kj::Promise> CapabilityServerSet::getLocalServer( - typename T::Client& client) { - return getLocalServerInternal(client) - .then([](void* server) -> kj::Maybe { - if (server == nullptr) { - return nullptr; - } else { - return *reinterpret_cast(server); - } - }); -} - -template -struct Orphanage::GetInnerReader { - static inline kj::Own apply(typename T::Client t) { - return ClientHook::from(kj::mv(t)); - } -}; - -} // namespace capnp - -#endif // CAPNP_CAPABILITY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_CAPABILITY_H_ +#define CAPNP_CAPABILITY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#if CAPNP_LITE +#error "RPC APIs, including this header, are not available in lite mode." +#endif + +#include +#include +#include "raw-schema.h" +#include "any.h" +#include "pointer-helpers.h" + +namespace capnp { + +template +class Response; + +template +class RemotePromise: public kj::Promise>, public T::Pipeline { + // A Promise which supports pipelined calls. T is typically a struct type. T must declare + // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply + // multiply-inherits that type along with Promise>. T::Pipeline must be movable, + // but does not need to be copyable (i.e. just like Promise). + // + // The promise is for an owned pointer so that the RPC system can allocate the MessageReader + // itself. + +public: + inline RemotePromise(kj::Promise>&& promise, typename T::Pipeline&& pipeline) + : kj::Promise>(kj::mv(promise)), + T::Pipeline(kj::mv(pipeline)) {} + inline RemotePromise(decltype(nullptr)) + : kj::Promise>(nullptr), + T::Pipeline(nullptr) {} + KJ_DISALLOW_COPY(RemotePromise); + RemotePromise(RemotePromise&& other) = default; + RemotePromise& operator=(RemotePromise&& other) = default; +}; + +class LocalClient; +namespace _ { // private +extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++ +class CapabilityServerSetBase; +} // namespace _ (private) + +struct Capability { + // A capability without type-safe methods. Typed capability clients wrap `Client` and typed + // capability servers subclass `Server` to dispatch to the regular, typed methods. + + class Client; + class Server; + + struct _capnpPrivate { + struct IsInterface; + static constexpr uint64_t typeId = 0x3; + static constexpr Kind kind = Kind::INTERFACE; + static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA; + + static const _::RawBrandedSchema* brand() { + return &_::NULL_INTERFACE_SCHEMA.defaultBrand; + } + }; +}; + +// ======================================================================================= +// Capability clients + +class RequestHook; +class ResponseHook; +class PipelineHook; +class ClientHook; + +template +class Request: public Params::Builder { + // A call that hasn't been sent yet. This class extends a Builder for the call's "Params" + // structure with a method send() that actually sends it. + // + // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have + // a method `Request fooRequest()` (as well as a convenience method + // `RemotePromise foo(A::Reader a, B::Reader b)`). + +public: + inline Request(typename Params::Builder builder, kj::Own&& hook) + : Params::Builder(builder), hook(kj::mv(hook)) {} + inline Request(decltype(nullptr)): Params::Builder(nullptr) {} + + RemotePromise send() KJ_WARN_UNUSED_RESULT; + // Send the call and return a promise for the results. + +private: + kj::Own hook; + + friend class Capability::Client; + friend struct DynamicCapability; + template + friend class CallContext; + friend class RequestHook; +}; + +template +class Response: public Results::Reader { + // A completed call. This class extends a Reader for the call's answer structure. The Response + // is move-only -- once it goes out-of-scope, the underlying message will be freed. + +public: + inline Response(typename Results::Reader reader, kj::Own&& hook) + : Results::Reader(reader), hook(kj::mv(hook)) {} + +private: + kj::Own hook; + + template + friend class Request; + friend class ResponseHook; +}; + +class Capability::Client { + // Base type for capability clients. + +public: + typedef Capability Reads; + typedef Capability Calls; + + Client(decltype(nullptr)); + // If you need to declare a Client before you have anything to assign to it (perhaps because + // the assignment is going to occur in an if/else scope), you can start by initializing it to + // `nullptr`. The resulting client is not meant to be called and throws exceptions from all + // methods. + + template ()>> + Client(kj::Own&& server); + // Make a client capability that wraps the given server capability. The server's methods will + // only be executed in the given EventLoop, regardless of what thread calls the client's methods. + + template ()>> + Client(kj::Promise&& promise); + // Make a client from a promise for a future client. The resulting client queues calls until the + // promise resolves. + + Client(kj::Exception&& exception); + // Make a broken client that throws the given exception from all calls. + + Client(Client& other); + Client& operator=(Client& other); + // Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of + // the client must remain in one thread. + + Client(Client&&) = default; + Client& operator=(Client&&) = default; + // Move constructor avoids reference counting. + + explicit Client(kj::Own&& hook); + // For use by the RPC implementation: Wrap a ClientHook. + + template + typename T::Client castAs(); + // Reinterpret the capability as implementing the given interface. Note that no error will occur + // here if the capability does not actually implement this interface, but later method calls will + // fail. It's up to the application to decide how indicate that additional interfaces are + // supported. + // + // TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance. + + template + typename T::Client castAs(InterfaceSchema schema); + // Dynamic version. `T` must be `DynamicCapability`, and you must `#include `. + + kj::Promise whenResolved(); + // If the capability is actually only a promise, the returned promise resolves once the + // capability itself has resolved to its final destination (or propagates the exception if + // the capability promise is rejected). This is mainly useful for error-checking in the case + // where no calls are being made. There is no reason to wait for this before making calls; if + // the capability does not resolve, the call results will propagate the error. + + Request typelessRequest( + uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint); + // Make a request without knowing the types of the params or results. You specify the type ID + // and method number manually. + + // TODO(someday): method(s) for Join + +protected: + Client() = default; + + template + Request newCall(uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint); + +private: + kj::Own hook; + + static kj::Own makeLocalClient(kj::Own&& server); + + template + friend struct _::PointerHelpers; + friend struct DynamicCapability; + friend class Orphanage; + friend struct DynamicStruct; + friend struct DynamicList; + template + friend struct List; + friend class _::CapabilityServerSetBase; + friend class ClientHook; +}; + +// ======================================================================================= +// Capability servers + +class CallContextHook; + +template +class CallContext: public kj::DisallowConstCopy { + // Wrapper around CallContextHook with a specific return type. + // + // Methods of this class may only be called from within the server's event loop, not from other + // threads. + // + // The CallContext becomes invalid as soon as the call reports completion. + +public: + explicit CallContext(CallContextHook& hook); + + typename Params::Reader getParams(); + // Get the params payload. + + void releaseParams(); + // Release the params payload. getParams() will throw an exception after this is called. + // Releasing the params may allow the RPC system to free up buffer space to handle other + // requests. Long-running asynchronous methods should try to call this as early as is + // convenient. + + typename Results::Builder getResults(kj::Maybe sizeHint = nullptr); + typename Results::Builder initResults(kj::Maybe sizeHint = nullptr); + void setResults(typename Results::Reader value); + void adoptResults(Orphan&& value); + Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); + // Manipulate the results payload. The "Return" message (part of the RPC protocol) will + // typically be allocated the first time one of these is called. Some RPC systems may + // allocate these messages in a limited space (such as a shared memory segment), therefore the + // application should delay calling these as long as is convenient to do so (but don't delay + // if doing so would require extra copies later). + // + // `sizeHint` indicates a guess at the message size. This will usually be used to decide how + // much space to allocate for the first message segment (don't worry: only space that is actually + // used will be sent on the wire). If omitted, the system decides. The message root pointer + // should not be included in the size. So, if you are simply going to copy some existing message + // directly into the results, just call `.totalSize()` and pass that in. + + template + kj::Promise tailCall(Request&& tailRequest); + // Resolve the call by making a tail call. `tailRequest` is a request that has been filled in + // but not yet sent. The context will send the call, then fill in the results with the result + // of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called. + // + // The RPC implementation may be able to optimize a tail call to another machine such that the + // results never actually pass through this machine. Even if no such optimization is possible, + // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site. + // + // In general, this should be the last thing a method implementation calls, and the promise + // returned from `tailCall()` should then be returned by the method implementation. + + void allowCancellation(); + // Indicate that it is OK for the RPC system to discard its Promise for this call's result if + // the caller cancels the call, thereby transitively canceling any asynchronous operations the + // call implementation was performing. This is not done by default because it could represent a + // security risk: applications must be carefully written to ensure that they do not end up in + // a bad state if an operation is canceled at an arbitrary point. However, for long-running + // method calls that hold significant resources, prompt cancellation is often useful. + // + // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously + // executing on a local thread. The method must perform an asynchronous operation or call + // `EventLoop::current().evalLater()` to yield control. + // + // Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that + // provide notification when the caller cancels the request without forcefully killing off the + // promise chain. Unfortunately, this composes poorly with promise forking: the canceled + // path may be just one branch of a fork of the result promise. The other branches still want + // the call to continue. Promise forking is used within the Cap'n Proto implementation -- in + // particular each pipelined call forks the result promise. So, if a caller made a pipelined + // call and then dropped the original object, the call should not be canceled, but it would be + // excessively complicated for the framework to avoid notififying of cancellation as long as + // pipelined calls still exist. + +private: + CallContextHook* hook; + + friend class Capability::Server; + friend struct DynamicCapability; +}; + +class Capability::Server { + // Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects + // will instead subclass a typed Server interface which will take care of implementing + // dispatchCall(). + +public: + typedef Capability Serves; + + virtual kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + CallContext context) = 0; + // Call the given method. `params` is the input struct, and should be released as soon as it + // is no longer needed. `context` may be used to allocate the output struct and deal with + // cancellation. + + // TODO(someday): Method which can optionally be overridden to implement Join when the object is + // a proxy. + +protected: + inline Capability::Client thisCap(); + // Get a capability pointing to this object, much like the `this` keyword. + // + // The effect of this method is undefined if: + // - No capability client has been created pointing to this object. (This is always the case in + // the server's constructor.) + // - The capability client pointing at this object has been destroyed. (This is always the case + // in the server's destructor.) + // - Multiple capability clients have been created around the same server (possible if the server + // is refcounted, which is not recommended since the client itself provides refcounting). + + template + CallContext internalGetTypedContext( + CallContext typeless); + kj::Promise internalUnimplemented(const char* actualInterfaceName, + uint64_t requestedTypeId); + kj::Promise internalUnimplemented(const char* interfaceName, + uint64_t typeId, uint16_t methodId); + kj::Promise internalUnimplemented(const char* interfaceName, const char* methodName, + uint64_t typeId, uint16_t methodId); + +private: + ClientHook* thisHook = nullptr; + friend class LocalClient; +}; + +// ======================================================================================= + +class ReaderCapabilityTable: private _::CapTableReader { + // Class which imbues Readers with the ability to read capabilities. + // + // In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into + // an external table. Since these pointers fundamentally point outside the message, a + // MessageReader by default has no idea what they point at, and therefore reading capabilities + // from such a reader will throw exceptions. + // + // In order to be able to read capabilities, you must first attach a capability table, using + // this class. By "imbuing" a Reader, you get a new Reader which will interpret capability + // pointers by treating them as indexes into the ReaderCapabilityTable. + // + // Note that when using Cap'n Proto's RPC system, this is handled automatically. + +public: + explicit ReaderCapabilityTable(kj::Array>> table); + KJ_DISALLOW_COPY(ReaderCapabilityTable); + + template + T imbue(T reader); + // Return a reader equivalent to `reader` except that when reading capability-valued fields, + // the capabilities are looked up in this table. + +private: + kj::Array>> table; + + kj::Maybe> extractCap(uint index) override; +}; + +class BuilderCapabilityTable: private _::CapTableBuilder { + // Class which imbues Builders with the ability to read and write capabilities. + // + // This is much like ReaderCapabilityTable, except for builders. The table starts out empty, + // but capabilities can be added to it over time. + +public: + BuilderCapabilityTable(); + KJ_DISALLOW_COPY(BuilderCapabilityTable); + + inline kj::ArrayPtr>> getTable() { return table; } + + template + T imbue(T builder); + // Return a builder equivalent to `builder` except that when reading capability-valued fields, + // the capabilities are looked up in this table. + +private: + kj::Vector>> table; + + kj::Maybe> extractCap(uint index) override; + uint injectCap(kj::Own&& cap) override; + void dropCap(uint index) override; +}; + +// ======================================================================================= + +namespace _ { // private + +class CapabilityServerSetBase { +public: + Capability::Client addInternal(kj::Own&& server, void* ptr); + kj::Promise getLocalServerInternal(Capability::Client& client); +}; + +} // namespace _ (private) + +template +class CapabilityServerSet: private _::CapabilityServerSetBase { + // Allows a server to recognize its own capabilities when passed back to it, and obtain the + // underlying Server objects associated with them. + // + // All objects in the set must have the same interface type T. The objects may implement various + // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects), + // but note that if you compile with RTTI disabled then you will not be able to down-cast through + // virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI + // disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type, + // and you server class will need to be directly derived from that, so that you can use + // static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile + // with RTTI, then you can freely dynamic_cast and ignore this issue!) + +public: + CapabilityServerSet() = default; + KJ_DISALLOW_COPY(CapabilityServerSet); + + typename T::Client add(kj::Own&& server); + // Create a new capability Client for the given Server and also add this server to the set. + + kj::Promise> getLocalServer(typename T::Client& client); + // Given a Client pointing to a server previously passed to add(), return the corresponding + // Server. This returns a promise because if the input client is itself a promise, this must + // wait for it to resolve. Keep in mind that the server will be deleted when all clients are + // gone, so the caller should make sure to keep the client alive (hence why this method only + // accepts an lvalue input). +}; + +// ======================================================================================= +// Hook interfaces which must be implemented by the RPC system. Applications never call these +// directly; the RPC system implements them and the types defined earlier in this file wrap them. + +class RequestHook { + // Hook interface implemented by RPC system representing a request being built. + +public: + virtual RemotePromise send() = 0; + // Send the call and return a promise for the result. + + virtual const void* getBrand() = 0; + // Returns a void* that identifies who made this request. This can be used by an RPC adapter to + // discover when tail call is going to be sent over its own connection and therefore can be + // optimized into a remote tail call. + + template + inline static kj::Own from(Request&& request) { + return kj::mv(request.hook); + } +}; + +class ResponseHook { + // Hook interface implemented by RPC system representing a response. + // + // At present this class has no methods. It exists only for garbage collection -- when the + // ResponseHook is destroyed, the results can be freed. + +public: + virtual ~ResponseHook() noexcept(false); + // Just here to make sure the type is dynamic. + + template + inline static kj::Own from(Response&& response) { + return kj::mv(response.hook); + } +}; + +// class PipelineHook is declared in any.h because it is needed there. + +class ClientHook { +public: + ClientHook(); + + virtual Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) = 0; + // Start a new call, allowing the client to allocate request/response objects as it sees fit. + // This version is used when calls are made from application code in the local process. + + struct VoidPromiseAndPipeline { + kj::Promise promise; + kj::Own pipeline; + }; + + virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) = 0; + // Call the object, but the caller controls allocation of the request/response objects. If the + // callee insists on allocating these objects itself, it must make a copy. This version is used + // when calls come in over the network via an RPC system. Note that even if the returned + // `Promise` is discarded, the call may continue executing if any pipelined calls are + // waiting for it. + // + // Since the caller of this method chooses the CallContext implementation, it is the caller's + // responsibility to ensure that the returned promise is not canceled unless allowed via + // the context's `allowCancellation()`. + // + // The call must not begin synchronously; the callee must arrange for the call to begin in a + // later turn of the event loop. Otherwise, application code may call back and affect the + // callee's state in an unexpected way. + + virtual kj::Maybe getResolved() = 0; + // If this ClientHook is a promise that has already resolved, returns the inner, resolved version + // of the capability. The caller may permanently replace this client with the resolved one if + // desired. Returns null if the client isn't a promise or hasn't resolved yet -- use + // `whenMoreResolved()` to distinguish between them. + + virtual kj::Maybe>> whenMoreResolved() = 0; + // If this client is a settled reference (not a promise), return nullptr. Otherwise, return a + // promise that eventually resolves to a new client that is closer to being the final, settled + // client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly + // should eventually produce a settled client. + + kj::Promise whenResolved(); + // Repeatedly calls whenMoreResolved() until it returns nullptr. + + virtual kj::Own addRef() = 0; + // Return a new reference to the same capability. + + virtual const void* getBrand() = 0; + // Returns a void* that identifies who made this client. This can be used by an RPC adapter to + // discover when a capability it needs to marshal is one that it created in the first place, and + // therefore it can transfer the capability without proxying. + + static const uint NULL_CAPABILITY_BRAND; + // Value is irrelevant; used for pointer. + + inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; } + // Returns true if the capability was created as a result of assigning a Client to null or by + // reading a null pointer out of a Cap'n Proto message. + + virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet); + // If this is a local capability created through `capServerSet`, return the underlying Server. + // Otherwise, return nullptr. Default implementation (which everyone except LocalClient should + // use) always returns nullptr. + + static kj::Own from(Capability::Client client) { return kj::mv(client.hook); } +}; + +class CallContextHook { + // Hook interface implemented by RPC system to manage a call on the server side. See + // CallContext. + +public: + virtual AnyPointer::Reader getParams() = 0; + virtual void releaseParams() = 0; + virtual AnyPointer::Builder getResults(kj::Maybe sizeHint) = 0; + virtual kj::Promise tailCall(kj::Own&& request) = 0; + virtual void allowCancellation() = 0; + + virtual kj::Promise onTailCall() = 0; + // If `tailCall()` is called, resolves to the PipelineHook from the tail call. An + // implementation of `ClientHook::call()` is allowed to call this at most once. + + virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) = 0; + // Call this when you would otherwise call onTailCall() immediately followed by tailCall(). + // Implementations of tailCall() should typically call directTailCall() and then fulfill the + // promise fulfiller for onTailCall() with the returned pipeline. + + virtual kj::Own addRef() = 0; +}; + +kj::Own newLocalPromiseClient(kj::Promise>&& promise); +// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to +// the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the +// redirection to the eventual replacement client. + +kj::Own newLocalPromisePipeline(kj::Promise>&& promise); +// Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to +// the new pipeline. + +kj::Own newBrokenCap(kj::StringPtr reason); +kj::Own newBrokenCap(kj::Exception&& reason); +// Helper function that creates a capability which simply throws exceptions when called. + +kj::Own newBrokenPipeline(kj::Exception&& reason); +// Helper function that creates a pipeline which simply throws exceptions when called. + +Request newBrokenRequest( + kj::Exception&& reason, kj::Maybe sizeHint); +// Helper function that creates a Request object that simply throws exceptions when sent. + +// ======================================================================================= +// Extend PointerHelpers for interfaces + +namespace _ { // private + +template +struct PointerHelpers { + static inline typename T::Client get(PointerReader reader) { + return typename T::Client(reader.getCapability()); + } + static inline typename T::Client get(PointerBuilder builder) { + return typename T::Client(builder.getCapability()); + } + static inline void set(PointerBuilder builder, typename T::Client&& value) { + builder.setCapability(kj::mv(value.Capability::Client::hook)); + } + static inline void set(PointerBuilder builder, typename T::Client& value) { + builder.setCapability(value.Capability::Client::hook->addRef()); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +} // namespace _ (private) + +// ======================================================================================= +// Extend List for interfaces + +template +struct List { + List() = delete; + + class Reader { + public: + typedef List Reads; + + Reader() = default; + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Client operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename T::Client(reader.getPointerElement( + bounded(index) * ELEMENTS).getCapability()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Client operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename T::Client(builder.getPointerElement( + bounded(index) * ELEMENTS).getCapability()); + } + inline void set(uint index, typename T::Client value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(value.hook)); + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +// ======================================================================================= +// Inline implementation details + +template +RemotePromise Request::send() { + auto typelessPromise = hook->send(); + hook = nullptr; // prevent reuse + + // Convert the Promise to return the correct response type. + // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the + // Pipeline part of the RemotePromise. + auto typedPromise = kj::implicitCast>&>(typelessPromise) + .then([](Response&& response) -> Response { + return Response(response.getAs(), kj::mv(response.hook)); + }); + + // Wrap the typeless pipeline in a typed wrapper. + typename Results::Pipeline typedPipeline( + kj::mv(kj::implicitCast(typelessPromise))); + + return RemotePromise(kj::mv(typedPromise), kj::mv(typedPipeline)); +} + +inline Capability::Client::Client(kj::Own&& hook): hook(kj::mv(hook)) {} +template +inline Capability::Client::Client(kj::Own&& server) + : hook(makeLocalClient(kj::mv(server))) {} +template +inline Capability::Client::Client(kj::Promise&& promise) + : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {} +inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {} +inline Capability::Client& Capability::Client::operator=(Client& other) { + hook = other.hook->addRef(); + return *this; +} +template +inline typename T::Client Capability::Client::castAs() { + return typename T::Client(hook->addRef()); +} +inline kj::Promise Capability::Client::whenResolved() { + return hook->whenResolved(); +} +inline Request Capability::Client::typelessRequest( + uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint) { + return newCall(interfaceId, methodId, sizeHint); +} +template +inline Request Capability::Client::newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) { + auto typeless = hook->newCall(interfaceId, methodId, sizeHint); + return Request(typeless.template getAs(), kj::mv(typeless.hook)); +} + +template +inline CallContext::CallContext(CallContextHook& hook): hook(&hook) {} +template +inline typename Params::Reader CallContext::getParams() { + return hook->getParams().template getAs(); +} +template +inline void CallContext::releaseParams() { + hook->releaseParams(); +} +template +inline typename Results::Builder CallContext::getResults( + kj::Maybe sizeHint) { + // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 + return hook->getResults(sizeHint).template getAs(); +} +template +inline typename Results::Builder CallContext::initResults( + kj::Maybe sizeHint) { + // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 + return hook->getResults(sizeHint).template initAs(); +} +template +inline void CallContext::setResults(typename Results::Reader value) { + hook->getResults(value.totalSize()).template setAs(value); +} +template +inline void CallContext::adoptResults(Orphan&& value) { + hook->getResults(nullptr).adopt(kj::mv(value)); +} +template +inline Orphanage CallContext::getResultsOrphanage( + kj::Maybe sizeHint) { + return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); +} +template +template +inline kj::Promise CallContext::tailCall( + Request&& tailRequest) { + return hook->tailCall(kj::mv(tailRequest.hook)); +} +template +inline void CallContext::allowCancellation() { + hook->allowCancellation(); +} + +template +CallContext Capability::Server::internalGetTypedContext( + CallContext typeless) { + return CallContext(*typeless.hook); +} + +Capability::Client Capability::Server::thisCap() { + return Client(thisHook->addRef()); +} + +template +T ReaderCapabilityTable::imbue(T reader) { + return T(_::PointerHelpers>::getInternalReader(reader).imbue(this)); +} + +template +T BuilderCapabilityTable::imbue(T builder) { + return T(_::PointerHelpers>::getInternalBuilder(kj::mv(builder)).imbue(this)); +} + +template +typename T::Client CapabilityServerSet::add(kj::Own&& server) { + void* ptr = reinterpret_cast(server.get()); + // Clang insists that `castAs` is a template-dependent member and therefore we need the + // `template` keyword here, but AFAICT this is wrong: addImpl() is not a template. + return addInternal(kj::mv(server), ptr).template castAs(); +} + +template +kj::Promise> CapabilityServerSet::getLocalServer( + typename T::Client& client) { + return getLocalServerInternal(client) + .then([](void* server) -> kj::Maybe { + if (server == nullptr) { + return nullptr; + } else { + return *reinterpret_cast(server); + } + }); +} + +template +struct Orphanage::GetInnerReader { + static inline kj::Own apply(typename T::Client t) { + return ClientHook::from(kj::mv(t)); + } +}; + +} // namespace capnp + +#endif // CAPNP_CAPABILITY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/common.h --- a/osx/include/capnp/common.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/common.h Mon May 22 10:01:37 2017 +0100 @@ -1,487 +1,719 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file contains types which are intended to help detect incorrect usage at compile -// time, but should then be optimized down to basic primitives (usually, integers) by the -// compiler. - -#ifndef CAPNP_COMMON_H_ -#define CAPNP_COMMON_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include -#include -#include - -namespace capnp { - -#define CAPNP_VERSION_MAJOR 0 -#define CAPNP_VERSION_MINOR 6 -#define CAPNP_VERSION_MICRO 0 - -#define CAPNP_VERSION \ - (CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO) - -#ifdef _MSC_VER -#define CAPNP_LITE 1 -// MSVC only supports "lite" mode for now, due to missing C++11 features. -#endif - -#ifndef CAPNP_LITE -#define CAPNP_LITE 0 -#endif - -typedef unsigned int uint; - -struct Void { - // Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves - // differently from other types. - - inline constexpr bool operator==(Void other) const { return true; } - inline constexpr bool operator!=(Void other) const { return false; } -}; - -static constexpr Void VOID = Void(); -// Constant value for `Void`, which is an empty struct. - -inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; } - -struct Text; -struct Data; - -enum class Kind: uint8_t { - PRIMITIVE, - BLOB, - ENUM, - STRUCT, - UNION, - INTERFACE, - LIST, - - OTHER - // Some other type which is often a type parameter to Cap'n Proto templates, but which needs - // special handling. This includes types like AnyPointer, Dynamic*, etc. -}; - -enum class Style: uint8_t { - PRIMITIVE, - POINTER, // other than struct - STRUCT, - CAPABILITY -}; - -enum class ElementSize: uint8_t { - // Size of a list element. - - VOID = 0, - BIT = 1, - BYTE = 2, - TWO_BYTES = 3, - FOUR_BYTES = 4, - EIGHT_BYTES = 5, - - POINTER = 6, - - INLINE_COMPOSITE = 7 -}; - -enum class PointerType { - // Various wire types a pointer field can take - - NULL_, - // Should be NULL, but that's #defined in stddef.h - - STRUCT, - LIST, - CAPABILITY -}; - -namespace schemas { - -template -struct EnumInfo; - -} // namespace schemas - -namespace _ { // private - -template struct Kind_; - -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; - -template struct Kind_> { - static constexpr Kind kind = Kind::STRUCT; -}; -template struct Kind_> { - static constexpr Kind kind = Kind::INTERFACE; -}; -template struct Kind_::IsEnum>> { - static constexpr Kind kind = Kind::ENUM; -}; - -} // namespace _ (private) - -template ::kind> -inline constexpr Kind kind() { - // This overload of kind() matches types which have a Kind_ specialization. - - return k; -} - -#if CAPNP_LITE - -#define CAPNP_KIND(T) ::capnp::_::Kind_::kind -// Avoid constexpr methods in lite mode (MSVC is bad at constexpr). - -#else // CAPNP_LITE - -#define CAPNP_KIND(T) ::capnp::kind() -// Use this macro rather than kind() in any code which must work in lite mode. - -template ()> -inline constexpr Style style() { - return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE - : k == Kind::STRUCT ? Style::STRUCT - : k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER; -} - -#endif // CAPNP_LITE, else - -template -struct List; - -#if _MSC_VER - -template -struct List {}; -// For some reason, without this declaration, MSVC will error out on some uses of List -// claiming that "T" -- as used in the default initializer for the second template param, "k" -- -// is not defined. I do not understand this error, but adding this empty default declaration fixes -// it. - -#endif - -template struct ListElementType_; -template struct ListElementType_> { typedef T Type; }; -template using ListElementType = typename ListElementType_::Type; - -namespace _ { // private -template struct Kind_> { - static constexpr Kind kind = Kind::LIST; -}; -} // namespace _ (private) - -template struct ReaderFor_ { typedef typename T::Reader Type; }; -template struct ReaderFor_ { typedef T Type; }; -template struct ReaderFor_ { typedef T Type; }; -template struct ReaderFor_ { typedef typename T::Client Type; }; -template using ReaderFor = typename ReaderFor_::Type; -// The type returned by List::Reader::operator[]. - -template struct BuilderFor_ { typedef typename T::Builder Type; }; -template struct BuilderFor_ { typedef T Type; }; -template struct BuilderFor_ { typedef T Type; }; -template struct BuilderFor_ { typedef typename T::Client Type; }; -template using BuilderFor = typename BuilderFor_::Type; -// The type returned by List::Builder::operator[]. - -template struct PipelineFor_ { typedef typename T::Pipeline Type;}; -template struct PipelineFor_ { typedef typename T::Client Type; }; -template using PipelineFor = typename PipelineFor_::Type; - -template struct TypeIfEnum_; -template struct TypeIfEnum_ { typedef T Type; }; - -template -using TypeIfEnum = typename TypeIfEnum_>::Type; - -template -using FromReader = typename kj::Decay::Reads; -// FromReader = MyType (for any Cap'n Proto type). - -template -using FromBuilder = typename kj::Decay::Builds; -// FromBuilder = MyType (for any Cap'n Proto type). - -template -using FromPipeline = typename kj::Decay::Pipelines; -// FromBuilder = MyType (for any Cap'n Proto type). - -template -using FromClient = typename kj::Decay::Calls; -// FromReader = MyType (for any Cap'n Proto interface type). - -template -using FromServer = typename kj::Decay::Serves; -// FromBuilder = MyType (for any Cap'n Proto interface type). - -template -struct FromAny_; - -template -struct FromAny_>> { - using Type = FromReader; -}; - -template -struct FromAny_>> { - using Type = FromBuilder; -}; - -template -struct FromAny_>> { - using Type = FromPipeline; -}; - -// Note that T::Client is covered by FromReader - -template -struct FromAny_, kj::VoidSfinae>> { - using Type = FromServer; -}; - -template -struct FromAny_::kind == Kind::PRIMITIVE || _::Kind_::kind == Kind::ENUM>> { - // TODO(msvc): Ideally the EnableIf condition would be `style() == Style::PRIMITIVE`, but MSVC - // cannot yet use style() in this constexpr context. - - using Type = kj::Decay; -}; - -template -using FromAny = typename FromAny_::Type; -// Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is: -// -// Foo::Reader -> Foo -// Foo::Builder -> Foo -// Foo::Pipeline -> Foo -// Foo::Client -> Foo -// Own -> Foo -// uint32_t -> uint32_t - -namespace _ { // private - -template -struct PointerHelpers; - -#if _MSC_VER - -template -struct PointerHelpers {}; -// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers -// claiming that "T" -- as used in the default initializer for the second template param, "k" -- -// is not defined. I do not understand this error, but adding this empty default declaration fixes -// it. - -#endif - -} // namespace _ (private) - -struct MessageSize { - // Size of a message. Every struct type has a method `.totalSize()` that returns this. - uint64_t wordCount; - uint capCount; -}; - -// ======================================================================================= -// Raw memory types and measures - -using kj::byte; - -class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: word() = default; }; -// word is an opaque type with size of 64 bits. This type is useful only to make pointer -// arithmetic clearer. Since the contents are private, the only way to access them is to first -// reinterpret_cast to some other pointer type. -// -// Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of -// aliasing rules. -// -// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as -// that type. - -static_assert(sizeof(byte) == 1, "uint8_t is not one byte?"); -static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?"); - -#if CAPNP_DEBUG_TYPES -// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are -// used. All the code should still operate exactly the same, we just lose compile-time checking. -// Note that this will also change symbol names, so it's important that the library and any clients -// be compiled with the same setting here. -// -// We disable this by default to reduce symbol name size and avoid any possibility of the compiler -// failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this -// during development and testing. - -namespace _ { class BitLabel; class ElementLabel; struct WirePointer; } - -typedef kj::Quantity BitCount; -typedef kj::Quantity BitCount8; -typedef kj::Quantity BitCount16; -typedef kj::Quantity BitCount32; -typedef kj::Quantity BitCount64; - -typedef kj::Quantity ByteCount; -typedef kj::Quantity ByteCount8; -typedef kj::Quantity ByteCount16; -typedef kj::Quantity ByteCount32; -typedef kj::Quantity ByteCount64; - -typedef kj::Quantity WordCount; -typedef kj::Quantity WordCount8; -typedef kj::Quantity WordCount16; -typedef kj::Quantity WordCount32; -typedef kj::Quantity WordCount64; - -typedef kj::Quantity ElementCount; -typedef kj::Quantity ElementCount8; -typedef kj::Quantity ElementCount16; -typedef kj::Quantity ElementCount32; -typedef kj::Quantity ElementCount64; - -typedef kj::Quantity WirePointerCount; -typedef kj::Quantity WirePointerCount8; -typedef kj::Quantity WirePointerCount16; -typedef kj::Quantity WirePointerCount32; -typedef kj::Quantity WirePointerCount64; - -template -inline constexpr U* operator+(U* ptr, kj::Quantity offset) { - return ptr + offset / kj::unit>(); -} -template -inline constexpr const U* operator+(const U* ptr, kj::Quantity offset) { - return ptr + offset / kj::unit>(); -} -template -inline constexpr U* operator+=(U*& ptr, kj::Quantity offset) { - return ptr = ptr + offset / kj::unit>(); -} -template -inline constexpr const U* operator+=(const U*& ptr, kj::Quantity offset) { - return ptr = ptr + offset / kj::unit>(); -} - -template -inline constexpr U* operator-(U* ptr, kj::Quantity offset) { - return ptr - offset / kj::unit>(); -} -template -inline constexpr const U* operator-(const U* ptr, kj::Quantity offset) { - return ptr - offset / kj::unit>(); -} -template -inline constexpr U* operator-=(U*& ptr, kj::Quantity offset) { - return ptr = ptr - offset / kj::unit>(); -} -template -inline constexpr const U* operator-=(const U*& ptr, kj::Quantity offset) { - return ptr = ptr - offset / kj::unit>(); -} - -#else - -typedef uint BitCount; -typedef uint8_t BitCount8; -typedef uint16_t BitCount16; -typedef uint32_t BitCount32; -typedef uint64_t BitCount64; - -typedef uint ByteCount; -typedef uint8_t ByteCount8; -typedef uint16_t ByteCount16; -typedef uint32_t ByteCount32; -typedef uint64_t ByteCount64; - -typedef uint WordCount; -typedef uint8_t WordCount8; -typedef uint16_t WordCount16; -typedef uint32_t WordCount32; -typedef uint64_t WordCount64; - -typedef uint ElementCount; -typedef uint8_t ElementCount8; -typedef uint16_t ElementCount16; -typedef uint32_t ElementCount32; -typedef uint64_t ElementCount64; - -typedef uint WirePointerCount; -typedef uint8_t WirePointerCount8; -typedef uint16_t WirePointerCount16; -typedef uint32_t WirePointerCount32; -typedef uint64_t WirePointerCount64; - -#endif - -constexpr BitCount BITS = kj::unit(); -constexpr ByteCount BYTES = kj::unit(); -constexpr WordCount WORDS = kj::unit(); -constexpr ElementCount ELEMENTS = kj::unit(); -constexpr WirePointerCount POINTERS = kj::unit(); - -// GCC 4.7 actually gives unused warnings on these constants in opt mode... -constexpr auto BITS_PER_BYTE KJ_UNUSED = 8 * BITS / BYTES; -constexpr auto BITS_PER_WORD KJ_UNUSED = 64 * BITS / WORDS; -constexpr auto BYTES_PER_WORD KJ_UNUSED = 8 * BYTES / WORDS; - -constexpr auto BITS_PER_POINTER KJ_UNUSED = 64 * BITS / POINTERS; -constexpr auto BYTES_PER_POINTER KJ_UNUSED = 8 * BYTES / POINTERS; -constexpr auto WORDS_PER_POINTER KJ_UNUSED = 1 * WORDS / POINTERS; - -constexpr WordCount POINTER_SIZE_IN_WORDS = 1 * POINTERS * WORDS_PER_POINTER; - -template -inline KJ_CONSTEXPR() decltype(BYTES / ELEMENTS) bytesPerElement() { - return sizeof(T) * BYTES / ELEMENTS; -} - -template -inline KJ_CONSTEXPR() decltype(BITS / ELEMENTS) bitsPerElement() { - return sizeof(T) * 8 * BITS / ELEMENTS; -} - -inline constexpr ByteCount intervalLength(const byte* a, const byte* b) { - return uint(b - a) * BYTES; -} -inline constexpr WordCount intervalLength(const word* a, const word* b) { - return uint(b - a) * WORDS; -} - -} // namespace capnp - -#endif // CAPNP_COMMON_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains types which are intended to help detect incorrect usage at compile +// time, but should then be optimized down to basic primitives (usually, integers) by the +// compiler. + +#ifndef CAPNP_COMMON_H_ +#define CAPNP_COMMON_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include + +#if CAPNP_DEBUG_TYPES +#include +#endif + +namespace capnp { + +#define CAPNP_VERSION_MAJOR 0 +#define CAPNP_VERSION_MINOR 6 +#define CAPNP_VERSION_MICRO 0 + +#define CAPNP_VERSION \ + (CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO) + +#ifndef CAPNP_LITE +#define CAPNP_LITE 0 +#endif + +typedef unsigned int uint; + +struct Void { + // Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves + // differently from other types. + + inline constexpr bool operator==(Void other) const { return true; } + inline constexpr bool operator!=(Void other) const { return false; } +}; + +static constexpr Void VOID = Void(); +// Constant value for `Void`, which is an empty struct. + +inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; } + +struct Text; +struct Data; + +enum class Kind: uint8_t { + PRIMITIVE, + BLOB, + ENUM, + STRUCT, + UNION, + INTERFACE, + LIST, + + OTHER + // Some other type which is often a type parameter to Cap'n Proto templates, but which needs + // special handling. This includes types like AnyPointer, Dynamic*, etc. +}; + +enum class Style: uint8_t { + PRIMITIVE, + POINTER, // other than struct + STRUCT, + CAPABILITY +}; + +enum class ElementSize: uint8_t { + // Size of a list element. + + VOID = 0, + BIT = 1, + BYTE = 2, + TWO_BYTES = 3, + FOUR_BYTES = 4, + EIGHT_BYTES = 5, + + POINTER = 6, + + INLINE_COMPOSITE = 7 +}; + +enum class PointerType { + // Various wire types a pointer field can take + + NULL_, + // Should be NULL, but that's #defined in stddef.h + + STRUCT, + LIST, + CAPABILITY +}; + +namespace schemas { + +template +struct EnumInfo; + +} // namespace schemas + +namespace _ { // private + +template struct Kind_; + +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; + +template struct Kind_> { + static constexpr Kind kind = Kind::STRUCT; +}; +template struct Kind_> { + static constexpr Kind kind = Kind::INTERFACE; +}; +template struct Kind_::IsEnum>> { + static constexpr Kind kind = Kind::ENUM; +}; + +} // namespace _ (private) + +template ::kind> +inline constexpr Kind kind() { + // This overload of kind() matches types which have a Kind_ specialization. + + return k; +} + +#if CAPNP_LITE + +#define CAPNP_KIND(T) ::capnp::_::Kind_::kind +// Avoid constexpr methods in lite mode (MSVC is bad at constexpr). + +#else // CAPNP_LITE + +#define CAPNP_KIND(T) ::capnp::kind() +// Use this macro rather than kind() in any code which must work in lite mode. + +template ()> +inline constexpr Style style() { + return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE + : k == Kind::STRUCT ? Style::STRUCT + : k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER; +} + +#endif // CAPNP_LITE, else + +template +struct List; + +#if _MSC_VER + +template +struct List {}; +// For some reason, without this declaration, MSVC will error out on some uses of List +// claiming that "T" -- as used in the default initializer for the second template param, "k" -- +// is not defined. I do not understand this error, but adding this empty default declaration fixes +// it. + +#endif + +template struct ListElementType_; +template struct ListElementType_> { typedef T Type; }; +template using ListElementType = typename ListElementType_::Type; + +namespace _ { // private +template struct Kind_> { + static constexpr Kind kind = Kind::LIST; +}; +} // namespace _ (private) + +template struct ReaderFor_ { typedef typename T::Reader Type; }; +template struct ReaderFor_ { typedef T Type; }; +template struct ReaderFor_ { typedef T Type; }; +template struct ReaderFor_ { typedef typename T::Client Type; }; +template using ReaderFor = typename ReaderFor_::Type; +// The type returned by List::Reader::operator[]. + +template struct BuilderFor_ { typedef typename T::Builder Type; }; +template struct BuilderFor_ { typedef T Type; }; +template struct BuilderFor_ { typedef T Type; }; +template struct BuilderFor_ { typedef typename T::Client Type; }; +template using BuilderFor = typename BuilderFor_::Type; +// The type returned by List::Builder::operator[]. + +template struct PipelineFor_ { typedef typename T::Pipeline Type;}; +template struct PipelineFor_ { typedef typename T::Client Type; }; +template using PipelineFor = typename PipelineFor_::Type; + +template struct TypeIfEnum_; +template struct TypeIfEnum_ { typedef T Type; }; + +template +using TypeIfEnum = typename TypeIfEnum_>::Type; + +template +using FromReader = typename kj::Decay::Reads; +// FromReader = MyType (for any Cap'n Proto type). + +template +using FromBuilder = typename kj::Decay::Builds; +// FromBuilder = MyType (for any Cap'n Proto type). + +template +using FromPipeline = typename kj::Decay::Pipelines; +// FromBuilder = MyType (for any Cap'n Proto type). + +template +using FromClient = typename kj::Decay::Calls; +// FromReader = MyType (for any Cap'n Proto interface type). + +template +using FromServer = typename kj::Decay::Serves; +// FromBuilder = MyType (for any Cap'n Proto interface type). + +template +struct FromAny_; + +template +struct FromAny_>> { + using Type = FromReader; +}; + +template +struct FromAny_>> { + using Type = FromBuilder; +}; + +template +struct FromAny_>> { + using Type = FromPipeline; +}; + +// Note that T::Client is covered by FromReader + +template +struct FromAny_, kj::VoidSfinae>> { + using Type = FromServer; +}; + +template +struct FromAny_::kind == Kind::PRIMITIVE || _::Kind_::kind == Kind::ENUM>> { + // TODO(msvc): Ideally the EnableIf condition would be `style() == Style::PRIMITIVE`, but MSVC + // cannot yet use style() in this constexpr context. + + using Type = kj::Decay; +}; + +template +using FromAny = typename FromAny_::Type; +// Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is: +// +// Foo::Reader -> Foo +// Foo::Builder -> Foo +// Foo::Pipeline -> Foo +// Foo::Client -> Foo +// Own -> Foo +// uint32_t -> uint32_t + +namespace _ { // private + +template +struct PointerHelpers; + +#if _MSC_VER + +template +struct PointerHelpers {}; +// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers +// claiming that "T" -- as used in the default initializer for the second template param, "k" -- +// is not defined. I do not understand this error, but adding this empty default declaration fixes +// it. + +#endif + +} // namespace _ (private) + +struct MessageSize { + // Size of a message. Every struct type has a method `.totalSize()` that returns this. + uint64_t wordCount; + uint capCount; +}; + +// ======================================================================================= +// Raw memory types and measures + +using kj::byte; + +class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: word() = default; }; +// word is an opaque type with size of 64 bits. This type is useful only to make pointer +// arithmetic clearer. Since the contents are private, the only way to access them is to first +// reinterpret_cast to some other pointer type. +// +// Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of +// aliasing rules. +// +// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as +// that type. + +static_assert(sizeof(byte) == 1, "uint8_t is not one byte?"); +static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?"); + +#if CAPNP_DEBUG_TYPES +// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are +// used. All the code should still operate exactly the same, we just lose compile-time checking. +// Note that this will also change symbol names, so it's important that the library and any clients +// be compiled with the same setting here. +// +// We disable this by default to reduce symbol name size and avoid any possibility of the compiler +// failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this +// during development and testing. + +namespace _ { class BitLabel; class ElementLabel; struct WirePointer; } + +template +using BitCountN = kj::Quantity(), T>, _::BitLabel>; +template +using ByteCountN = kj::Quantity(), T>, byte>; +template +using WordCountN = kj::Quantity(), T>, word>; +template +using ElementCountN = kj::Quantity(), T>, _::ElementLabel>; +template +using WirePointerCountN = kj::Quantity(), T>, _::WirePointer>; + +typedef BitCountN<8, uint8_t> BitCount8; +typedef BitCountN<16, uint16_t> BitCount16; +typedef BitCountN<32, uint32_t> BitCount32; +typedef BitCountN<64, uint64_t> BitCount64; +typedef BitCountN BitCount; + +typedef ByteCountN<8, uint8_t> ByteCount8; +typedef ByteCountN<16, uint16_t> ByteCount16; +typedef ByteCountN<32, uint32_t> ByteCount32; +typedef ByteCountN<64, uint64_t> ByteCount64; +typedef ByteCountN ByteCount; + +typedef WordCountN<8, uint8_t> WordCount8; +typedef WordCountN<16, uint16_t> WordCount16; +typedef WordCountN<32, uint32_t> WordCount32; +typedef WordCountN<64, uint64_t> WordCount64; +typedef WordCountN WordCount; + +typedef ElementCountN<8, uint8_t> ElementCount8; +typedef ElementCountN<16, uint16_t> ElementCount16; +typedef ElementCountN<32, uint32_t> ElementCount32; +typedef ElementCountN<64, uint64_t> ElementCount64; +typedef ElementCountN ElementCount; + +typedef WirePointerCountN<8, uint8_t> WirePointerCount8; +typedef WirePointerCountN<16, uint16_t> WirePointerCount16; +typedef WirePointerCountN<32, uint32_t> WirePointerCount32; +typedef WirePointerCountN<64, uint64_t> WirePointerCount64; +typedef WirePointerCountN WirePointerCount; + +template +using BitsPerElementN = decltype(BitCountN() / ElementCountN()); +template +using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); +template +using WordsPerElementN = decltype(WordCountN() / ElementCountN()); +template +using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); + +using kj::bounded; +using kj::unbound; +using kj::unboundAs; +using kj::unboundMax; +using kj::unboundMaxBits; +using kj::assertMax; +using kj::assertMaxBits; +using kj::upgradeBound; +using kj::ThrowOverflow; +using kj::assumeBits; +using kj::assumeMax; +using kj::subtractChecked; +using kj::trySubtract; + +template +inline constexpr U* operator+(U* ptr, kj::Quantity offset) { + return ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator+(const U* ptr, kj::Quantity offset) { + return ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr U* operator+=(U*& ptr, kj::Quantity offset) { + return ptr = ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator+=(const U*& ptr, kj::Quantity offset) { + return ptr = ptr + unbound(offset / kj::unit>()); +} + +template +inline constexpr U* operator-(U* ptr, kj::Quantity offset) { + return ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator-(const U* ptr, kj::Quantity offset) { + return ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr U* operator-=(U*& ptr, kj::Quantity offset) { + return ptr = ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator-=(const U*& ptr, kj::Quantity offset) { + return ptr = ptr - unbound(offset / kj::unit>()); +} + +constexpr auto BITS = kj::unit>(); +constexpr auto BYTES = kj::unit>(); +constexpr auto WORDS = kj::unit>(); +constexpr auto ELEMENTS = kj::unit>(); +constexpr auto POINTERS = kj::unit>(); + +constexpr auto ZERO = kj::bounded<0>(); +constexpr auto ONE = kj::bounded<1>(); + +// GCC 4.7 actually gives unused warnings on these constants in opt mode... +constexpr auto BITS_PER_BYTE KJ_UNUSED = bounded<8>() * BITS / BYTES; +constexpr auto BITS_PER_WORD KJ_UNUSED = bounded<64>() * BITS / WORDS; +constexpr auto BYTES_PER_WORD KJ_UNUSED = bounded<8>() * BYTES / WORDS; + +constexpr auto BITS_PER_POINTER KJ_UNUSED = bounded<64>() * BITS / POINTERS; +constexpr auto BYTES_PER_POINTER KJ_UNUSED = bounded<8>() * BYTES / POINTERS; +constexpr auto WORDS_PER_POINTER KJ_UNUSED = ONE * WORDS / POINTERS; + +constexpr auto POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; + +constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. +constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. +constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. +constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. +constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. + +typedef WordCountN SegmentWordCount; +typedef ElementCountN ListElementCount; +typedef WordCountN StructDataWordCount; +typedef WirePointerCountN StructPointerCount; +typedef ByteCountN BlobSize; + +constexpr auto MAX_SEGMENT_WORDS = + bounded()>() * WORDS; +constexpr auto MAX_LIST_ELEMENTS = + bounded()>() * ELEMENTS; +constexpr auto MAX_STUCT_DATA_WORDS = + bounded()>() * WORDS; +constexpr auto MAX_STRUCT_POINTER_COUNT = + bounded()>() * POINTERS; + +using StructDataBitCount = decltype(WordCountN() * BITS_PER_WORD); +// Number of bits in a Struct data segment (should come out to BitCountN<22>). + +using StructDataOffset = decltype(StructDataBitCount() * (ONE * ELEMENTS / BITS)); +using StructPointerOffset = StructPointerCount; +// Type of a field offset. + +inline StructDataOffset assumeDataOffset(uint32_t offset) { + return assumeMax(MAX_STUCT_DATA_WORDS * BITS_PER_WORD * (ONE * ELEMENTS / BITS), + bounded(offset) * ELEMENTS); +} + +inline StructPointerOffset assumePointerOffset(uint32_t offset) { + return assumeMax(MAX_STRUCT_POINTER_COUNT, bounded(offset) * POINTERS); +} + +constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; +typedef kj::Quantity, byte> TextSize; +// Not including NUL terminator. + +template +inline KJ_CONSTEXPR() decltype(bounded() * BYTES / ELEMENTS) bytesPerElement() { + return bounded() * BYTES / ELEMENTS; +} + +template +inline KJ_CONSTEXPR() decltype(bounded() * BITS / ELEMENTS) bitsPerElement() { + return bounded() * BITS / ELEMENTS; +} + +template +inline constexpr kj::Quantity, T> +intervalLength(const T* a, const T* b, kj::Quantity, T>) { + return kj::assumeMax(b - a) * kj::unit, T>>(); +} + +template +inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, kj::Quantity size) { + return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); +} +template +inline constexpr kj::ArrayPtr arrayPtr(U* ptr, kj::Quantity size) { + return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); +} + +#else + +template +using BitCountN = T; +template +using ByteCountN = T; +template +using WordCountN = T; +template +using ElementCountN = T; +template +using WirePointerCountN = T; + + +// XXX +typedef BitCountN<8, uint8_t> BitCount8; +typedef BitCountN<16, uint16_t> BitCount16; +typedef BitCountN<32, uint32_t> BitCount32; +typedef BitCountN<64, uint64_t> BitCount64; +typedef BitCountN BitCount; + +typedef ByteCountN<8, uint8_t> ByteCount8; +typedef ByteCountN<16, uint16_t> ByteCount16; +typedef ByteCountN<32, uint32_t> ByteCount32; +typedef ByteCountN<64, uint64_t> ByteCount64; +typedef ByteCountN ByteCount; + +typedef WordCountN<8, uint8_t> WordCount8; +typedef WordCountN<16, uint16_t> WordCount16; +typedef WordCountN<32, uint32_t> WordCount32; +typedef WordCountN<64, uint64_t> WordCount64; +typedef WordCountN WordCount; + +typedef ElementCountN<8, uint8_t> ElementCount8; +typedef ElementCountN<16, uint16_t> ElementCount16; +typedef ElementCountN<32, uint32_t> ElementCount32; +typedef ElementCountN<64, uint64_t> ElementCount64; +typedef ElementCountN ElementCount; + +typedef WirePointerCountN<8, uint8_t> WirePointerCount8; +typedef WirePointerCountN<16, uint16_t> WirePointerCount16; +typedef WirePointerCountN<32, uint32_t> WirePointerCount32; +typedef WirePointerCountN<64, uint64_t> WirePointerCount64; +typedef WirePointerCountN WirePointerCount; + +template +using BitsPerElementN = decltype(BitCountN() / ElementCountN()); +template +using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); +template +using WordsPerElementN = decltype(WordCountN() / ElementCountN()); +template +using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); + +using kj::ThrowOverflow; +// YYY + +template inline constexpr uint bounded() { return i; } +template inline constexpr T bounded(T i) { return i; } +template inline constexpr T unbound(T i) { return i; } + +template inline constexpr T unboundAs(U i) { return i; } + +template inline constexpr uint unboundMax(T i) { return i; } +template inline constexpr uint unboundMaxBits(T i) { return i; } + +template +inline T assertMax(T value, ErrorFunc&& func) { + if (KJ_UNLIKELY(value > newMax)) func(); + return value; +} + +template +inline T assertMax(uint newMax, T value, ErrorFunc&& func) { + if (KJ_UNLIKELY(value > newMax)) func(); + return value; +} + +template +inline T assertMaxBits(T value, ErrorFunc&& func = ErrorFunc()) { + if (KJ_UNLIKELY(value > kj::maxValueForBits())) func(); + return value; +} + +template +inline T assertMaxBits(uint bits, T value, ErrorFunc&& func = ErrorFunc()) { + if (KJ_UNLIKELY(value > (1ull << bits) - 1)) func(); + return value; +} + +template inline constexpr T upgradeBound(U i) { return i; } + +template inline constexpr T assumeBits(T i) { return i; } +template inline constexpr T assumeMax(T i) { return i; } + +template +inline auto subtractChecked(T a, U b, ErrorFunc&& errorFunc = ErrorFunc()) + -> decltype(a - b) { + if (b > a) errorFunc(); + return a - b; +} + +template +inline auto trySubtract(T a, U b) -> kj::Maybe { + if (b > a) { + return nullptr; + } else { + return a - b; + } +} + +constexpr uint BITS = 1; +constexpr uint BYTES = 1; +constexpr uint WORDS = 1; +constexpr uint ELEMENTS = 1; +constexpr uint POINTERS = 1; + +constexpr uint ZERO = 0; +constexpr uint ONE = 1; + +// GCC 4.7 actually gives unused warnings on these constants in opt mode... +constexpr uint BITS_PER_BYTE KJ_UNUSED = 8; +constexpr uint BITS_PER_WORD KJ_UNUSED = 64; +constexpr uint BYTES_PER_WORD KJ_UNUSED = 8; + +constexpr uint BITS_PER_POINTER KJ_UNUSED = 64; +constexpr uint BYTES_PER_POINTER KJ_UNUSED = 8; +constexpr uint WORDS_PER_POINTER KJ_UNUSED = 1; + +// XXX +constexpr uint POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; + +constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. +constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. +constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. +constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. +constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. + +typedef WordCountN SegmentWordCount; +typedef ElementCountN ListElementCount; +typedef WordCountN StructDataWordCount; +typedef WirePointerCountN StructPointerCount; +typedef ByteCountN BlobSize; +// YYY + +constexpr auto MAX_SEGMENT_WORDS = kj::maxValueForBits(); +constexpr auto MAX_LIST_ELEMENTS = kj::maxValueForBits(); +constexpr auto MAX_STUCT_DATA_WORDS = kj::maxValueForBits(); +constexpr auto MAX_STRUCT_POINTER_COUNT = kj::maxValueForBits(); + +typedef uint StructDataBitCount; +typedef uint StructDataOffset; +typedef uint StructPointerOffset; + +inline StructDataOffset assumeDataOffset(uint32_t offset) { return offset; } +inline StructPointerOffset assumePointerOffset(uint32_t offset) { return offset; } + +constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; +typedef uint TextSize; + +template +inline KJ_CONSTEXPR() size_t bytesPerElement() { return sizeof(T); } + +template +inline KJ_CONSTEXPR() size_t bitsPerElement() { return sizeof(T) * 8; } + +template +inline constexpr ptrdiff_t intervalLength(const T* a, const T* b, uint) { + return b - a; +} + +template +inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, T size) { + return kj::arrayPtr(ptr, size); +} +template +inline constexpr kj::ArrayPtr arrayPtr(U* ptr, T size) { + return kj::arrayPtr(ptr, size); +} + +#endif + +} // namespace capnp + +#endif // CAPNP_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/compat/json.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/capnp/compat/json.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,860 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: json.capnp + +#ifndef CAPNP_INCLUDED_8ef99297a43a5e34_ +#define CAPNP_INCLUDED_8ef99297a43a5e34_ + +#include +#if !CAPNP_LITE +#include +#endif // !CAPNP_LITE + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(8825ffaa852cda72); +CAPNP_DECLARE_SCHEMA(c27855d853a937cc); +CAPNP_DECLARE_SCHEMA(9bbf84153dd4bb60); + +} // namespace schemas +} // namespace capnp + +namespace capnp { + +struct JsonValue { + JsonValue() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NULL_, + BOOLEAN, + NUMBER, + STRING, + ARRAY, + OBJECT, + CALL, + }; + struct Field; + struct Call; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8825ffaa852cda72, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JsonValue::Field { + Field() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c27855d853a937cc, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JsonValue::Call { + Call() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9bbf84153dd4bb60, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class JsonValue::Reader { +public: + typedef JsonValue Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNull() const; + inline ::capnp::Void getNull() const; + + inline bool isBoolean() const; + inline bool getBoolean() const; + + inline bool isNumber() const; + inline double getNumber() const; + + inline bool isString() const; + inline bool hasString() const; + inline ::capnp::Text::Reader getString() const; + + inline bool isArray() const; + inline bool hasArray() const; + inline ::capnp::List< ::capnp::JsonValue>::Reader getArray() const; + + inline bool isObject() const; + inline bool hasObject() const; + inline ::capnp::List< ::capnp::JsonValue::Field>::Reader getObject() const; + + inline bool isCall() const; + inline bool hasCall() const; + inline ::capnp::JsonValue::Call::Reader getCall() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Builder { +public: + typedef JsonValue Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNull(); + inline ::capnp::Void getNull(); + inline void setNull( ::capnp::Void value = ::capnp::VOID); + + inline bool isBoolean(); + inline bool getBoolean(); + inline void setBoolean(bool value); + + inline bool isNumber(); + inline double getNumber(); + inline void setNumber(double value); + + inline bool isString(); + inline bool hasString(); + inline ::capnp::Text::Builder getString(); + inline void setString( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initString(unsigned int size); + inline void adoptString(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownString(); + + inline bool isArray(); + inline bool hasArray(); + inline ::capnp::List< ::capnp::JsonValue>::Builder getArray(); + inline void setArray( ::capnp::List< ::capnp::JsonValue>::Reader value); + inline ::capnp::List< ::capnp::JsonValue>::Builder initArray(unsigned int size); + inline void adoptArray(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownArray(); + + inline bool isObject(); + inline bool hasObject(); + inline ::capnp::List< ::capnp::JsonValue::Field>::Builder getObject(); + inline void setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value); + inline ::capnp::List< ::capnp::JsonValue::Field>::Builder initObject(unsigned int size); + inline void adoptObject(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> disownObject(); + + inline bool isCall(); + inline bool hasCall(); + inline ::capnp::JsonValue::Call::Builder getCall(); + inline void setCall( ::capnp::JsonValue::Call::Reader value); + inline ::capnp::JsonValue::Call::Builder initCall(); + inline void adoptCall(::capnp::Orphan< ::capnp::JsonValue::Call>&& value); + inline ::capnp::Orphan< ::capnp::JsonValue::Call> disownCall(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Pipeline { +public: + typedef JsonValue Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JsonValue::Field::Reader { +public: + typedef Field Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline bool hasValue() const; + inline ::capnp::JsonValue::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Field::Builder { +public: + typedef Field Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline bool hasValue(); + inline ::capnp::JsonValue::Builder getValue(); + inline void setValue( ::capnp::JsonValue::Reader value); + inline ::capnp::JsonValue::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::JsonValue>&& value); + inline ::capnp::Orphan< ::capnp::JsonValue> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Field::Pipeline { +public: + typedef Field Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::JsonValue::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JsonValue::Call::Reader { +public: + typedef Call Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasFunction() const; + inline ::capnp::Text::Reader getFunction() const; + + inline bool hasParams() const; + inline ::capnp::List< ::capnp::JsonValue>::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Call::Builder { +public: + typedef Call Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasFunction(); + inline ::capnp::Text::Builder getFunction(); + inline void setFunction( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initFunction(unsigned int size); + inline void adoptFunction(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownFunction(); + + inline bool hasParams(); + inline ::capnp::List< ::capnp::JsonValue>::Builder getParams(); + inline void setParams( ::capnp::List< ::capnp::JsonValue>::Reader value); + inline ::capnp::List< ::capnp::JsonValue>::Builder initParams(unsigned int size); + inline void adoptParams(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Call::Pipeline { +public: + typedef Call Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::JsonValue::Which JsonValue::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::JsonValue::Which JsonValue::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool JsonValue::Reader::isNull() const { + return which() == JsonValue::NULL_; +} +inline bool JsonValue::Builder::isNull() { + return which() == JsonValue::NULL_; +} +inline ::capnp::Void JsonValue::Reader::getNull() const { + KJ_IREQUIRE((which() == JsonValue::NULL_), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void JsonValue::Builder::getNull() { + KJ_IREQUIRE((which() == JsonValue::NULL_), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setNull( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NULL_); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isBoolean() const { + return which() == JsonValue::BOOLEAN; +} +inline bool JsonValue::Builder::isBoolean() { + return which() == JsonValue::BOOLEAN; +} +inline bool JsonValue::Reader::getBoolean() const { + KJ_IREQUIRE((which() == JsonValue::BOOLEAN), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} + +inline bool JsonValue::Builder::getBoolean() { + KJ_IREQUIRE((which() == JsonValue::BOOLEAN), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setBoolean(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::BOOLEAN); + _builder.setDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isNumber() const { + return which() == JsonValue::NUMBER; +} +inline bool JsonValue::Builder::isNumber() { + return which() == JsonValue::NUMBER; +} +inline double JsonValue::Reader::getNumber() const { + KJ_IREQUIRE((which() == JsonValue::NUMBER), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double JsonValue::Builder::getNumber() { + KJ_IREQUIRE((which() == JsonValue::NUMBER), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setNumber(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NUMBER); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isString() const { + return which() == JsonValue::STRING; +} +inline bool JsonValue::Builder::isString() { + return which() == JsonValue::STRING; +} +inline bool JsonValue::Reader::hasString() const { + if (which() != JsonValue::STRING) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasString() { + if (which() != JsonValue::STRING) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Reader::getString() const { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Builder::getString() { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setString( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Builder::initString(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptString( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Builder::disownString() { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isArray() const { + return which() == JsonValue::ARRAY; +} +inline bool JsonValue::Builder::isArray() { + return which() == JsonValue::ARRAY; +} +inline bool JsonValue::Reader::hasArray() const { + if (which() != JsonValue::ARRAY) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasArray() { + if (which() != JsonValue::ARRAY) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Reader::getArray() const { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::getArray() { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setArray( ::capnp::List< ::capnp::JsonValue>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::initArray(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptArray( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Builder::disownArray() { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isObject() const { + return which() == JsonValue::OBJECT; +} +inline bool JsonValue::Builder::isObject() { + return which() == JsonValue::OBJECT; +} +inline bool JsonValue::Reader::hasObject() const { + if (which() != JsonValue::OBJECT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasObject() { + if (which() != JsonValue::OBJECT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Reader JsonValue::Reader::getObject() const { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::getObject() { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::initObject(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptObject( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> JsonValue::Builder::disownObject() { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isCall() const { + return which() == JsonValue::CALL; +} +inline bool JsonValue::Builder::isCall() { + return which() == JsonValue::CALL; +} +inline bool JsonValue::Reader::hasCall() const { + if (which() != JsonValue::CALL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasCall() { + if (which() != JsonValue::CALL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::JsonValue::Call::Reader JsonValue::Reader::getCall() const { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::getCall() { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setCall( ::capnp::JsonValue::Call::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::initCall() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::adoptCall( + ::capnp::Orphan< ::capnp::JsonValue::Call>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::JsonValue::Call> JsonValue::Builder::disownCall() { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Field::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Field::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Field::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Field::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Field::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Field::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Field::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Field::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Field::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Field::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::JsonValue::Reader JsonValue::Field::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::JsonValue::Pipeline JsonValue::Field::Pipeline::getValue() { + return ::capnp::JsonValue::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void JsonValue::Field::Builder::setValue( ::capnp::JsonValue::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::JsonValue>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void JsonValue::Field::Builder::adoptValue( + ::capnp::Orphan< ::capnp::JsonValue>&& value) { + ::capnp::_::PointerHelpers< ::capnp::JsonValue>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::JsonValue> JsonValue::Field::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Call::Reader::hasFunction() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Call::Builder::hasFunction() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Call::Reader::getFunction() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Call::Builder::getFunction() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Call::Builder::setFunction( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Call::Builder::initFunction(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Call::Builder::adoptFunction( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Call::Builder::disownFunction() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Call::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Call::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Call::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void JsonValue::Call::Builder::setParams( ::capnp::List< ::capnp::JsonValue>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::initParams(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Call::Builder::adoptParams( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Call::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +} // namespace + +#endif // CAPNP_INCLUDED_8ef99297a43a5e34_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/compat/json.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/capnp/compat/json.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,462 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPAT_JSON_H_ +#define CAPNP_COMPAT_JSON_H_ + +#include +#include +#include + +namespace capnp { + +class JsonCodec { + // Flexible class for encoding Cap'n Proto types as JSON, and decoding JSON back to Cap'n Proto. + // + // Typical usage: + // + // JsonCodec json; + // + // // encode + // kj::String encoded = json.encode(someStructReader); + // + // // decode + // json.decode(encoded, someStructBuilder); + // + // Advanced users can do fancy things like override the way certain types or fields are + // represented in JSON by registering handlers. See the unit test for an example. + // + // Notes: + // - When encoding, all primitive fields are always encoded, even if default-valued. Pointer + // fields are only encoded if they are non-null. + // - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating + // points which cannot store a 64-bit integer without losing data. + // - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded + // as null. This matches the behavior of `JSON.stringify` in at least Firefox and Chrome. + // - Data is encoded as an array of numbers in the range [0,255]. You probably want to register + // a handler that does something better, like maybe base64 encoding, but there are a zillion + // different ways people do this. + // - Encoding/decoding capabilities and AnyPointers requires registering a Handler, since there's + // no obvious default behavior. + // - When decoding, unrecognized field names are ignored. Note: This means that JSON is NOT a + // good format for receiving input from a human. Consider `capnp eval` or the SchemaParser + // library for human input. + +public: + JsonCodec(); + ~JsonCodec() noexcept(false); + + // --------------------------------------------------------------------------- + // standard API + + void setPrettyPrint(bool enabled); + // Enable to insert newlines, indentation, and other extra spacing into the output. The default + // is to use minimal whitespace. + + void setMaxNestingDepth(size_t maxNestingDepth); + // Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing + // the call stack. The default is 64. + + template + kj::String encode(T&& value); + // Encode any Cap'n Proto value to JSON, including primitives and + // Dynamic{Enum,Struct,List,Capability}, but not DynamicValue (see below). + + kj::String encode(DynamicValue::Reader value, Type type) const; + // Encode a DynamicValue to JSON. `type` is needed because `DynamicValue` itself does + // not distinguish between e.g. int32 and int64, which in JSON are handled differently. Most + // of the time, though, you can use the single-argument templated version of `encode()` instead. + + void decode(kj::ArrayPtr input, DynamicStruct::Builder output) const; + // Decode JSON text directly into a struct builder. This only works for structs since lists + // need to be allocated with the correct size in advance. + // + // (Remember that any Cap'n Proto struct reader type can be implicitly cast to + // DynamicStruct::Reader.) + + template + Orphan decode(kj::ArrayPtr input, Orphanage orphanage) const; + // Decode JSON text to any Cap'n Proto object (pointer value), allocated using the given + // orphanage. T must be specified explicitly and cannot be dynamic, e.g.: + // + // Orphan orphan = json.decode(text, orphanage); + + template + ReaderFor decode(kj::ArrayPtr input) const; + // Decode JSON text into a primitive or capability value. T must be specified explicitly and + // cannot be dynamic, e.g.: + // + // uint32_t n = json.decode(text); + + Orphan decode(kj::ArrayPtr input, Type type, Orphanage orphanage) const; + Orphan decode( + kj::ArrayPtr input, ListSchema type, Orphanage orphanage) const; + Orphan decode( + kj::ArrayPtr input, StructSchema type, Orphanage orphanage) const; + DynamicCapability::Client decode(kj::ArrayPtr input, InterfaceSchema type) const; + DynamicEnum decode(kj::ArrayPtr input, EnumSchema type) const; + // Decode to a dynamic value, specifying the type schema. + + // --------------------------------------------------------------------------- + // layered API + // + // You can separate text <-> JsonValue from JsonValue <-> T. These are particularly useful + // for calling from Handler implementations. + + kj::String encodeRaw(JsonValue::Reader value) const; + void decodeRaw(kj::ArrayPtr input, JsonValue::Builder output) const; + // Translate JsonValue <-> text. + + template + void encode(T&& value, JsonValue::Builder output); + void encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const; + void decode(JsonValue::Reader input, DynamicStruct::Builder output) const; + template + Orphan decode(JsonValue::Reader input, Orphanage orphanage) const; + template + ReaderFor decode(JsonValue::Reader input) const; + + Orphan decode(JsonValue::Reader input, Type type, Orphanage orphanage) const; + Orphan decode(JsonValue::Reader input, ListSchema type, Orphanage orphanage) const; + Orphan decode( + JsonValue::Reader input, StructSchema type, Orphanage orphanage) const; + DynamicCapability::Client decode(JsonValue::Reader input, InterfaceSchema type) const; + DynamicEnum decode(JsonValue::Reader input, EnumSchema type) const; + + // --------------------------------------------------------------------------- + // specializing particular types + + template ()> + class Handler; + // Implement this interface to specify a special encoding for a particular type or field. + // + // The templates are a bit ugly, but subclasses of this type essentially implement two methods, + // one to encode values of this type and one to decode values of this type. `encode()` is simple: + // + // void encode(const JsonCodec& codec, ReaderFor input, JsonValue::Builder output) const; + // + // `decode()` is a bit trickier. When T is a struct (including DynamicStruct), it is: + // + // void decode(const JsonCodec& codec, JsonValue::Reader input, BuilderFor output) const; + // + // However, when T is a primitive, decode() is: + // + // T decode(const JsonCodec& codec, JsonValue::Reader input) const; + // + // Or when T is any non-struct object (list, blob), decode() is: + // + // Orphan decode(const JsonCodec& codec, JsonValue::Reader input, Orphanage orphanage) const; + // + // Or when T is an interface: + // + // T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const; + // + // Additionally, when T is a struct you can *optionally* also implement the orphan-returning form + // of decode(), but it will only be called when the struct would be allocated as an individual + // object, not as part of a list. This allows you to return "nullptr" in these cases to say that + // the pointer value should be null. This does not apply to list elements because struct list + // elements cannot ever be null (since Cap'n Proto encodes struct lists as a flat list rather + // than list-of-pointers). + + template + void addTypeHandler(Handler& handler); + void addTypeHandler(Type type, Handler& handler); + void addTypeHandler(EnumSchema type, Handler& handler); + void addTypeHandler(StructSchema type, Handler& handler); + void addTypeHandler(ListSchema type, Handler& handler); + void addTypeHandler(InterfaceSchema type, Handler& handler); + // Arrange that whenever the type T appears in the message, your handler will be used to + // encode/decode it. + // + // Note that if you register a handler for a capability type, it will also apply to subtypes. + // Thus Handler handles all capabilities. + + template + void addFieldHandler(StructSchema::Field field, Handler& handler); + // Matches only the specific field. T can be a dynamic type. T must match the field's type. + +private: + class HandlerBase; + struct Impl; + + kj::Own impl; + + void encodeField(StructSchema::Field field, DynamicValue::Reader input, + JsonValue::Builder output) const; + void decodeArray(List::Reader input, DynamicList::Builder output) const; + void decodeObject(List::Reader input, DynamicStruct::Builder output) const; + void addTypeHandlerImpl(Type type, HandlerBase& handler); + void addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler); +}; + +// ======================================================================================= +// inline implementation details + +template +kj::String JsonCodec::encode(T&& value) { + typedef FromAny> Base; + return encode(DynamicValue::Reader(ReaderFor(kj::fwd(value))), Type::from()); +} + +template +inline Orphan JsonCodec::decode(kj::ArrayPtr input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +template +inline ReaderFor JsonCodec::decode(kj::ArrayPtr input) const { + static_assert(style() == Style::PRIMITIVE || style() == Style::CAPABILITY, + "must specify an orphanage to decode an object type"); + return decode(input, Type::from(), Orphanage()).getReader().template as(); +} + +inline Orphan JsonCodec::decode( + kj::ArrayPtr input, ListSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline Orphan JsonCodec::decode( + kj::ArrayPtr input, StructSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline DynamicCapability::Client JsonCodec::decode( + kj::ArrayPtr input, InterfaceSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} +inline DynamicEnum JsonCodec::decode(kj::ArrayPtr input, EnumSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} + +// ----------------------------------------------------------------------------- + +template +void JsonCodec::encode(T&& value, JsonValue::Builder output) { + typedef FromAny> Base; + encode(DynamicValue::Reader(ReaderFor(kj::fwd(value))), Type::from(), output); +} + +template +inline Orphan JsonCodec::decode(JsonValue::Reader input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +template +inline ReaderFor JsonCodec::decode(JsonValue::Reader input) const { + static_assert(style() == Style::PRIMITIVE || style() == Style::CAPABILITY, + "must specify an orphanage to decode an object type"); + return decode(input, Type::from(), Orphanage()).getReader().template as(); +} + +inline Orphan JsonCodec::decode( + JsonValue::Reader input, ListSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline Orphan JsonCodec::decode( + JsonValue::Reader input, StructSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline DynamicCapability::Client JsonCodec::decode( + JsonValue::Reader input, InterfaceSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} +inline DynamicEnum JsonCodec::decode(JsonValue::Reader input, EnumSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} + +// ----------------------------------------------------------------------------- + +class JsonCodec::HandlerBase { + // Internal helper; ignore. +public: + virtual void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const = 0; + virtual Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const; + virtual void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, ReaderFor input, + JsonValue::Builder output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + Orphanage orphanage) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, orphanage); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, ReaderFor input, + JsonValue::Builder output) const = 0; + virtual void decode(const JsonCodec& codec, JsonValue::Reader input, + BuilderFor output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + Orphanage orphanage) const { + // If subclass does not override, fall back to regular version. + auto result = orphanage.newOrphan(); + decode(codec, input, result.get()); + return result; + } + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, orphanage); + } + void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const override final { + decode(codec, input, output.as()); + } + friend class JsonCodec; +}; + +template <> +class JsonCodec::Handler: private JsonCodec::HandlerBase { + // Almost identical to Style::STRUCT except that we pass the struct type to decode(). + +public: + virtual void encode(const JsonCodec& codec, DynamicStruct::Reader input, + JsonValue::Builder output) const = 0; + virtual void decode(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + StructSchema type, Orphanage orphanage) const { + // If subclass does not override, fall back to regular version. + auto result = orphanage.newOrphan(type); + decode(codec, input, result.get()); + return result; + } + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, type.asStruct(), orphanage); + } + void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const override final { + decode(codec, input, output.as()); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, T input, JsonValue::Builder output) const = 0; + virtual T decode(const JsonCodec& codec, JsonValue::Reader input) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, typename T::Client input, + JsonValue::Builder output) const = 0; + virtual typename T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return orphanage.newOrphanCopy(decode(codec, input)); + } + friend class JsonCodec; +}; + +template +inline void JsonCodec::addTypeHandler(Handler& handler) { + addTypeHandlerImpl(Type::from(), handler); +} +inline void JsonCodec::addTypeHandler(Type type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(EnumSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(StructSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(ListSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(InterfaceSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} + +template +inline void JsonCodec::addFieldHandler(StructSchema::Field field, Handler& handler) { + addFieldHandlerImpl(field, Type::from(), handler); +} + +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +// TODO(someday): Implement support for registering handlers that cover thinsg like "all structs" +// or "all lists". Currently you can only target a specific struct or list type. + +} // namespace capnp + +#endif // CAPNP_COMPAT_JSON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/dynamic.h --- a/osx/include/capnp/dynamic.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/dynamic.h Mon May 22 10:01:37 2017 +0100 @@ -1,1593 +1,1643 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file defines classes that can be used to manipulate messages based on schemas that are not -// known until runtime. This is also useful for writing generic code that uses schemas to handle -// arbitrary types in a generic way. -// -// Each of the classes defined here has a to() template method which converts an instance back to a -// native type. This method will throw an exception if the requested type does not match the -// schema. To convert native types to dynamic, use DynamicFactory. -// -// As always, underlying data is validated lazily, so you have to actually traverse the whole -// message if you want to validate all content. - -#ifndef CAPNP_DYNAMIC_H_ -#define CAPNP_DYNAMIC_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "schema.h" -#include "layout.h" -#include "message.h" -#include "any.h" -#include "capability.h" - -namespace capnp { - -class MessageReader; -class MessageBuilder; - -struct DynamicValue { - DynamicValue() = delete; - - enum Type { - UNKNOWN, - // Means that the value has unknown type and content because it comes from a newer version of - // the schema, or from a newer version of Cap'n Proto that has new features that this version - // doesn't understand. - - VOID, - BOOL, - INT, - UINT, - FLOAT, - TEXT, - DATA, - LIST, - ENUM, - STRUCT, - CAPABILITY, - ANY_POINTER - }; - - class Reader; - class Builder; - class Pipeline; -}; -class DynamicEnum; -struct DynamicStruct { - DynamicStruct() = delete; - class Reader; - class Builder; - class Pipeline; -}; -struct DynamicList { - DynamicList() = delete; - class Reader; - class Builder; -}; -struct DynamicCapability { - DynamicCapability() = delete; - class Client; - class Server; -}; -template <> class Orphan; - -template struct DynamicTypeFor_; -template <> struct DynamicTypeFor_ { typedef DynamicEnum Type; }; -template <> struct DynamicTypeFor_ { typedef DynamicStruct Type; }; -template <> struct DynamicTypeFor_ { typedef DynamicList Type; }; -template <> struct DynamicTypeFor_ { typedef DynamicCapability Type; }; - -template -using DynamicTypeFor = typename DynamicTypeFor_()>::Type; - -template -ReaderFor>> toDynamic(T&& value); -template -BuilderFor>> toDynamic(T&& value); -template -DynamicTypeFor> toDynamic(T&& value); -template -typename DynamicTypeFor>::Client toDynamic(kj::Own&& value); - -namespace _ { // private - -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; - -} // namespace _ (private) - -template <> inline constexpr Style style() { return Style::POINTER; } -template <> inline constexpr Style style() { return Style::PRIMITIVE; } -template <> inline constexpr Style style() { return Style::STRUCT; } -template <> inline constexpr Style style() { return Style::POINTER; } -template <> inline constexpr Style style() { return Style::CAPABILITY; } - -// ------------------------------------------------------------------- - -class DynamicEnum { -public: - DynamicEnum() = default; - inline DynamicEnum(EnumSchema::Enumerant enumerant) - : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {} - inline DynamicEnum(EnumSchema schema, uint16_t value) - : schema(schema), value(value) {} - - template () == Kind::ENUM>> - inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} - - template - inline T as() const { return static_cast(asImpl(typeId())); } - // Cast to a native enum type. - - inline EnumSchema getSchema() const { return schema; } - - kj::Maybe getEnumerant() const; - // Get which enumerant this enum value represents. Returns nullptr if the numeric value does not - // correspond to any enumerant in the schema -- this can happen if the data was built using a - // newer schema that has more values defined. - - inline uint16_t getRaw() const { return value; } - // Returns the raw underlying enum value. - -private: - EnumSchema schema; - uint16_t value; - - uint16_t asImpl(uint64_t requestedTypeId) const; - - friend struct DynamicStruct; - friend struct DynamicList; - friend struct DynamicValue; - template - friend DynamicTypeFor> toDynamic(T&& value); -}; - -// ------------------------------------------------------------------- - -class DynamicStruct::Reader { -public: - typedef DynamicStruct Reads; - - Reader() = default; - - template >() == Kind::STRUCT>> - inline Reader(T&& value): Reader(toDynamic(value)) {} - - inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } - - template - typename T::Reader as() const; - // Convert the dynamic struct to its compiled-in type. - - inline StructSchema getSchema() const { return schema; } - - DynamicValue::Reader get(StructSchema::Field field) const; - // Read the given field value. - - bool has(StructSchema::Field field) const; - // Tests whether the given field is set to its default value. For pointer values, this does - // not actually traverse the value comparing it with the default, but simply returns true if the - // pointer is non-null. For members of unions, has() returns false if the union member is not - // active, but does not necessarily return true if the member is active (depends on the field's - // value). - - kj::Maybe which() const; - // If the struct contains an (unnamed) union, and the currently-active field within that union - // is known, this returns that field. Otherwise, it returns null. In other words, this returns - // null if there is no union present _or_ if the union's discriminant is set to an unrecognized - // value. This could happen in particular when receiving a message from a sender who has a - // newer version of the protocol and is using a field of the union that you don't know about yet. - - DynamicValue::Reader get(kj::StringPtr name) const; - bool has(kj::StringPtr name) const; - // Shortcuts to access fields by name. These throw exceptions if no such field exists. - -private: - StructSchema schema; - _::StructReader reader; - - inline Reader(StructSchema schema, _::StructReader reader) - : schema(schema), reader(reader) {} - - bool isSetInUnion(StructSchema::Field field) const; - void verifySetInUnion(StructSchema::Field field) const; - static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field); - - template - friend struct _::PointerHelpers; - friend class DynamicStruct::Builder; - friend struct DynamicList; - friend class MessageReader; - friend class MessageBuilder; - template - friend struct ::capnp::ToDynamic_; - friend kj::StringTree _::structString( - _::StructReader reader, const _::RawBrandedSchema& schema); - friend class Orphanage; - friend class Orphan; - friend class Orphan; - friend class Orphan; -}; - -class DynamicStruct::Builder { -public: - typedef DynamicStruct Builds; - - Builder() = default; - inline Builder(decltype(nullptr)) {} - - template >() == Kind::STRUCT>> - inline Builder(T&& value): Builder(toDynamic(value)) {} - - inline MessageSize totalSize() const { return asReader().totalSize(); } - - template - typename T::Builder as(); - // Cast to a particular struct type. - - inline StructSchema getSchema() const { return schema; } - - DynamicValue::Builder get(StructSchema::Field field); - // Read the given field value. - - inline bool has(StructSchema::Field field) { return asReader().has(field); } - // Tests whether the given field is set to its default value. For pointer values, this does - // not actually traverse the value comparing it with the default, but simply returns true if the - // pointer is non-null. For members of unions, has() returns whether the field is currently - // active and the union as a whole is non-default -- so, the only time has() will return false - // for an active union field is if it is the default active field and it has its default value. - - kj::Maybe which(); - // If the struct contains an (unnamed) union, and the currently-active field within that union - // is known, this returns that field. Otherwise, it returns null. In other words, this returns - // null if there is no union present _or_ if the union's discriminant is set to an unrecognized - // value. This could happen in particular when receiving a message from a sender who has a - // newer version of the protocol and is using a field of the union that you don't know about yet. - - void set(StructSchema::Field field, const DynamicValue::Reader& value); - // Set the given field value. - - DynamicValue::Builder init(StructSchema::Field field); - DynamicValue::Builder init(StructSchema::Field field, uint size); - // Init a struct, list, or blob field. - - void adopt(StructSchema::Field field, Orphan&& orphan); - Orphan disown(StructSchema::Field field); - // Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set() - // and disown() becomes like get() followed by clear(). - - void clear(StructSchema::Field field); - // Clear a field, setting it to its default value. For pointer fields, this actually makes the - // field null. - - DynamicValue::Builder get(kj::StringPtr name); - bool has(kj::StringPtr name); - void set(kj::StringPtr name, const DynamicValue::Reader& value); - void set(kj::StringPtr name, std::initializer_list value); - DynamicValue::Builder init(kj::StringPtr name); - DynamicValue::Builder init(kj::StringPtr name, uint size); - void adopt(kj::StringPtr name, Orphan&& orphan); - Orphan disown(kj::StringPtr name); - void clear(kj::StringPtr name); - // Shortcuts to access fields by name. These throw exceptions if no such field exists. - - Reader asReader() const; - -private: - StructSchema schema; - _::StructBuilder builder; - - inline Builder(StructSchema schema, _::StructBuilder builder) - : schema(schema), builder(builder) {} - - bool isSetInUnion(StructSchema::Field field); - void verifySetInUnion(StructSchema::Field field); - void setInUnion(StructSchema::Field field); - - template - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class MessageReader; - friend class MessageBuilder; - template - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - friend class Orphan; - friend class Orphan; - friend class Orphan; -}; - -class DynamicStruct::Pipeline { -public: - typedef DynamicStruct Pipelines; - - inline Pipeline(decltype(nullptr)): typeless(nullptr) {} - - template - typename T::Pipeline releaseAs(); - // Convert the dynamic pipeline to its compiled-in type. - - inline StructSchema getSchema() { return schema; } - - DynamicValue::Pipeline get(StructSchema::Field field); - // Read the given field value. - - DynamicValue::Pipeline get(kj::StringPtr name); - // Get by string name. - -private: - StructSchema schema; - AnyPointer::Pipeline typeless; - - inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless) - : schema(schema), typeless(kj::mv(typeless)) {} - - friend class Request; -}; - -// ------------------------------------------------------------------- - -class DynamicList::Reader { -public: - typedef DynamicList Reads; - - inline Reader(): reader(ElementSize::VOID) {} - - template >() == Kind::LIST>> - inline Reader(T&& value): Reader(toDynamic(value)) {} - - template - typename T::Reader as() const; - // Try to convert to any List, Data, or Text. Throws an exception if the underlying data - // can't possibly represent the requested type. - - inline ListSchema getSchema() const { return schema; } - - inline uint size() const { return reader.size() / ELEMENTS; } - DynamicValue::Reader operator[](uint index) const; - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - ListSchema schema; - _::ListReader reader; - - Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicStruct; - friend class DynamicList::Builder; - template - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - friend class Orphan; - friend class Orphan; - friend class Orphan; -}; - -class DynamicList::Builder { -public: - typedef DynamicList Builds; - - inline Builder(): builder(ElementSize::VOID) {} - inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} - - template >() == Kind::LIST>> - inline Builder(T&& value): Builder(toDynamic(value)) {} - - template - typename T::Builder as(); - // Try to convert to any List, Data, or Text. Throws an exception if the underlying data - // can't possibly represent the requested type. - - inline ListSchema getSchema() const { return schema; } - - inline uint size() const { return builder.size() / ELEMENTS; } - DynamicValue::Builder operator[](uint index); - void set(uint index, const DynamicValue::Reader& value); - DynamicValue::Builder init(uint index, uint size); - void adopt(uint index, Orphan&& orphan); - Orphan disown(uint index); - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - void copyFrom(std::initializer_list value); - - Reader asReader() const; - -private: - ListSchema schema; - _::ListBuilder builder; - - Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicStruct; - template - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - template - friend struct _::OrphanGetImpl; - friend class Orphan; - friend class Orphan; - friend class Orphan; -}; - -// ------------------------------------------------------------------- - -class DynamicCapability::Client: public Capability::Client { -public: - typedef DynamicCapability Calls; - typedef DynamicCapability Reads; - - Client() = default; - - template >() == Kind::INTERFACE>> - inline Client(T&& client); - - template ()>> - inline Client(kj::Own&& server); - - template () == Kind::INTERFACE>> - typename T::Client as(); - template () == Kind::INTERFACE>> - typename T::Client releaseAs(); - // Convert to any client type. - - Client upcast(InterfaceSchema requestedSchema); - // Upcast to a superclass. Throws an exception if `schema` is not a superclass. - - inline InterfaceSchema getSchema() { return schema; } - - Request newRequest( - InterfaceSchema::Method method, kj::Maybe sizeHint = nullptr); - Request newRequest( - kj::StringPtr methodName, kj::Maybe sizeHint = nullptr); - -private: - InterfaceSchema schema; - - Client(InterfaceSchema schema, kj::Own&& hook) - : Capability::Client(kj::mv(hook)), schema(schema) {} - - template - inline Client(InterfaceSchema schema, kj::Own&& server); - - friend struct Capability; - friend struct DynamicStruct; - friend struct DynamicList; - friend struct DynamicValue; - friend class Orphan; - friend class Orphan; - friend class Orphan; - template - friend struct _::PointerHelpers; -}; - -class DynamicCapability::Server: public Capability::Server { -public: - typedef DynamicCapability Serves; - - Server(InterfaceSchema schema): schema(schema) {} - - virtual kj::Promise call(InterfaceSchema::Method method, - CallContext context) = 0; - - kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, - CallContext context) override final; - - inline InterfaceSchema getSchema() const { return schema; } - -private: - InterfaceSchema schema; -}; - -template <> -class Request: public DynamicStruct::Builder { - // Specialization of `Request` for DynamicStruct. - -public: - inline Request(DynamicStruct::Builder builder, kj::Own&& hook, - StructSchema resultSchema) - : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} - - RemotePromise send(); - // Send the call and return a promise for the results. - -private: - kj::Own hook; - StructSchema resultSchema; - - friend class Capability::Client; - friend struct DynamicCapability; - template - friend class CallContext; - friend class RequestHook; -}; - -template <> -class CallContext: public kj::DisallowConstCopy { - // Wrapper around CallContextHook with a specific return type. - // - // Methods of this class may only be called from within the server's event loop, not from other - // threads. - -public: - explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType); - - DynamicStruct::Reader getParams(); - void releaseParams(); - DynamicStruct::Builder getResults(kj::Maybe sizeHint = nullptr); - DynamicStruct::Builder initResults(kj::Maybe sizeHint = nullptr); - void setResults(DynamicStruct::Reader value); - void adoptResults(Orphan&& value); - Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); - template - kj::Promise tailCall(Request&& tailRequest); - void allowCancellation(); - -private: - CallContextHook* hook; - StructSchema paramType; - StructSchema resultType; - - friend class DynamicCapability::Server; -}; - -// ------------------------------------------------------------------- - -// Make sure ReaderFor and BuilderFor work for DynamicEnum, DynamicStruct, and -// DynamicList, so that we can define DynamicValue::as(). - -template <> struct ReaderFor_ { typedef DynamicEnum Type; }; -template <> struct BuilderFor_ { typedef DynamicEnum Type; }; -template <> struct ReaderFor_ { typedef DynamicStruct::Reader Type; }; -template <> struct BuilderFor_ { typedef DynamicStruct::Builder Type; }; -template <> struct ReaderFor_ { typedef DynamicList::Reader Type; }; -template <> struct BuilderFor_ { typedef DynamicList::Builder Type; }; -template <> struct ReaderFor_ { typedef DynamicCapability::Client Type; }; -template <> struct BuilderFor_ { typedef DynamicCapability::Client Type; }; -template <> struct PipelineFor_ { typedef DynamicCapability::Client Type; }; - -class DynamicValue::Reader { -public: - typedef DynamicValue Reads; - - inline Reader(decltype(nullptr) n = nullptr); // UNKNOWN - inline Reader(Void value); - inline Reader(bool value); - inline Reader(char value); - inline Reader(signed char value); - inline Reader(short value); - inline Reader(int value); - inline Reader(long value); - inline Reader(long long value); - inline Reader(unsigned char value); - inline Reader(unsigned short value); - inline Reader(unsigned int value); - inline Reader(unsigned long value); - inline Reader(unsigned long long value); - inline Reader(float value); - inline Reader(double value); - inline Reader(const char* value); // Text - inline Reader(const Text::Reader& value); - inline Reader(const Data::Reader& value); - inline Reader(const DynamicList::Reader& value); - inline Reader(DynamicEnum value); - inline Reader(const DynamicStruct::Reader& value); - inline Reader(const AnyPointer::Reader& value); - inline Reader(DynamicCapability::Client& value); - inline Reader(DynamicCapability::Client&& value); - template ()>> - inline Reader(kj::Own&& value); - Reader(ConstSchema constant); - - template ()))> - inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {} - - Reader(const Reader& other); - Reader(Reader&& other) noexcept; - ~Reader() noexcept(false); - Reader& operator=(const Reader& other); - Reader& operator=(Reader&& other); - // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not - // trivially copyable. - - template - inline ReaderFor as() const { return AsImpl::apply(*this); } - // Use to interpret the value as some Cap'n Proto type. Allowed types are: - // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value. - // - Text, Data, AnyPointer, any struct type: Returns the corresponding Reader. - // - List for any T listed above: Returns List::Reader. - // - DynamicEnum: Returns the corresponding type. - // - DynamicStruct, DynamicList: Returns the corresponding Reader. - // - Any capability type, including DynamicCapability: Returns the corresponding Client. - // (TODO(perf): On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids - // refcounting.) - // - // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier. - // - Any integer can be converted to any other integer type so long as the actual value is within - // the new type's range. - // - Floating-point types can be converted to integers as long as no information would be lost - // in the conversion. - // - Integers can be converted to floating points. This may lose information, but won't throw. - // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose - // information, but won't throw. - // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not - // vice-versa). - // - Capabilities can be upcast (cast to a supertype), but not downcast. - // - // Any other conversion attempt will throw an exception. - - inline Type getType() const { return type; } - // Get the type of this value. - -private: - Type type; - - union { - Void voidValue; - bool boolValue; - int64_t intValue; - uint64_t uintValue; - double floatValue; - Text::Reader textValue; - Data::Reader dataValue; - DynamicList::Reader listValue; - DynamicEnum enumValue; - DynamicStruct::Reader structValue; - AnyPointer::Reader anyPointerValue; - - mutable DynamicCapability::Client capabilityValue; - // Declared mutable because `Client`s normally cannot be const. - - // Warning: Copy/move constructors assume all these types are trivially copyable except - // Capability. - }; - - template ()> struct AsImpl; - // Implementation backing the as() method. Needs to be a struct to allow partial - // specialization. Has a method apply() which does the work. - - friend class Orphanage; // to speed up newOrphanCopy(DynamicValue::Reader) -}; - -class DynamicValue::Builder { -public: - typedef DynamicValue Builds; - - inline Builder(decltype(nullptr) n = nullptr); // UNKNOWN - inline Builder(Void value); - inline Builder(bool value); - inline Builder(char value); - inline Builder(signed char value); - inline Builder(short value); - inline Builder(int value); - inline Builder(long value); - inline Builder(long long value); - inline Builder(unsigned char value); - inline Builder(unsigned short value); - inline Builder(unsigned int value); - inline Builder(unsigned long value); - inline Builder(unsigned long long value); - inline Builder(float value); - inline Builder(double value); - inline Builder(Text::Builder value); - inline Builder(Data::Builder value); - inline Builder(DynamicList::Builder value); - inline Builder(DynamicEnum value); - inline Builder(DynamicStruct::Builder value); - inline Builder(AnyPointer::Builder value); - inline Builder(DynamicCapability::Client& value); - inline Builder(DynamicCapability::Client&& value); - - template ()))> - inline Builder(T value): Builder(toDynamic(value)) {} - - Builder(Builder& other); - Builder(Builder&& other) noexcept; - ~Builder() noexcept(false); - Builder& operator=(Builder& other); - Builder& operator=(Builder&& other); - // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not - // trivially copyable. - - template - inline BuilderFor as() { return AsImpl::apply(*this); } - // See DynamicValue::Reader::as(). - - inline Type getType() { return type; } - // Get the type of this value. - - Reader asReader() const; - -private: - Type type; - - union { - Void voidValue; - bool boolValue; - int64_t intValue; - uint64_t uintValue; - double floatValue; - Text::Builder textValue; - Data::Builder dataValue; - DynamicList::Builder listValue; - DynamicEnum enumValue; - DynamicStruct::Builder structValue; - AnyPointer::Builder anyPointerValue; - - mutable DynamicCapability::Client capabilityValue; - // Declared mutable because `Client`s normally cannot be const. - }; - - template ()> struct AsImpl; - // Implementation backing the as() method. Needs to be a struct to allow partial - // specialization. Has a method apply() which does the work. - - friend class Orphan; -}; - -class DynamicValue::Pipeline { -public: - typedef DynamicValue Pipelines; - - inline Pipeline(decltype(nullptr) n = nullptr); - inline Pipeline(DynamicStruct::Pipeline&& value); - inline Pipeline(DynamicCapability::Client&& value); - - Pipeline(Pipeline&& other) noexcept; - Pipeline& operator=(Pipeline&& other); - ~Pipeline() noexcept(false); - - template - inline PipelineFor releaseAs() { return AsImpl::apply(*this); } - - inline Type getType() { return type; } - // Get the type of this value. - -private: - Type type; - union { - DynamicStruct::Pipeline structValue; - DynamicCapability::Client capabilityValue; - }; - - template ()> struct AsImpl; - // Implementation backing the releaseAs() method. Needs to be a struct to allow partial - // specialization. Has a method apply() which does the work. -}; - -kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value); -kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value); -kj::StringTree KJ_STRINGIFY(DynamicEnum value); -kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value); -kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value); -kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value); -kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value); - -// ------------------------------------------------------------------- -// Orphan <-> Dynamic glue - -template <> -class Orphan { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template () == Kind::STRUCT>> - inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} - - DynamicStruct::Builder get(); - DynamicStruct::Reader getReader() const; - - template - Orphan releaseAs(); - // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan is no longer valid after this call; ownership is - // transferred to the returned Orphan. - - inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } - -private: - StructSchema schema; - _::OrphanBuilder builder; - - inline Orphan(StructSchema schema, _::OrphanBuilder&& builder) - : schema(schema), builder(kj::mv(builder)) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan; - friend class Orphan; - friend class MessageBuilder; -}; - -template <> -class Orphan { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template () == Kind::LIST>> - inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} - - DynamicList::Builder get(); - DynamicList::Reader getReader() const; - - template - Orphan releaseAs(); - // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan is no longer valid after this call; ownership is - // transferred to the returned Orphan. - - // TODO(someday): Support truncate(). - - inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } - -private: - ListSchema schema; - _::OrphanBuilder builder; - - inline Orphan(ListSchema schema, _::OrphanBuilder&& builder) - : schema(schema), builder(kj::mv(builder)) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan; - friend class Orphan; -}; - -template <> -class Orphan { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template () == Kind::INTERFACE>> - inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} - - DynamicCapability::Client get(); - DynamicCapability::Client getReader() const; - - template - Orphan releaseAs(); - // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan is no longer valid after this call; ownership is - // transferred to the returned Orphan. - - inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } - -private: - InterfaceSchema schema; - _::OrphanBuilder builder; - - inline Orphan(InterfaceSchema schema, _::OrphanBuilder&& builder) - : schema(schema), builder(kj::mv(builder)) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan; - friend class Orphan; -}; - -template <> -class Orphan { -public: - inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {} - inline Orphan(Void value); - inline Orphan(bool value); - inline Orphan(char value); - inline Orphan(signed char value); - inline Orphan(short value); - inline Orphan(int value); - inline Orphan(long value); - inline Orphan(long long value); - inline Orphan(unsigned char value); - inline Orphan(unsigned short value); - inline Orphan(unsigned int value); - inline Orphan(unsigned long value); - inline Orphan(unsigned long long value); - inline Orphan(float value); - inline Orphan(double value); - inline Orphan(DynamicEnum value); - Orphan(Orphan&&) = default; - template - Orphan(Orphan&&); - Orphan(Orphan&&); - Orphan(void*) = delete; // So Orphan(bool) doesn't accept pointers. - KJ_DISALLOW_COPY(Orphan); - - Orphan& operator=(Orphan&&) = default; - - inline DynamicValue::Type getType() { return type; } - - DynamicValue::Builder get(); - DynamicValue::Reader getReader() const; - - template - Orphan releaseAs(); - // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan is no longer valid after this call; ownership is - // transferred to the returned Orphan. - -private: - DynamicValue::Type type; - union { - Void voidValue; - bool boolValue; - int64_t intValue; - uint64_t uintValue; - double floatValue; - DynamicEnum enumValue; - StructSchema structSchema; - ListSchema listSchema; - InterfaceSchema interfaceSchema; - }; - - _::OrphanBuilder builder; - // Only used if `type` is a pointer type. - - Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder); - Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder) - : type(type), builder(kj::mv(builder)) {} - Orphan(StructSchema structSchema, _::OrphanBuilder&& builder) - : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {} - Orphan(ListSchema listSchema, _::OrphanBuilder&& builder) - : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {} - - template - friend struct _::PointerHelpers; - friend struct DynamicStruct; - friend struct DynamicList; - friend struct AnyPointer; - friend class Orphanage; -}; - -template -inline Orphan::Orphan(Orphan&& other) - : Orphan(other.get(), kj::mv(other.builder)) {} - -inline Orphan::Orphan(Orphan&& other) - : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} - -template -Orphan Orphan::releaseAs() { - get().as(); // type check - return Orphan(kj::mv(builder)); -} - -template -Orphan Orphan::releaseAs() { - get().as(); // type check - return Orphan(kj::mv(builder)); -} - -template -Orphan Orphan::releaseAs() { - get().as(); // type check - return Orphan(kj::mv(builder)); -} - -template -Orphan Orphan::releaseAs() { - get().as(); // type check - type = DynamicValue::UNKNOWN; - return Orphan(kj::mv(builder)); -} - -template <> -Orphan Orphan::releaseAs(); -template <> -Orphan Orphan::releaseAs(); -template <> -Orphan Orphan::releaseAs(); -template <> -Orphan Orphan::releaseAs(); - -template <> -struct Orphanage::GetInnerBuilder { - static inline _::StructBuilder apply(DynamicStruct::Builder& t) { - return t.builder; - } -}; - -template <> -struct Orphanage::GetInnerBuilder { - static inline _::ListBuilder apply(DynamicList::Builder& t) { - return t.builder; - } -}; - -template <> -inline Orphan Orphanage::newOrphanCopy( - DynamicStruct::Reader copyFrom) const { - return Orphan( - copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); -} - -template <> -inline Orphan Orphanage::newOrphanCopy( - DynamicList::Reader copyFrom) const { - return Orphan(copyFrom.getSchema(), - _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); -} - -template <> -inline Orphan Orphanage::newOrphanCopy( - DynamicCapability::Client copyFrom) const { - return Orphan( - copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); -} - -template <> -Orphan Orphanage::newOrphanCopy( - DynamicValue::Reader copyFrom) const; - -namespace _ { // private - -template <> -struct PointerHelpers { - // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for - // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we - // don't want people to accidentally be able to provide their own default value. - static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema); - static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema); - static void set(PointerBuilder builder, const DynamicStruct::Reader& value); - static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema); - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder, StructSchema schema) { - return Orphan(schema, builder.disown()); - } -}; - -template <> -struct PointerHelpers { - // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for - // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we - // don't want people to accidentally be able to provide their own default value. - static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema); - static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema); - static void set(PointerBuilder builder, const DynamicList::Reader& value); - static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size); - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder, ListSchema schema) { - return Orphan(schema, builder.disown()); - } -}; - -template <> -struct PointerHelpers { - // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for - // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we - // don't want people to accidentally be able to provide their own default value. - static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema); - static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema); - static void set(PointerBuilder builder, DynamicCapability::Client& value); - static void set(PointerBuilder builder, DynamicCapability::Client&& value); - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder, InterfaceSchema schema) { - return Orphan(schema, builder.disown()); - } -}; - -} // namespace _ (private) - -template -inline ReaderFor AnyPointer::Reader::getAs(StructSchema schema) const { - return _::PointerHelpers::getDynamic(reader, schema); -} -template -inline ReaderFor AnyPointer::Reader::getAs(ListSchema schema) const { - return _::PointerHelpers::getDynamic(reader, schema); -} -template -inline ReaderFor AnyPointer::Reader::getAs(InterfaceSchema schema) const { - return _::PointerHelpers::getDynamic(reader, schema); -} -template -inline BuilderFor AnyPointer::Builder::getAs(StructSchema schema) { - return _::PointerHelpers::getDynamic(builder, schema); -} -template -inline BuilderFor AnyPointer::Builder::getAs(ListSchema schema) { - return _::PointerHelpers::getDynamic(builder, schema); -} -template -inline BuilderFor AnyPointer::Builder::getAs(InterfaceSchema schema) { - return _::PointerHelpers::getDynamic(builder, schema); -} -template -inline BuilderFor AnyPointer::Builder::initAs(StructSchema schema) { - return _::PointerHelpers::init(builder, schema); -} -template -inline BuilderFor AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { - return _::PointerHelpers::init(builder, schema, elementCount); -} -template <> -inline void AnyPointer::Builder::setAs(DynamicStruct::Reader value) { - return _::PointerHelpers::set(builder, value); -} -template <> -inline void AnyPointer::Builder::setAs(DynamicList::Reader value) { - return _::PointerHelpers::set(builder, value); -} -template <> -inline void AnyPointer::Builder::setAs(DynamicCapability::Client value) { - return _::PointerHelpers::set(builder, kj::mv(value)); -} -template <> -void AnyPointer::Builder::adopt(Orphan&& orphan); -template -inline Orphan AnyPointer::Builder::disownAs(StructSchema schema) { - return _::PointerHelpers::disown(builder, schema); -} -template -inline Orphan AnyPointer::Builder::disownAs(ListSchema schema) { - return _::PointerHelpers::disown(builder, schema); -} -template -inline Orphan AnyPointer::Builder::disownAs(InterfaceSchema schema) { - return _::PointerHelpers::disown(builder, schema); -} - -template <> -DynamicStruct::Builder Orphan::getAs(StructSchema schema); -template <> -DynamicList::Builder Orphan::getAs(ListSchema schema); -template <> -DynamicCapability::Client Orphan::getAs(InterfaceSchema schema); -template <> -DynamicStruct::Reader Orphan::getAsReader(StructSchema schema) const; -template <> -DynamicList::Reader Orphan::getAsReader(ListSchema schema) const; -template <> -DynamicCapability::Client Orphan::getAsReader( - InterfaceSchema schema) const; -template <> -Orphan Orphan::releaseAs(StructSchema schema); -template <> -Orphan Orphan::releaseAs(ListSchema schema); -template <> -Orphan Orphan::releaseAs( - InterfaceSchema schema); - -// ======================================================================================= -// Inline implementation details. - -template -struct ToDynamic_ { - static inline DynamicStruct::Reader apply(const typename T::Reader& value) { - return DynamicStruct::Reader(Schema::from(), value._reader); - } - static inline DynamicStruct::Builder apply(typename T::Builder& value) { - return DynamicStruct::Builder(Schema::from(), value._builder); - } -}; - -template -struct ToDynamic_ { - static inline DynamicList::Reader apply(const typename T::Reader& value) { - return DynamicList::Reader(Schema::from(), value.reader); - } - static inline DynamicList::Builder apply(typename T::Builder& value) { - return DynamicList::Builder(Schema::from(), value.builder); - } -}; - -template -struct ToDynamic_ { - static inline DynamicCapability::Client apply(typename T::Client value) { - return DynamicCapability::Client(kj::mv(value)); - } - static inline DynamicCapability::Client apply(typename T::Client&& value) { - return DynamicCapability::Client(kj::mv(value)); - } -}; - -template -ReaderFor>> toDynamic(T&& value) { - return ToDynamic_>::apply(value); -} -template -BuilderFor>> toDynamic(T&& value) { - return ToDynamic_>::apply(value); -} -template -DynamicTypeFor> toDynamic(T&& value) { - return DynamicEnum(Schema::from>(), static_cast(value)); -} -template -typename DynamicTypeFor>::Client toDynamic(kj::Own&& value) { - return typename FromServer::Client(kj::mv(value)); -} - -inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {} -inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {} - -#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ -inline DynamicValue::Reader::Reader(cppType value) \ - : type(typeTag), fieldName##Value(value) {} \ -inline DynamicValue::Builder::Builder(cppType value) \ - : type(typeTag), fieldName##Value(value) {} \ -inline Orphan::Orphan(cppType value) \ - : type(DynamicValue::typeTag), fieldName##Value(value) {} - -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum); -#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR - -#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ -inline DynamicValue::Reader::Reader(const cppType::Reader& value) \ - : type(typeTag), fieldName##Value(value) {} \ -inline DynamicValue::Builder::Builder(cppType::Builder value) \ - : type(typeTag), fieldName##Value(value) {} - -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct); -CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer); - -#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR - -inline DynamicValue::Reader::Reader(DynamicCapability::Client& value) - : type(CAPABILITY), capabilityValue(value) {} -inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value) - : type(CAPABILITY), capabilityValue(kj::mv(value)) {} -template -inline DynamicValue::Reader::Reader(kj::Own&& value) - : type(CAPABILITY), capabilityValue(kj::mv(value)) {} -inline DynamicValue::Builder::Builder(DynamicCapability::Client& value) - : type(CAPABILITY), capabilityValue(value) {} -inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value) - : type(CAPABILITY), capabilityValue(kj::mv(value)) {} - -inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {} - -#define CAPNP_DECLARE_TYPE(discrim, typeName) \ -template <> \ -struct DynamicValue::Reader::AsImpl { \ - static ReaderFor apply(const Reader& reader); \ -}; \ -template <> \ -struct DynamicValue::Builder::AsImpl { \ - static BuilderFor apply(Builder& builder); \ -}; - -//CAPNP_DECLARE_TYPE(VOID, Void) -CAPNP_DECLARE_TYPE(BOOL, bool) -CAPNP_DECLARE_TYPE(INT8, int8_t) -CAPNP_DECLARE_TYPE(INT16, int16_t) -CAPNP_DECLARE_TYPE(INT32, int32_t) -CAPNP_DECLARE_TYPE(INT64, int64_t) -CAPNP_DECLARE_TYPE(UINT8, uint8_t) -CAPNP_DECLARE_TYPE(UINT16, uint16_t) -CAPNP_DECLARE_TYPE(UINT32, uint32_t) -CAPNP_DECLARE_TYPE(UINT64, uint64_t) -CAPNP_DECLARE_TYPE(FLOAT32, float) -CAPNP_DECLARE_TYPE(FLOAT64, double) - -CAPNP_DECLARE_TYPE(TEXT, Text) -CAPNP_DECLARE_TYPE(DATA, Data) -CAPNP_DECLARE_TYPE(LIST, DynamicList) -CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct) -CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability) -CAPNP_DECLARE_TYPE(ENUM, DynamicEnum) -CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer) -#undef CAPNP_DECLARE_TYPE - -// CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the -// ReaderFor<> and BuilderFor<> wrappers, it works. -template <> -struct DynamicValue::Reader::AsImpl { - static Void apply(const Reader& reader); -}; -template <> -struct DynamicValue::Builder::AsImpl { - static Void apply(Builder& builder); -}; - -template -struct DynamicValue::Reader::AsImpl { - static T apply(const Reader& reader) { - return reader.as().as(); - } -}; -template -struct DynamicValue::Builder::AsImpl { - static T apply(Builder& builder) { - return builder.as().as(); - } -}; - -template -struct DynamicValue::Reader::AsImpl { - static typename T::Reader apply(const Reader& reader) { - return reader.as().as(); - } -}; -template -struct DynamicValue::Builder::AsImpl { - static typename T::Builder apply(Builder& builder) { - return builder.as().as(); - } -}; - -template -struct DynamicValue::Reader::AsImpl { - static typename T::Reader apply(const Reader& reader) { - return reader.as().as(); - } -}; -template -struct DynamicValue::Builder::AsImpl { - static typename T::Builder apply(Builder& builder) { - return builder.as().as(); - } -}; - -template -struct DynamicValue::Reader::AsImpl { - static typename T::Client apply(const Reader& reader) { - return reader.as().as(); - } -}; -template -struct DynamicValue::Builder::AsImpl { - static typename T::Client apply(Builder& builder) { - return builder.as().as(); - } -}; - -inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {} -inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value) - : type(STRUCT), structValue(kj::mv(value)) {} -inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value) - : type(CAPABILITY), capabilityValue(kj::mv(value)) {} - -template -struct DynamicValue::Pipeline::AsImpl { - static typename T::Pipeline apply(Pipeline& pipeline) { - return pipeline.releaseAs().releaseAs(); - } -}; -template -struct DynamicValue::Pipeline::AsImpl { - static typename T::Client apply(Pipeline& pipeline) { - return pipeline.releaseAs().releaseAs(); - } -}; -template <> -struct DynamicValue::Pipeline::AsImpl { - static PipelineFor apply(Pipeline& pipeline); -}; -template <> -struct DynamicValue::Pipeline::AsImpl { - static PipelineFor apply(Pipeline& pipeline); -}; - -// ------------------------------------------------------------------- - -template -typename T::Reader DynamicStruct::Reader::as() const { - static_assert(kind() == Kind::STRUCT, - "DynamicStruct::Reader::as() can only convert to struct types."); - schema.requireUsableAs(); - return typename T::Reader(reader); -} - -template -typename T::Builder DynamicStruct::Builder::as() { - static_assert(kind() == Kind::STRUCT, - "DynamicStruct::Builder::as() can only convert to struct types."); - schema.requireUsableAs(); - return typename T::Builder(builder); -} - -template <> -inline DynamicStruct::Reader DynamicStruct::Reader::as() const { - return *this; -} -template <> -inline DynamicStruct::Builder DynamicStruct::Builder::as() { - return *this; -} - -inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { - return DynamicStruct::Reader(schema, builder.asReader()); -} - -template <> -inline AnyStruct::Reader DynamicStruct::Reader::as() const { - return AnyStruct::Reader(reader); -} - -template <> -inline AnyStruct::Builder DynamicStruct::Builder::as() { - return AnyStruct::Builder(builder); -} - -template -typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { - static_assert(kind() == Kind::STRUCT, - "DynamicStruct::Pipeline::releaseAs() can only convert to struct types."); - schema.requireUsableAs(); - return typename T::Pipeline(kj::mv(typeless)); -} - -// ------------------------------------------------------------------- - -template -typename T::Reader DynamicList::Reader::as() const { - static_assert(kind() == Kind::LIST, - "DynamicStruct::Reader::as() can only convert to list types."); - schema.requireUsableAs(); - return typename T::Reader(reader); -} -template -typename T::Builder DynamicList::Builder::as() { - static_assert(kind() == Kind::LIST, - "DynamicStruct::Builder::as() can only convert to list types."); - schema.requireUsableAs(); - return typename T::Builder(builder); -} - -template <> -inline DynamicList::Reader DynamicList::Reader::as() const { - return *this; -} -template <> -inline DynamicList::Builder DynamicList::Builder::as() { - return *this; -} - -// ------------------------------------------------------------------- - -template -inline DynamicCapability::Client::Client(T&& client) - : Capability::Client(kj::mv(client)), schema(Schema::from>()) {} - -template -inline DynamicCapability::Client::Client(kj::Own&& server) - : Client(server->getSchema(), kj::mv(server)) {} -template -inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own&& server) - : Capability::Client(kj::mv(server)), schema(schema) {} - -template -typename T::Client DynamicCapability::Client::as() { - static_assert(kind() == Kind::INTERFACE, - "DynamicCapability::Client::as() can only convert to interface types."); - schema.requireUsableAs(); - return typename T::Client(hook->addRef()); -} - -template -typename T::Client DynamicCapability::Client::releaseAs() { - static_assert(kind() == Kind::INTERFACE, - "DynamicCapability::Client::as() can only convert to interface types."); - schema.requireUsableAs(); - return typename T::Client(kj::mv(hook)); -} - -inline CallContext::CallContext( - CallContextHook& hook, StructSchema paramType, StructSchema resultType) - : hook(&hook), paramType(paramType), resultType(resultType) {} -inline DynamicStruct::Reader CallContext::getParams() { - return hook->getParams().getAs(paramType); -} -inline void CallContext::releaseParams() { - hook->releaseParams(); -} -inline DynamicStruct::Builder CallContext::getResults( - kj::Maybe sizeHint) { - return hook->getResults(sizeHint).getAs(resultType); -} -inline DynamicStruct::Builder CallContext::initResults( - kj::Maybe sizeHint) { - return hook->getResults(sizeHint).initAs(resultType); -} -inline void CallContext::setResults(DynamicStruct::Reader value) { - hook->getResults(value.totalSize()).setAs(value); -} -inline void CallContext::adoptResults(Orphan&& value) { - hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); -} -inline Orphanage CallContext::getResultsOrphanage( - kj::Maybe sizeHint) { - return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); -} -template -inline kj::Promise CallContext::tailCall( - Request&& tailRequest) { - return hook->tailCall(kj::mv(tailRequest.hook)); -} -inline void CallContext::allowCancellation() { - hook->allowCancellation(); -} - -template <> -inline DynamicCapability::Client Capability::Client::castAs( - InterfaceSchema schema) { - return DynamicCapability::Client(schema, hook->addRef()); -} - -// ------------------------------------------------------------------- - -template -ReaderFor ConstSchema::as() const { - return DynamicValue::Reader(*this).as(); -} - -} // namespace capnp - -#endif // CAPNP_DYNAMIC_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file defines classes that can be used to manipulate messages based on schemas that are not +// known until runtime. This is also useful for writing generic code that uses schemas to handle +// arbitrary types in a generic way. +// +// Each of the classes defined here has a to() template method which converts an instance back to a +// native type. This method will throw an exception if the requested type does not match the +// schema. To convert native types to dynamic, use DynamicFactory. +// +// As always, underlying data is validated lazily, so you have to actually traverse the whole +// message if you want to validate all content. + +#ifndef CAPNP_DYNAMIC_H_ +#define CAPNP_DYNAMIC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema.h" +#include "layout.h" +#include "message.h" +#include "any.h" +#include "capability.h" + +namespace capnp { + +class MessageReader; +class MessageBuilder; + +struct DynamicValue { + DynamicValue() = delete; + + enum Type { + UNKNOWN, + // Means that the value has unknown type and content because it comes from a newer version of + // the schema, or from a newer version of Cap'n Proto that has new features that this version + // doesn't understand. + + VOID, + BOOL, + INT, + UINT, + FLOAT, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + CAPABILITY, + ANY_POINTER + }; + + class Reader; + class Builder; + class Pipeline; +}; +class DynamicEnum; +struct DynamicStruct { + DynamicStruct() = delete; + class Reader; + class Builder; + class Pipeline; +}; +struct DynamicList { + DynamicList() = delete; + class Reader; + class Builder; +}; +struct DynamicCapability { + DynamicCapability() = delete; + class Client; + class Server; +}; +template <> class Orphan; + +template struct DynamicTypeFor_; +template <> struct DynamicTypeFor_ { typedef DynamicEnum Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicStruct Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicList Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicCapability Type; }; + +template +using DynamicTypeFor = typename DynamicTypeFor_()>::Type; + +template +ReaderFor>> toDynamic(T&& value); +template +BuilderFor>> toDynamic(T&& value); +template +DynamicTypeFor> toDynamic(T&& value); +template +typename DynamicTypeFor>::Client toDynamic(kj::Own&& value); + +namespace _ { // private + +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; + +} // namespace _ (private) + +template <> inline constexpr Style style() { return Style::POINTER; } +template <> inline constexpr Style style() { return Style::PRIMITIVE; } +template <> inline constexpr Style style() { return Style::STRUCT; } +template <> inline constexpr Style style() { return Style::POINTER; } +template <> inline constexpr Style style() { return Style::CAPABILITY; } + +// ------------------------------------------------------------------- + +class DynamicEnum { +public: + DynamicEnum() = default; + inline DynamicEnum(EnumSchema::Enumerant enumerant) + : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {} + inline DynamicEnum(EnumSchema schema, uint16_t value) + : schema(schema), value(value) {} + + template () == Kind::ENUM>> + inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} + + template + inline T as() const { return static_cast(asImpl(typeId())); } + // Cast to a native enum type. + + inline EnumSchema getSchema() const { return schema; } + + kj::Maybe getEnumerant() const; + // Get which enumerant this enum value represents. Returns nullptr if the numeric value does not + // correspond to any enumerant in the schema -- this can happen if the data was built using a + // newer schema that has more values defined. + + inline uint16_t getRaw() const { return value; } + // Returns the raw underlying enum value. + +private: + EnumSchema schema; + uint16_t value; + + uint16_t asImpl(uint64_t requestedTypeId) const; + + friend struct DynamicStruct; + friend struct DynamicList; + friend struct DynamicValue; + template + friend DynamicTypeFor> toDynamic(T&& value); +}; + +// ------------------------------------------------------------------- + +class DynamicStruct::Reader { +public: + typedef DynamicStruct Reads; + + Reader() = default; + + template >() == Kind::STRUCT>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } + + template + typename T::Reader as() const; + // Convert the dynamic struct to its compiled-in type. + + inline StructSchema getSchema() const { return schema; } + + DynamicValue::Reader get(StructSchema::Field field) const; + // Read the given field value. + + bool has(StructSchema::Field field) const; + // Tests whether the given field is set to its default value. For pointer values, this does + // not actually traverse the value comparing it with the default, but simply returns true if the + // pointer is non-null. For members of unions, has() returns false if the union member is not + // active, but does not necessarily return true if the member is active (depends on the field's + // value). + + kj::Maybe which() const; + // If the struct contains an (unnamed) union, and the currently-active field within that union + // is known, this returns that field. Otherwise, it returns null. In other words, this returns + // null if there is no union present _or_ if the union's discriminant is set to an unrecognized + // value. This could happen in particular when receiving a message from a sender who has a + // newer version of the protocol and is using a field of the union that you don't know about yet. + + DynamicValue::Reader get(kj::StringPtr name) const; + bool has(kj::StringPtr name) const; + // Shortcuts to access fields by name. These throw exceptions if no such field exists. + +private: + StructSchema schema; + _::StructReader reader; + + inline Reader(StructSchema schema, _::StructReader reader) + : schema(schema), reader(reader) {} + Reader(StructSchema schema, const _::OrphanBuilder& orphan); + + bool isSetInUnion(StructSchema::Field field) const; + void verifySetInUnion(StructSchema::Field field) const; + static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field); + + template + friend struct _::PointerHelpers; + friend class DynamicStruct::Builder; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template + friend struct ::capnp::ToDynamic_; + friend kj::StringTree _::structString( + _::StructReader reader, const _::RawBrandedSchema& schema); + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicStruct::Builder { +public: + typedef DynamicStruct Builds; + + Builder() = default; + inline Builder(decltype(nullptr)) {} + + template >() == Kind::STRUCT>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + inline MessageSize totalSize() const { return asReader().totalSize(); } + + template + typename T::Builder as(); + // Cast to a particular struct type. + + inline StructSchema getSchema() const { return schema; } + + DynamicValue::Builder get(StructSchema::Field field); + // Read the given field value. + + inline bool has(StructSchema::Field field) { return asReader().has(field); } + // Tests whether the given field is set to its default value. For pointer values, this does + // not actually traverse the value comparing it with the default, but simply returns true if the + // pointer is non-null. For members of unions, has() returns whether the field is currently + // active and the union as a whole is non-default -- so, the only time has() will return false + // for an active union field is if it is the default active field and it has its default value. + + kj::Maybe which(); + // If the struct contains an (unnamed) union, and the currently-active field within that union + // is known, this returns that field. Otherwise, it returns null. In other words, this returns + // null if there is no union present _or_ if the union's discriminant is set to an unrecognized + // value. This could happen in particular when receiving a message from a sender who has a + // newer version of the protocol and is using a field of the union that you don't know about yet. + + void set(StructSchema::Field field, const DynamicValue::Reader& value); + // Set the given field value. + + DynamicValue::Builder init(StructSchema::Field field); + DynamicValue::Builder init(StructSchema::Field field, uint size); + // Init a struct, list, or blob field. + + void adopt(StructSchema::Field field, Orphan&& orphan); + Orphan disown(StructSchema::Field field); + // Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set() + // and disown() becomes like get() followed by clear(). + + void clear(StructSchema::Field field); + // Clear a field, setting it to its default value. For pointer fields, this actually makes the + // field null. + + DynamicValue::Builder get(kj::StringPtr name); + bool has(kj::StringPtr name); + void set(kj::StringPtr name, const DynamicValue::Reader& value); + void set(kj::StringPtr name, std::initializer_list value); + DynamicValue::Builder init(kj::StringPtr name); + DynamicValue::Builder init(kj::StringPtr name, uint size); + void adopt(kj::StringPtr name, Orphan&& orphan); + Orphan disown(kj::StringPtr name); + void clear(kj::StringPtr name); + // Shortcuts to access fields by name. These throw exceptions if no such field exists. + + Reader asReader() const; + +private: + StructSchema schema; + _::StructBuilder builder; + + inline Builder(StructSchema schema, _::StructBuilder builder) + : schema(schema), builder(builder) {} + Builder(StructSchema schema, _::OrphanBuilder& orphan); + + bool isSetInUnion(StructSchema::Field field); + void verifySetInUnion(StructSchema::Field field); + void setInUnion(StructSchema::Field field); + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicStruct::Pipeline { +public: + typedef DynamicStruct Pipelines; + + inline Pipeline(decltype(nullptr)): typeless(nullptr) {} + + template + typename T::Pipeline releaseAs(); + // Convert the dynamic pipeline to its compiled-in type. + + inline StructSchema getSchema() { return schema; } + + DynamicValue::Pipeline get(StructSchema::Field field); + // Read the given field value. + + DynamicValue::Pipeline get(kj::StringPtr name); + // Get by string name. + +private: + StructSchema schema; + AnyPointer::Pipeline typeless; + + inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless) + : schema(schema), typeless(kj::mv(typeless)) {} + + friend class Request; +}; + +// ------------------------------------------------------------------- + +class DynamicList::Reader { +public: + typedef DynamicList Reads; + + inline Reader(): reader(ElementSize::VOID) {} + + template >() == Kind::LIST>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + template + typename T::Reader as() const; + // Try to convert to any List, Data, or Text. Throws an exception if the underlying data + // can't possibly represent the requested type. + + inline ListSchema getSchema() const { return schema; } + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + DynamicValue::Reader operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + ListSchema schema; + _::ListReader reader; + + Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {} + Reader(ListSchema schema, const _::OrphanBuilder& orphan); + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend class DynamicList::Builder; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicList::Builder { +public: + typedef DynamicList Builds; + + inline Builder(): builder(ElementSize::VOID) {} + inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} + + template >() == Kind::LIST>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + template + typename T::Builder as(); + // Try to convert to any List, Data, or Text. Throws an exception if the underlying data + // can't possibly represent the requested type. + + inline ListSchema getSchema() const { return schema; } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + DynamicValue::Builder operator[](uint index); + void set(uint index, const DynamicValue::Reader& value); + DynamicValue::Builder init(uint index, uint size); + void adopt(uint index, Orphan&& orphan); + Orphan disown(uint index); + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + void copyFrom(std::initializer_list value); + + Reader asReader() const; + +private: + ListSchema schema; + _::ListBuilder builder; + + Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} + Builder(ListSchema schema, _::OrphanBuilder& orphan); + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + template + friend struct _::OrphanGetImpl; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +// ------------------------------------------------------------------- + +class DynamicCapability::Client: public Capability::Client { +public: + typedef DynamicCapability Calls; + typedef DynamicCapability Reads; + + Client() = default; + + template >() == Kind::INTERFACE>> + inline Client(T&& client); + + template ()>> + inline Client(kj::Own&& server); + + template () == Kind::INTERFACE>> + typename T::Client as(); + template () == Kind::INTERFACE>> + typename T::Client releaseAs(); + // Convert to any client type. + + Client upcast(InterfaceSchema requestedSchema); + // Upcast to a superclass. Throws an exception if `schema` is not a superclass. + + inline InterfaceSchema getSchema() { return schema; } + + Request newRequest( + InterfaceSchema::Method method, kj::Maybe sizeHint = nullptr); + Request newRequest( + kj::StringPtr methodName, kj::Maybe sizeHint = nullptr); + +private: + InterfaceSchema schema; + + Client(InterfaceSchema schema, kj::Own&& hook) + : Capability::Client(kj::mv(hook)), schema(schema) {} + + template + inline Client(InterfaceSchema schema, kj::Own&& server); + + friend struct Capability; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct DynamicValue; + friend class Orphan; + friend class Orphan; + friend class Orphan; + template + friend struct _::PointerHelpers; +}; + +class DynamicCapability::Server: public Capability::Server { +public: + typedef DynamicCapability Serves; + + Server(InterfaceSchema schema): schema(schema) {} + + virtual kj::Promise call(InterfaceSchema::Method method, + CallContext context) = 0; + + kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + CallContext context) override final; + + inline InterfaceSchema getSchema() const { return schema; } + +private: + InterfaceSchema schema; +}; + +template <> +class Request: public DynamicStruct::Builder { + // Specialization of `Request` for DynamicStruct. + +public: + inline Request(DynamicStruct::Builder builder, kj::Own&& hook, + StructSchema resultSchema) + : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} + + RemotePromise send(); + // Send the call and return a promise for the results. + +private: + kj::Own hook; + StructSchema resultSchema; + + friend class Capability::Client; + friend struct DynamicCapability; + template + friend class CallContext; + friend class RequestHook; +}; + +template <> +class CallContext: public kj::DisallowConstCopy { + // Wrapper around CallContextHook with a specific return type. + // + // Methods of this class may only be called from within the server's event loop, not from other + // threads. + +public: + explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType); + + DynamicStruct::Reader getParams(); + void releaseParams(); + DynamicStruct::Builder getResults(kj::Maybe sizeHint = nullptr); + DynamicStruct::Builder initResults(kj::Maybe sizeHint = nullptr); + void setResults(DynamicStruct::Reader value); + void adoptResults(Orphan&& value); + Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); + template + kj::Promise tailCall(Request&& tailRequest); + void allowCancellation(); + +private: + CallContextHook* hook; + StructSchema paramType; + StructSchema resultType; + + friend class DynamicCapability::Server; +}; + +// ------------------------------------------------------------------- + +// Make sure ReaderFor and BuilderFor work for DynamicEnum, DynamicStruct, and +// DynamicList, so that we can define DynamicValue::as(). + +template <> struct ReaderFor_ { typedef DynamicEnum Type; }; +template <> struct BuilderFor_ { typedef DynamicEnum Type; }; +template <> struct ReaderFor_ { typedef DynamicStruct::Reader Type; }; +template <> struct BuilderFor_ { typedef DynamicStruct::Builder Type; }; +template <> struct ReaderFor_ { typedef DynamicList::Reader Type; }; +template <> struct BuilderFor_ { typedef DynamicList::Builder Type; }; +template <> struct ReaderFor_ { typedef DynamicCapability::Client Type; }; +template <> struct BuilderFor_ { typedef DynamicCapability::Client Type; }; +template <> struct PipelineFor_ { typedef DynamicCapability::Client Type; }; + +class DynamicValue::Reader { +public: + typedef DynamicValue Reads; + + inline Reader(decltype(nullptr) n = nullptr); // UNKNOWN + inline Reader(Void value); + inline Reader(bool value); + inline Reader(char value); + inline Reader(signed char value); + inline Reader(short value); + inline Reader(int value); + inline Reader(long value); + inline Reader(long long value); + inline Reader(unsigned char value); + inline Reader(unsigned short value); + inline Reader(unsigned int value); + inline Reader(unsigned long value); + inline Reader(unsigned long long value); + inline Reader(float value); + inline Reader(double value); + inline Reader(const char* value); // Text + inline Reader(const Text::Reader& value); + inline Reader(const Data::Reader& value); + inline Reader(const DynamicList::Reader& value); + inline Reader(DynamicEnum value); + inline Reader(const DynamicStruct::Reader& value); + inline Reader(const AnyPointer::Reader& value); + inline Reader(DynamicCapability::Client& value); + inline Reader(DynamicCapability::Client&& value); + template ()>> + inline Reader(kj::Own&& value); + Reader(ConstSchema constant); + + template ()))> + inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {} + + Reader(const Reader& other); + Reader(Reader&& other) noexcept; + ~Reader() noexcept(false); + Reader& operator=(const Reader& other); + Reader& operator=(Reader&& other); + // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not + // trivially copyable. + + template + inline ReaderFor as() const { return AsImpl::apply(*this); } + // Use to interpret the value as some Cap'n Proto type. Allowed types are: + // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value. + // - Text, Data, AnyPointer, any struct type: Returns the corresponding Reader. + // - List for any T listed above: Returns List::Reader. + // - DynamicEnum: Returns the corresponding type. + // - DynamicStruct, DynamicList: Returns the corresponding Reader. + // - Any capability type, including DynamicCapability: Returns the corresponding Client. + // - DynamicValue: Returns an identical Reader. Useful to avoid special-casing in generic code. + // (TODO(perf): On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids + // refcounting.) + // + // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier. + // - Any integer can be converted to any other integer type so long as the actual value is within + // the new type's range. + // - Floating-point types can be converted to integers as long as no information would be lost + // in the conversion. + // - Integers can be converted to floating points. This may lose information, but won't throw. + // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose + // information, but won't throw. + // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not + // vice-versa). + // - Capabilities can be upcast (cast to a supertype), but not downcast. + // + // Any other conversion attempt will throw an exception. + + inline Type getType() const { return type; } + // Get the type of this value. + +private: + Type type; + + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + Text::Reader textValue; + Data::Reader dataValue; + DynamicList::Reader listValue; + DynamicEnum enumValue; + DynamicStruct::Reader structValue; + AnyPointer::Reader anyPointerValue; + + mutable DynamicCapability::Client capabilityValue; + // Declared mutable because `Client`s normally cannot be const. + + // Warning: Copy/move constructors assume all these types are trivially copyable except + // Capability. + }; + + template ()> struct AsImpl; + // Implementation backing the as() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. + + friend class Orphanage; // to speed up newOrphanCopy(DynamicValue::Reader) +}; + +class DynamicValue::Builder { +public: + typedef DynamicValue Builds; + + inline Builder(decltype(nullptr) n = nullptr); // UNKNOWN + inline Builder(Void value); + inline Builder(bool value); + inline Builder(char value); + inline Builder(signed char value); + inline Builder(short value); + inline Builder(int value); + inline Builder(long value); + inline Builder(long long value); + inline Builder(unsigned char value); + inline Builder(unsigned short value); + inline Builder(unsigned int value); + inline Builder(unsigned long value); + inline Builder(unsigned long long value); + inline Builder(float value); + inline Builder(double value); + inline Builder(Text::Builder value); + inline Builder(Data::Builder value); + inline Builder(DynamicList::Builder value); + inline Builder(DynamicEnum value); + inline Builder(DynamicStruct::Builder value); + inline Builder(AnyPointer::Builder value); + inline Builder(DynamicCapability::Client& value); + inline Builder(DynamicCapability::Client&& value); + + template ()))> + inline Builder(T value): Builder(toDynamic(value)) {} + + Builder(Builder& other); + Builder(Builder&& other) noexcept; + ~Builder() noexcept(false); + Builder& operator=(Builder& other); + Builder& operator=(Builder&& other); + // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not + // trivially copyable. + + template + inline BuilderFor as() { return AsImpl::apply(*this); } + // See DynamicValue::Reader::as(). + + inline Type getType() { return type; } + // Get the type of this value. + + Reader asReader() const; + +private: + Type type; + + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + Text::Builder textValue; + Data::Builder dataValue; + DynamicList::Builder listValue; + DynamicEnum enumValue; + DynamicStruct::Builder structValue; + AnyPointer::Builder anyPointerValue; + + mutable DynamicCapability::Client capabilityValue; + // Declared mutable because `Client`s normally cannot be const. + }; + + template ()> struct AsImpl; + // Implementation backing the as() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. + + friend class Orphan; +}; + +class DynamicValue::Pipeline { +public: + typedef DynamicValue Pipelines; + + inline Pipeline(decltype(nullptr) n = nullptr); + inline Pipeline(DynamicStruct::Pipeline&& value); + inline Pipeline(DynamicCapability::Client&& value); + + Pipeline(Pipeline&& other) noexcept; + Pipeline& operator=(Pipeline&& other); + ~Pipeline() noexcept(false); + + template + inline PipelineFor releaseAs() { return AsImpl::apply(*this); } + + inline Type getType() { return type; } + // Get the type of this value. + +private: + Type type; + union { + DynamicStruct::Pipeline structValue; + DynamicCapability::Client capabilityValue; + }; + + template ()> struct AsImpl; + // Implementation backing the releaseAs() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. +}; + +kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value); +kj::StringTree KJ_STRINGIFY(DynamicEnum value); +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value); +kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value); + +// ------------------------------------------------------------------- +// Orphan <-> Dynamic glue + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::STRUCT>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicStruct::Builder get(); + DynamicStruct::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + StructSchema schema; + _::OrphanBuilder builder; + + inline Orphan(StructSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class MessageBuilder; +}; + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::LIST>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicList::Builder get(); + DynamicList::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + // TODO(someday): Support truncate(). + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + ListSchema schema; + _::OrphanBuilder builder; + + inline Orphan(ListSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; +}; + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::INTERFACE>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicCapability::Client get(); + DynamicCapability::Client getReader() const; + + template + Orphan releaseAs(); + // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + InterfaceSchema schema; + _::OrphanBuilder builder; + + inline Orphan(InterfaceSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; +}; + +template <> +class Orphan { +public: + inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {} + inline Orphan(Void value); + inline Orphan(bool value); + inline Orphan(char value); + inline Orphan(signed char value); + inline Orphan(short value); + inline Orphan(int value); + inline Orphan(long value); + inline Orphan(long long value); + inline Orphan(unsigned char value); + inline Orphan(unsigned short value); + inline Orphan(unsigned int value); + inline Orphan(unsigned long value); + inline Orphan(unsigned long long value); + inline Orphan(float value); + inline Orphan(double value); + inline Orphan(DynamicEnum value); + Orphan(Orphan&&) = default; + template + Orphan(Orphan&&); + Orphan(Orphan&&); + Orphan(void*) = delete; // So Orphan(bool) doesn't accept pointers. + KJ_DISALLOW_COPY(Orphan); + + Orphan& operator=(Orphan&&) = default; + + inline DynamicValue::Type getType() { return type; } + + DynamicValue::Builder get(); + DynamicValue::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + +private: + DynamicValue::Type type; + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + DynamicEnum enumValue; + StructSchema structSchema; + ListSchema listSchema; + InterfaceSchema interfaceSchema; + }; + + _::OrphanBuilder builder; + // Only used if `type` is a pointer type. + + Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder); + Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder) + : type(type), builder(kj::mv(builder)) {} + Orphan(StructSchema structSchema, _::OrphanBuilder&& builder) + : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {} + Orphan(ListSchema listSchema, _::OrphanBuilder&& builder) + : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct AnyPointer; + friend class Orphanage; +}; + +template +inline Orphan::Orphan(Orphan&& other) + : Orphan(other.get(), kj::mv(other.builder)) {} + +inline Orphan::Orphan(Orphan&& other) + : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + type = DynamicValue::UNKNOWN; + return Orphan(kj::mv(builder)); +} + +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(DynamicStruct::Builder& t) { + return t.builder; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(DynamicList::Builder& t) { + return t.builder; + } +}; + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicStruct::Reader copyFrom) const { + return Orphan( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicList::Reader copyFrom) const { + return Orphan(copyFrom.getSchema(), + _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicCapability::Client copyFrom) const { + return Orphan( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); +} + +template <> +Orphan Orphanage::newOrphanCopy( + DynamicValue::Reader copyFrom) const; + +namespace _ { // private + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema); + static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema); + static void set(PointerBuilder builder, const DynamicStruct::Reader& value); + static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, StructSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema); + static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema); + static void set(PointerBuilder builder, const DynamicList::Reader& value); + static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, ListSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema); + static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema); + static void set(PointerBuilder builder, DynamicCapability::Client& value); + static void set(PointerBuilder builder, DynamicCapability::Client&& value); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, InterfaceSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +} // namespace _ (private) + +template +inline ReaderFor AnyPointer::Reader::getAs(StructSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline ReaderFor AnyPointer::Reader::getAs(ListSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline ReaderFor AnyPointer::Reader::getAs(InterfaceSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(StructSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(ListSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(InterfaceSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::initAs(StructSchema schema) { + return _::PointerHelpers::init(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { + return _::PointerHelpers::init(builder, schema, elementCount); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicStruct::Reader value) { + return _::PointerHelpers::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicList::Reader value) { + return _::PointerHelpers::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicCapability::Client value) { + return _::PointerHelpers::set(builder, kj::mv(value)); +} +template <> +void AnyPointer::Builder::adopt(Orphan&& orphan); +template +inline Orphan AnyPointer::Builder::disownAs(StructSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} +template +inline Orphan AnyPointer::Builder::disownAs(ListSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} +template +inline Orphan AnyPointer::Builder::disownAs(InterfaceSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} + +// We have to declare the methods below inline because Clang and GCC disagree about how to mangle +// their symbol names. +template <> +inline DynamicStruct::Builder Orphan::getAs(StructSchema schema) { + return DynamicStruct::Builder(schema, builder); +} +template <> +inline DynamicStruct::Reader Orphan::getAsReader( + StructSchema schema) const { + return DynamicStruct::Reader(schema, builder); +} +template <> +inline Orphan Orphan::releaseAs(StructSchema schema) { + return Orphan(schema, kj::mv(builder)); +} +template <> +inline DynamicList::Builder Orphan::getAs(ListSchema schema) { + return DynamicList::Builder(schema, builder); +} +template <> +inline DynamicList::Reader Orphan::getAsReader(ListSchema schema) const { + return DynamicList::Reader(schema, builder); +} +template <> +inline Orphan Orphan::releaseAs(ListSchema schema) { + return Orphan(schema, kj::mv(builder)); +} +template <> +inline DynamicCapability::Client Orphan::getAs( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline DynamicCapability::Client Orphan::getAsReader( + InterfaceSchema schema) const { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline Orphan Orphan::releaseAs( + InterfaceSchema schema) { + return Orphan(schema, kj::mv(builder)); +} + +// ======================================================================================= +// Inline implementation details. + +template +struct ToDynamic_ { + static inline DynamicStruct::Reader apply(const typename T::Reader& value) { + return DynamicStruct::Reader(Schema::from(), value._reader); + } + static inline DynamicStruct::Builder apply(typename T::Builder& value) { + return DynamicStruct::Builder(Schema::from(), value._builder); + } +}; + +template +struct ToDynamic_ { + static inline DynamicList::Reader apply(const typename T::Reader& value) { + return DynamicList::Reader(Schema::from(), value.reader); + } + static inline DynamicList::Builder apply(typename T::Builder& value) { + return DynamicList::Builder(Schema::from(), value.builder); + } +}; + +template +struct ToDynamic_ { + static inline DynamicCapability::Client apply(typename T::Client value) { + return DynamicCapability::Client(kj::mv(value)); + } + static inline DynamicCapability::Client apply(typename T::Client&& value) { + return DynamicCapability::Client(kj::mv(value)); + } +}; + +template +ReaderFor>> toDynamic(T&& value) { + return ToDynamic_>::apply(value); +} +template +BuilderFor>> toDynamic(T&& value) { + return ToDynamic_>::apply(value); +} +template +DynamicTypeFor> toDynamic(T&& value) { + return DynamicEnum(Schema::from>(), static_cast(value)); +} +template +typename DynamicTypeFor>::Client toDynamic(kj::Own&& value) { + return typename FromServer::Client(kj::mv(value)); +} + +inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {} +inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {} + +#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ +inline DynamicValue::Reader::Reader(cppType value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline DynamicValue::Builder::Builder(cppType value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline Orphan::Orphan(cppType value) \ + : type(DynamicValue::typeTag), fieldName##Value(value) {} + +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum); +#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR + +#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ +inline DynamicValue::Reader::Reader(const cppType::Reader& value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline DynamicValue::Builder::Builder(cppType::Builder value) \ + : type(typeTag), fieldName##Value(value) {} + +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer); + +#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR + +inline DynamicValue::Reader::Reader(DynamicCapability::Client& value) + : type(CAPABILITY), capabilityValue(value) {} +inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} +template +inline DynamicValue::Reader::Reader(kj::Own&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} +inline DynamicValue::Builder::Builder(DynamicCapability::Client& value) + : type(CAPABILITY), capabilityValue(value) {} +inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} + +inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {} + +#define CAPNP_DECLARE_TYPE(discrim, typeName) \ +template <> \ +struct DynamicValue::Reader::AsImpl { \ + static ReaderFor apply(const Reader& reader); \ +}; \ +template <> \ +struct DynamicValue::Builder::AsImpl { \ + static BuilderFor apply(Builder& builder); \ +}; + +//CAPNP_DECLARE_TYPE(VOID, Void) +CAPNP_DECLARE_TYPE(BOOL, bool) +CAPNP_DECLARE_TYPE(INT8, int8_t) +CAPNP_DECLARE_TYPE(INT16, int16_t) +CAPNP_DECLARE_TYPE(INT32, int32_t) +CAPNP_DECLARE_TYPE(INT64, int64_t) +CAPNP_DECLARE_TYPE(UINT8, uint8_t) +CAPNP_DECLARE_TYPE(UINT16, uint16_t) +CAPNP_DECLARE_TYPE(UINT32, uint32_t) +CAPNP_DECLARE_TYPE(UINT64, uint64_t) +CAPNP_DECLARE_TYPE(FLOAT32, float) +CAPNP_DECLARE_TYPE(FLOAT64, double) + +CAPNP_DECLARE_TYPE(TEXT, Text) +CAPNP_DECLARE_TYPE(DATA, Data) +CAPNP_DECLARE_TYPE(LIST, DynamicList) +CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct) +CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability) +CAPNP_DECLARE_TYPE(ENUM, DynamicEnum) +CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer) +#undef CAPNP_DECLARE_TYPE + +// CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the +// ReaderFor<> and BuilderFor<> wrappers, it works. +template <> +struct DynamicValue::Reader::AsImpl { + static Void apply(const Reader& reader); +}; +template <> +struct DynamicValue::Builder::AsImpl { + static Void apply(Builder& builder); +}; + +template +struct DynamicValue::Reader::AsImpl { + static T apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static T apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Reader apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Builder apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Reader apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Builder apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Client apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Client apply(Builder& builder) { + return builder.as().as(); + } +}; + +template <> +struct DynamicValue::Reader::AsImpl { + static DynamicValue::Reader apply(const Reader& reader) { + return reader; + } +}; +template <> +struct DynamicValue::Builder::AsImpl { + static DynamicValue::Builder apply(Builder& builder) { + return builder; + } +}; + +inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {} +inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value) + : type(STRUCT), structValue(kj::mv(value)) {} +inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} + +template +struct DynamicValue::Pipeline::AsImpl { + static typename T::Pipeline apply(Pipeline& pipeline) { + return pipeline.releaseAs().releaseAs(); + } +}; +template +struct DynamicValue::Pipeline::AsImpl { + static typename T::Client apply(Pipeline& pipeline) { + return pipeline.releaseAs().releaseAs(); + } +}; +template <> +struct DynamicValue::Pipeline::AsImpl { + static PipelineFor apply(Pipeline& pipeline); +}; +template <> +struct DynamicValue::Pipeline::AsImpl { + static PipelineFor apply(Pipeline& pipeline); +}; + +// ------------------------------------------------------------------- + +template +typename T::Reader DynamicStruct::Reader::as() const { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Reader::as() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Reader(reader); +} + +template +typename T::Builder DynamicStruct::Builder::as() { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Builder::as() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Builder(builder); +} + +template <> +inline DynamicStruct::Reader DynamicStruct::Reader::as() const { + return *this; +} +template <> +inline DynamicStruct::Builder DynamicStruct::Builder::as() { + return *this; +} + +inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { + return DynamicStruct::Reader(schema, builder.asReader()); +} + +template <> +inline AnyStruct::Reader DynamicStruct::Reader::as() const { + return AnyStruct::Reader(reader); +} + +template <> +inline AnyStruct::Builder DynamicStruct::Builder::as() { + return AnyStruct::Builder(builder); +} + +template +typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Pipeline::releaseAs() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Pipeline(kj::mv(typeless)); +} + +// ------------------------------------------------------------------- + +template +typename T::Reader DynamicList::Reader::as() const { + static_assert(kind() == Kind::LIST, + "DynamicStruct::Reader::as() can only convert to list types."); + schema.requireUsableAs(); + return typename T::Reader(reader); +} +template +typename T::Builder DynamicList::Builder::as() { + static_assert(kind() == Kind::LIST, + "DynamicStruct::Builder::as() can only convert to list types."); + schema.requireUsableAs(); + return typename T::Builder(builder); +} + +template <> +inline DynamicList::Reader DynamicList::Reader::as() const { + return *this; +} +template <> +inline DynamicList::Builder DynamicList::Builder::as() { + return *this; +} + +template <> +inline AnyList::Reader DynamicList::Reader::as() const { + return AnyList::Reader(reader); +} + +template <> +inline AnyList::Builder DynamicList::Builder::as() { + return AnyList::Builder(builder); +} + +// ------------------------------------------------------------------- + +template +inline DynamicCapability::Client::Client(T&& client) + : Capability::Client(kj::mv(client)), schema(Schema::from>()) {} + +template +inline DynamicCapability::Client::Client(kj::Own&& server) + : Client(server->getSchema(), kj::mv(server)) {} +template +inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own&& server) + : Capability::Client(kj::mv(server)), schema(schema) {} + +template +typename T::Client DynamicCapability::Client::as() { + static_assert(kind() == Kind::INTERFACE, + "DynamicCapability::Client::as() can only convert to interface types."); + schema.requireUsableAs(); + return typename T::Client(hook->addRef()); +} + +template +typename T::Client DynamicCapability::Client::releaseAs() { + static_assert(kind() == Kind::INTERFACE, + "DynamicCapability::Client::as() can only convert to interface types."); + schema.requireUsableAs(); + return typename T::Client(kj::mv(hook)); +} + +inline CallContext::CallContext( + CallContextHook& hook, StructSchema paramType, StructSchema resultType) + : hook(&hook), paramType(paramType), resultType(resultType) {} +inline DynamicStruct::Reader CallContext::getParams() { + return hook->getParams().getAs(paramType); +} +inline void CallContext::releaseParams() { + hook->releaseParams(); +} +inline DynamicStruct::Builder CallContext::getResults( + kj::Maybe sizeHint) { + return hook->getResults(sizeHint).getAs(resultType); +} +inline DynamicStruct::Builder CallContext::initResults( + kj::Maybe sizeHint) { + return hook->getResults(sizeHint).initAs(resultType); +} +inline void CallContext::setResults(DynamicStruct::Reader value) { + hook->getResults(value.totalSize()).setAs(value); +} +inline void CallContext::adoptResults(Orphan&& value) { + hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); +} +inline Orphanage CallContext::getResultsOrphanage( + kj::Maybe sizeHint) { + return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); +} +template +inline kj::Promise CallContext::tailCall( + Request&& tailRequest) { + return hook->tailCall(kj::mv(tailRequest.hook)); +} +inline void CallContext::allowCancellation() { + hook->allowCancellation(); +} + +template <> +inline DynamicCapability::Client Capability::Client::castAs( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, hook->addRef()); +} + +// ------------------------------------------------------------------- + +template +ReaderFor ConstSchema::as() const { + return DynamicValue::Reader(*this).as(); +} + +} // namespace capnp + +#endif // CAPNP_DYNAMIC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/endian.h --- a/osx/include/capnp/endian.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/endian.h Mon May 22 10:01:37 2017 +0100 @@ -1,309 +1,309 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_ENDIAN_H_ -#define CAPNP_ENDIAN_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "common.h" -#include -#include // memcpy - -namespace capnp { -namespace _ { // private - -// WireValue -// -// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the -// wire, because little-endian is the most common endianness in modern CPUs. -// -// Note: In general, code that depends cares about byte ordering is bad. See: -// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html -// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over -// allocation and layout of memory, in order to squeeze out every last drop of performance. - -#if _MSC_VER -// Assume Windows is little-endian. -// -// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or -// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC -// intrinsics. - -#ifndef __ORDER_BIG_ENDIAN__ -#define __ORDER_BIG_ENDIAN__ 4321 -#endif -#ifndef __ORDER_LITTLE_ENDIAN__ -#define __ORDER_LITTLE_ENDIAN__ 1234 -#endif -#ifndef __BYTE_ORDER__ -#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#endif -#endif - -#if CAPNP_REVERSE_ENDIAN -#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ -#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ -#else -#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ -#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ -#endif - -#if defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ - !CAPNP_DISABLE_ENDIAN_DETECTION -// CPU is little-endian. We can just read/write the memory directly. - -template -class DirectWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template -using WireValue = DirectWireValue; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#elif defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ - defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION -// Big-endian, but GCC's __builtin_bswap() is available. - -// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have -// them. - -// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the -// compiler optimizes away the memcpy()s and keeps everything in registers. - -template -class SwappingWireValue; - -template -class SwappingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template -class SwappingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing - // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). - uint16_t swapped = (value << 8) | (value >> 8); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint16_t raw; - memcpy(&raw, &newValue, sizeof(T)); - // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing - // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). - value = (raw << 8) | (raw >> 8); - } - -private: - uint16_t value; -}; - -template -class SwappingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint32_t swapped = __builtin_bswap32(value); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint32_t raw; - memcpy(&raw, &newValue, sizeof(T)); - value = __builtin_bswap32(raw); - } - -private: - uint32_t value; -}; - -template -class SwappingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint64_t swapped = __builtin_bswap64(value); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint64_t raw; - memcpy(&raw, &newValue, sizeof(T)); - value = __builtin_bswap64(raw); - } - -private: - uint64_t value; -}; - -template -using WireValue = SwappingWireValue; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#else -// Unknown endianness. Fall back to bit shifts. - -#if !CAPNP_DISABLE_ENDIAN_DETECTION -#if _MSC_VER -#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") -#pragma message("Consider changing this code to detect your platform and send us a patch!") -#else -#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." -#warning "Consider changing this code to detect your platform and send us a patch!" -#endif -#endif // !CAPNP_DISABLE_ENDIAN_DETECTION - -template -class ShiftingWireValue; - -template -class ShiftingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template -class ShiftingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint16_t raw = (static_cast(bytes[0]) ) | - (static_cast(bytes[1]) << 8); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint16_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - } - -private: - union { - byte bytes[2]; - uint16_t align; - }; -}; - -template -class ShiftingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint32_t raw = (static_cast(bytes[0]) ) | - (static_cast(bytes[1]) << 8) | - (static_cast(bytes[2]) << 16) | - (static_cast(bytes[3]) << 24); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint32_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - bytes[2] = raw >> 16; - bytes[3] = raw >> 24; - } - -private: - union { - byte bytes[4]; - uint32_t align; - }; -}; - -template -class ShiftingWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint64_t raw = (static_cast(bytes[0]) ) | - (static_cast(bytes[1]) << 8) | - (static_cast(bytes[2]) << 16) | - (static_cast(bytes[3]) << 24) | - (static_cast(bytes[4]) << 32) | - (static_cast(bytes[5]) << 40) | - (static_cast(bytes[6]) << 48) | - (static_cast(bytes[7]) << 56); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint64_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - bytes[2] = raw >> 16; - bytes[3] = raw >> 24; - bytes[4] = raw >> 32; - bytes[5] = raw >> 40; - bytes[6] = raw >> 48; - bytes[7] = raw >> 56; - } - -private: - union { - byte bytes[8]; - uint64_t align; - }; -}; - -template -using WireValue = ShiftingWireValue; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#endif - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_ENDIAN_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ENDIAN_H_ +#define CAPNP_ENDIAN_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" +#include +#include // memcpy + +namespace capnp { +namespace _ { // private + +// WireValue +// +// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the +// wire, because little-endian is the most common endianness in modern CPUs. +// +// Note: In general, code that depends cares about byte ordering is bad. See: +// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html +// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over +// allocation and layout of memory, in order to squeeze out every last drop of performance. + +#if _MSC_VER +// Assume Windows is little-endian. +// +// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or +// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC +// intrinsics. + +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ 4321 +#endif +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 1234 +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#endif + +#if CAPNP_REVERSE_ENDIAN +#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#else +#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#endif + +#if defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ + !CAPNP_DISABLE_ENDIAN_DETECTION +// CPU is little-endian. We can just read/write the memory directly. + +template +class DirectWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +using WireValue = DirectWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#elif defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ + defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION +// Big-endian, but GCC's __builtin_bswap() is available. + +// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have +// them. + +// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the +// compiler optimizes away the memcpy()s and keeps everything in registers. + +template +class SwappingWireValue; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + uint16_t swapped = (value << 8) | (value >> 8); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + value = (raw << 8) | (raw >> 8); + } + +private: + uint16_t value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t swapped = __builtin_bswap32(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap32(raw); + } + +private: + uint32_t value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t swapped = __builtin_bswap64(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap64(raw); + } + +private: + uint64_t value; +}; + +template +using WireValue = SwappingWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#else +// Unknown endianness. Fall back to bit shifts. + +#if !CAPNP_DISABLE_ENDIAN_DETECTION +#if _MSC_VER +#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") +#pragma message("Consider changing this code to detect your platform and send us a patch!") +#else +#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." +#warning "Consider changing this code to detect your platform and send us a patch!" +#endif +#endif // !CAPNP_DISABLE_ENDIAN_DETECTION + +template +class ShiftingWireValue; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint16_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + } + +private: + union { + byte bytes[2]; + uint16_t align; + }; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8) | + (static_cast(bytes[2]) << 16) | + (static_cast(bytes[3]) << 24); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + } + +private: + union { + byte bytes[4]; + uint32_t align; + }; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8) | + (static_cast(bytes[2]) << 16) | + (static_cast(bytes[3]) << 24) | + (static_cast(bytes[4]) << 32) | + (static_cast(bytes[5]) << 40) | + (static_cast(bytes[6]) << 48) | + (static_cast(bytes[7]) << 56); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + bytes[4] = raw >> 32; + bytes[5] = raw >> 40; + bytes[6] = raw >> 48; + bytes[7] = raw >> 56; + } + +private: + union { + byte bytes[8]; + uint64_t align; + }; +}; + +template +using WireValue = ShiftingWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#endif + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_ENDIAN_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/ez-rpc.h --- a/osx/include/capnp/ez-rpc.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/ez-rpc.h Mon May 22 10:01:37 2017 +0100 @@ -1,254 +1,254 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_EZ_RPC_H_ -#define CAPNP_EZ_RPC_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "rpc.h" -#include "message.h" - -struct sockaddr; - -namespace kj { class AsyncIoProvider; class LowLevelAsyncIoProvider; } - -namespace capnp { - -class EzRpcContext; - -class EzRpcClient { - // Super-simple interface for setting up a Cap'n Proto RPC client. Example: - // - // # Cap'n Proto schema - // interface Adder { - // add @0 (left :Int32, right :Int32) -> (value :Int32); - // } - // - // // C++ client - // int main() { - // capnp::EzRpcClient client("localhost:3456"); - // Adder::Client adder = client.getMain(); - // auto request = adder.addRequest(); - // request.setLeft(12); - // request.setRight(34); - // auto response = request.send().wait(client.getWaitScope()); - // assert(response.getValue() == 46); - // return 0; - // } - // - // // C++ server - // class AdderImpl final: public Adder::Server { - // public: - // kj::Promise add(AddContext context) override { - // auto params = context.getParams(); - // context.getResults().setValue(params.getLeft() + params.getRight()); - // return kj::READY_NOW; - // } - // }; - // - // int main() { - // capnp::EzRpcServer server(kj::heap(), "*:3456"); - // kj::NEVER_DONE.wait(server.getWaitScope()); - // } - // - // This interface is easy, but it hides a lot of useful features available from the lower-level - // classes: - // - The server can only export a small set of public, singleton capabilities under well-known - // string names. This is fine for transient services where no state needs to be kept between - // connections, but hides the power of Cap'n Proto when it comes to long-lived resources. - // - EzRpcClient/EzRpcServer automatically set up a `kj::EventLoop` and make it current for the - // thread. Only one `kj::EventLoop` can exist per thread, so you cannot use these interfaces - // if you wish to set up your own event loop. (However, you can safely create multiple - // EzRpcClient / EzRpcServer objects in a single thread; they will make sure to make no more - // than one EventLoop.) - // - These classes only support simple two-party connections, not multilateral VatNetworks. - // - These classes only support communication over a raw, unencrypted socket. If you want to - // build on an abstract stream (perhaps one which supports encryption), you must use the - // lower-level interfaces. - // - // Some of these restrictions will probably be lifted in future versions, but some things will - // always require using the low-level interfaces directly. If you are interested in working - // at a lower level, start by looking at these interfaces: - // - `kj::setupAsyncIo()` in `kj/async-io.h`. - // - `RpcSystem` in `capnp/rpc.h`. - // - `TwoPartyVatNetwork` in `capnp/rpc-twoparty.h`. - -public: - explicit EzRpcClient(kj::StringPtr serverAddress, uint defaultPort = 0, - ReaderOptions readerOpts = ReaderOptions()); - // Construct a new EzRpcClient and connect to the given address. The connection is formed in - // the background -- if it fails, calls to capabilities returned by importCap() will fail with an - // appropriate exception. - // - // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. - // If unspecified, the port is required in `serverAddress`. - // - // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info - // on the address format, but basically it's what you'd expect. - // - // `readerOpts` is the ReaderOptions structure used to read each incoming message on the - // connection. Setting this may be necessary if you need to receive very large individual - // messages or messages. However, it is recommended that you instead think about how to change - // your protocol to send large data blobs in multiple small chunks -- this is much better for - // both security and performance. See `ReaderOptions` in `message.h` for more details. - - EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, - ReaderOptions readerOpts = ReaderOptions()); - // Like the above constructor, but connects to an already-resolved socket address. Any address - // format supported by `kj::Network` in `kj/async-io.h` is accepted. - - explicit EzRpcClient(int socketFd, ReaderOptions readerOpts = ReaderOptions()); - // Create a client on top of an already-connected socket. - // `readerOpts` acts as in the first constructor. - - ~EzRpcClient() noexcept(false); - - template - typename Type::Client getMain(); - Capability::Client getMain(); - // Get the server's main (aka "bootstrap") interface. - - template - typename Type::Client importCap(kj::StringPtr name) - KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); - Capability::Client importCap(kj::StringPtr name) - KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); - // ** DEPRECATED ** - // - // Ask the sever for the capability with the given name. You may specify a type to automatically - // down-cast to that type. It is up to you to specify the correct expected type. - // - // Named interfaces are deprecated. The new preferred usage pattern is for the server to export - // a "main" interface which itself has methods for getting any other interfaces. - - kj::WaitScope& getWaitScope(); - // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on - // promises. - - kj::AsyncIoProvider& getIoProvider(); - // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want - // to do some non-RPC I/O in asynchronous fashion. - - kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); - // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you - // want to do some non-RPC I/O in asynchronous fashion. - -private: - struct Impl; - kj::Own impl; -}; - -class EzRpcServer { - // The server counterpart to `EzRpcClient`. See `EzRpcClient` for an example. - -public: - explicit EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress, - uint defaultPort = 0, ReaderOptions readerOpts = ReaderOptions()); - // Construct a new `EzRpcServer` that binds to the given address. An address of "*" means to - // bind to all local addresses. - // - // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. - // If unspecified, a port is chosen automatically, and you must call getPort() to find out what - // it is. - // - // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info - // on the address format, but basically it's what you'd expect. - // - // The server might not begin listening immediately, especially if `bindAddress` needs to be - // resolved. If you need to wait until the server is definitely up, wait on the promise returned - // by `getPort()`. - // - // `readerOpts` is the ReaderOptions structure used to read each incoming message on the - // connection. Setting this may be necessary if you need to receive very large individual - // messages or messages. However, it is recommended that you instead think about how to change - // your protocol to send large data blobs in multiple small chunks -- this is much better for - // both security and performance. See `ReaderOptions` in `message.h` for more details. - - EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize, - ReaderOptions readerOpts = ReaderOptions()); - // Like the above constructor, but binds to an already-resolved socket address. Any address - // format supported by `kj::Network` in `kj/async-io.h` is accepted. - - EzRpcServer(Capability::Client mainInterface, int socketFd, uint port, - ReaderOptions readerOpts = ReaderOptions()); - // Create a server on top of an already-listening socket (i.e. one on which accept() may be - // called). `port` is returned by `getPort()` -- it serves no other purpose. - // `readerOpts` acts as in the other two above constructors. - - explicit EzRpcServer(kj::StringPtr bindAddress, uint defaultPort = 0, - ReaderOptions readerOpts = ReaderOptions()) - KJ_DEPRECATED("Please specify a main interface for your server."); - EzRpcServer(struct sockaddr* bindAddress, uint addrSize, - ReaderOptions readerOpts = ReaderOptions()) - KJ_DEPRECATED("Please specify a main interface for your server."); - EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts = ReaderOptions()) - KJ_DEPRECATED("Please specify a main interface for your server."); - - ~EzRpcServer() noexcept(false); - - void exportCap(kj::StringPtr name, Capability::Client cap); - // Export a capability publicly under the given name, so that clients can import it. - // - // Keep in mind that you can implicitly convert `kj::Own&&` to - // `Capability::Client`, so it's typical to pass something like - // `kj::heap()` as the second parameter. - - kj::Promise getPort(); - // Get the IP port number on which this server is listening. This promise won't resolve until - // the server is actually listening. If the address was not an IP address (e.g. it was a Unix - // domain socket) then getPort() resolves to zero. - - kj::WaitScope& getWaitScope(); - // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on - // promises. - - kj::AsyncIoProvider& getIoProvider(); - // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want - // to do some non-RPC I/O in asynchronous fashion. - - kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); - // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you - // want to do some non-RPC I/O in asynchronous fashion. - -private: - struct Impl; - kj::Own impl; -}; - -// ======================================================================================= -// inline implementation details - -template -inline typename Type::Client EzRpcClient::getMain() { - return getMain().castAs(); -} - -template -inline typename Type::Client EzRpcClient::importCap(kj::StringPtr name) { - return importCap(name).castAs(); -} - -} // namespace capnp - -#endif // CAPNP_EZ_RPC_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_EZ_RPC_H_ +#define CAPNP_EZ_RPC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "rpc.h" +#include "message.h" + +struct sockaddr; + +namespace kj { class AsyncIoProvider; class LowLevelAsyncIoProvider; } + +namespace capnp { + +class EzRpcContext; + +class EzRpcClient { + // Super-simple interface for setting up a Cap'n Proto RPC client. Example: + // + // # Cap'n Proto schema + // interface Adder { + // add @0 (left :Int32, right :Int32) -> (value :Int32); + // } + // + // // C++ client + // int main() { + // capnp::EzRpcClient client("localhost:3456"); + // Adder::Client adder = client.getMain(); + // auto request = adder.addRequest(); + // request.setLeft(12); + // request.setRight(34); + // auto response = request.send().wait(client.getWaitScope()); + // assert(response.getValue() == 46); + // return 0; + // } + // + // // C++ server + // class AdderImpl final: public Adder::Server { + // public: + // kj::Promise add(AddContext context) override { + // auto params = context.getParams(); + // context.getResults().setValue(params.getLeft() + params.getRight()); + // return kj::READY_NOW; + // } + // }; + // + // int main() { + // capnp::EzRpcServer server(kj::heap(), "*:3456"); + // kj::NEVER_DONE.wait(server.getWaitScope()); + // } + // + // This interface is easy, but it hides a lot of useful features available from the lower-level + // classes: + // - The server can only export a small set of public, singleton capabilities under well-known + // string names. This is fine for transient services where no state needs to be kept between + // connections, but hides the power of Cap'n Proto when it comes to long-lived resources. + // - EzRpcClient/EzRpcServer automatically set up a `kj::EventLoop` and make it current for the + // thread. Only one `kj::EventLoop` can exist per thread, so you cannot use these interfaces + // if you wish to set up your own event loop. (However, you can safely create multiple + // EzRpcClient / EzRpcServer objects in a single thread; they will make sure to make no more + // than one EventLoop.) + // - These classes only support simple two-party connections, not multilateral VatNetworks. + // - These classes only support communication over a raw, unencrypted socket. If you want to + // build on an abstract stream (perhaps one which supports encryption), you must use the + // lower-level interfaces. + // + // Some of these restrictions will probably be lifted in future versions, but some things will + // always require using the low-level interfaces directly. If you are interested in working + // at a lower level, start by looking at these interfaces: + // - `kj::setupAsyncIo()` in `kj/async-io.h`. + // - `RpcSystem` in `capnp/rpc.h`. + // - `TwoPartyVatNetwork` in `capnp/rpc-twoparty.h`. + +public: + explicit EzRpcClient(kj::StringPtr serverAddress, uint defaultPort = 0, + ReaderOptions readerOpts = ReaderOptions()); + // Construct a new EzRpcClient and connect to the given address. The connection is formed in + // the background -- if it fails, calls to capabilities returned by importCap() will fail with an + // appropriate exception. + // + // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. + // If unspecified, the port is required in `serverAddress`. + // + // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info + // on the address format, but basically it's what you'd expect. + // + // `readerOpts` is the ReaderOptions structure used to read each incoming message on the + // connection. Setting this may be necessary if you need to receive very large individual + // messages or messages. However, it is recommended that you instead think about how to change + // your protocol to send large data blobs in multiple small chunks -- this is much better for + // both security and performance. See `ReaderOptions` in `message.h` for more details. + + EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()); + // Like the above constructor, but connects to an already-resolved socket address. Any address + // format supported by `kj::Network` in `kj/async-io.h` is accepted. + + explicit EzRpcClient(int socketFd, ReaderOptions readerOpts = ReaderOptions()); + // Create a client on top of an already-connected socket. + // `readerOpts` acts as in the first constructor. + + ~EzRpcClient() noexcept(false); + + template + typename Type::Client getMain(); + Capability::Client getMain(); + // Get the server's main (aka "bootstrap") interface. + + template + typename Type::Client importCap(kj::StringPtr name) + KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); + Capability::Client importCap(kj::StringPtr name) + KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); + // ** DEPRECATED ** + // + // Ask the sever for the capability with the given name. You may specify a type to automatically + // down-cast to that type. It is up to you to specify the correct expected type. + // + // Named interfaces are deprecated. The new preferred usage pattern is for the server to export + // a "main" interface which itself has methods for getting any other interfaces. + + kj::WaitScope& getWaitScope(); + // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on + // promises. + + kj::AsyncIoProvider& getIoProvider(); + // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want + // to do some non-RPC I/O in asynchronous fashion. + + kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); + // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you + // want to do some non-RPC I/O in asynchronous fashion. + +private: + struct Impl; + kj::Own impl; +}; + +class EzRpcServer { + // The server counterpart to `EzRpcClient`. See `EzRpcClient` for an example. + +public: + explicit EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress, + uint defaultPort = 0, ReaderOptions readerOpts = ReaderOptions()); + // Construct a new `EzRpcServer` that binds to the given address. An address of "*" means to + // bind to all local addresses. + // + // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. + // If unspecified, a port is chosen automatically, and you must call getPort() to find out what + // it is. + // + // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info + // on the address format, but basically it's what you'd expect. + // + // The server might not begin listening immediately, especially if `bindAddress` needs to be + // resolved. If you need to wait until the server is definitely up, wait on the promise returned + // by `getPort()`. + // + // `readerOpts` is the ReaderOptions structure used to read each incoming message on the + // connection. Setting this may be necessary if you need to receive very large individual + // messages or messages. However, it is recommended that you instead think about how to change + // your protocol to send large data blobs in multiple small chunks -- this is much better for + // both security and performance. See `ReaderOptions` in `message.h` for more details. + + EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()); + // Like the above constructor, but binds to an already-resolved socket address. Any address + // format supported by `kj::Network` in `kj/async-io.h` is accepted. + + EzRpcServer(Capability::Client mainInterface, int socketFd, uint port, + ReaderOptions readerOpts = ReaderOptions()); + // Create a server on top of an already-listening socket (i.e. one on which accept() may be + // called). `port` is returned by `getPort()` -- it serves no other purpose. + // `readerOpts` acts as in the other two above constructors. + + explicit EzRpcServer(kj::StringPtr bindAddress, uint defaultPort = 0, + ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + EzRpcServer(struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + + ~EzRpcServer() noexcept(false); + + void exportCap(kj::StringPtr name, Capability::Client cap); + // Export a capability publicly under the given name, so that clients can import it. + // + // Keep in mind that you can implicitly convert `kj::Own&&` to + // `Capability::Client`, so it's typical to pass something like + // `kj::heap()` as the second parameter. + + kj::Promise getPort(); + // Get the IP port number on which this server is listening. This promise won't resolve until + // the server is actually listening. If the address was not an IP address (e.g. it was a Unix + // domain socket) then getPort() resolves to zero. + + kj::WaitScope& getWaitScope(); + // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on + // promises. + + kj::AsyncIoProvider& getIoProvider(); + // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want + // to do some non-RPC I/O in asynchronous fashion. + + kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); + // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you + // want to do some non-RPC I/O in asynchronous fashion. + +private: + struct Impl; + kj::Own impl; +}; + +// ======================================================================================= +// inline implementation details + +template +inline typename Type::Client EzRpcClient::getMain() { + return getMain().castAs(); +} + +template +inline typename Type::Client EzRpcClient::importCap(kj::StringPtr name) { + return importCap(name).castAs(); +} + +} // namespace capnp + +#endif // CAPNP_EZ_RPC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/generated-header-support.h --- a/osx/include/capnp/generated-header-support.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/generated-header-support.h Mon May 22 10:01:37 2017 +0100 @@ -1,585 +1,407 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file is included form all generated headers. - -#ifndef CAPNP_GENERATED_HEADER_SUPPORT_H_ -#define CAPNP_GENERATED_HEADER_SUPPORT_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "layout.h" -#include "list.h" -#include "orphan.h" -#include "pointer-helpers.h" -#include "any.h" -#include -#include - -namespace capnp { - -class MessageBuilder; // So that it can be declared a friend. - -template -struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. - -struct DynamicStruct; // So that it can be declared a friend. - -struct Capability; // To declare brandBindingFor() - -namespace _ { // private - -#if !CAPNP_LITE - -struct RawSchema; - -struct RawBrandedSchema { - // Represents a combination of a schema and bindings for its generic parameters. - // - // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for - // every _instance_ of a generic type -- or, at least, every instance that is actually used. For - // generated-code types, we use template magic to initialize these. - - const RawSchema* generic; - // Generic type which we're branding. - - struct Binding { - uint8_t which; // Numeric value of one of schema::Type::Which. - - bool isImplicitParameter; - // For AnyPointer, true if it's an implicit method parameter. - - uint16_t listDepth; // Number of times to wrap the base type in List(). - - uint16_t paramIndex; - // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter - // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric - // value of one of schema::Type::AnyPointer::Unconstrained::Which. - - union { - const RawBrandedSchema* schema; // for struct, enum, interface - uint64_t scopeId; // for AnyPointer, if it's a type parameter - }; - - Binding() = default; - inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) - : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0), - schema(schema) {} - inline constexpr Binding(uint8_t which, uint16_t listDepth, - uint64_t scopeId, uint16_t paramIndex) - : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex), - scopeId(scopeId) {} - inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex) - : which(which), isImplicitParameter(true), listDepth(listDepth), - paramIndex(implicitParamIndex), scopeId(0) {} - }; - - struct Scope { - uint64_t typeId; - // Type ID whose parameters are being bound. - - const Binding* bindings; - uint bindingCount; - // Bindings for those parameters. - - bool isUnbound; - // This scope is unbound, in the sense of SchemaLoader::getUnbound(). - }; - - const Scope* scopes; - // Array of enclosing scopes for which generic variables have been bound, sorted by type ID. - - struct Dependency { - uint location; - const RawBrandedSchema* schema; - }; - - const Dependency* dependencies; - // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that - // are branded are included in this map; if a dependency is missing, use its `defaultBrand`. - - uint32_t scopeCount; - uint32_t dependencyCount; - - enum class DepKind { - // Component of a Dependency::location. Specifies what sort of dependency this is. - - INVALID, - // Mostly defined to ensure that zero is not a valid location. - - FIELD, - // Binding needed for a field's type. The index is the field index (NOT ordinal!). - - METHOD_PARAMS, - // Bindings needed for a method's params type. The index is the method number. - - METHOD_RESULTS, - // Bindings needed for a method's results type. The index is the method ordinal. - - SUPERCLASS, - // Bindings needed for a superclass type. The index is the superclass's index in the - // "extends" list. - - CONST_TYPE - // Bindings needed for the type of a constant. The index is zero. - }; - - static inline uint makeDepLocation(DepKind kind, uint index) { - // Make a number representing the location of a particular dependency within its parent - // schema. - - return (static_cast(kind) << 24) | index; - } - - class Initializer { - public: - virtual void init(const RawBrandedSchema* generic) 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); - } - - inline bool isUnbound() const; - // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case - // binding lookups need to be handled specially. -}; - -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(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. - - const uint16_t* 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 uint16_t* membersByDiscriminant; - // List of all member indexes ordered by discriminant value. Those which don't have a - // discriminant value are listed at the end, in order by ordinal. - - 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); - } - - RawBrandedSchema defaultBrand; - // Specifies the brand to use for this schema if no generic parameters have been bound to - // anything. Generally, in the default brand, all generic parameters are treated as if they were - // bound to `AnyPointer`. -}; - -inline bool RawBrandedSchema::isUnbound() const { - // The unbound schema is the only one that has no scopes but is not the default schema. - return scopeCount == 0 && this != &generic->defaultBrand; -} - -template -inline const RawSchema& rawSchema() { - return *CapnpPrivate::schema; -} -template ::typeId> -inline const RawSchema& rawSchema() { - return *schemas::EnumInfo::schema; -} - -template -inline const RawBrandedSchema& rawBrandedSchema() { - return *CapnpPrivate::brand; -} -template ::typeId> -inline const RawBrandedSchema& rawBrandedSchema() { - return schemas::EnumInfo::schema->defaultBrand; -} - -template -struct ChooseBrand; -// If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a -// specific brand instance. TypeTag is the _capnpPrivate struct for the type in question. - -template -struct ChooseBrand { - // All params were AnyPointer. No specific brand needed. - static constexpr _::RawBrandedSchema const* brand = &TypeTag::schema->defaultBrand; -}; - -template -struct ChooseBrand: public ChooseBrand {}; -// The first parameter is AnyPointer, so recurse to check the rest. - -template -struct ChooseBrand { - // At least one parameter is not AnyPointer, so use the specificBrand constant. - static constexpr _::RawBrandedSchema const* brand = &TypeTag::specificBrand; -}; - -template ()> -struct BrandBindingFor_; - -#define HANDLE_TYPE(Type, which) \ - template <> \ - struct BrandBindingFor_ { \ - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \ - return { which, listDepth, nullptr }; \ - } \ - } -HANDLE_TYPE(Void, 0); -HANDLE_TYPE(bool, 1); -HANDLE_TYPE(int8_t, 2); -HANDLE_TYPE(int16_t, 3); -HANDLE_TYPE(int32_t, 4); -HANDLE_TYPE(int64_t, 5); -HANDLE_TYPE(uint8_t, 6); -HANDLE_TYPE(uint16_t, 7); -HANDLE_TYPE(uint32_t, 8); -HANDLE_TYPE(uint64_t, 9); -HANDLE_TYPE(float, 10); -HANDLE_TYPE(double, 11); -#undef HANDLE_TYPE - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 12, listDepth, nullptr }; - } -}; - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 13, listDepth, nullptr }; - } -}; - -template -struct BrandBindingFor_, Kind::LIST> { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return BrandBindingFor_::get(listDepth + 1); - } -}; - -template -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 15, listDepth, nullptr }; - } -}; - -template -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 16, listDepth, T::_capnpPrivate::brand }; - } -}; - -template -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 17, listDepth, T::_capnpPrivate::brand }; - } -}; - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 18, listDepth, 0, 0 }; - } -}; - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 18, listDepth, 0, 1 }; - } -}; - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 18, listDepth, 0, 2 }; - } -}; - -template <> -struct BrandBindingFor_ { - static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { - return { 18, listDepth, 0, 3 }; - } -}; - -template -constexpr RawBrandedSchema::Binding brandBindingFor() { - return BrandBindingFor_::get(0); -} - -kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema); -kj::String enumString(uint16_t value, const RawBrandedSchema& schema); -// 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 -inline kj::StringTree structString(StructReader reader) { - return structString(reader, rawBrandedSchema()); -} -template -inline kj::String enumString(T value) { - return enumString(static_cast(value), rawBrandedSchema()); -} - -#endif // !CAPNP_LITE - -// TODO(cleanup): Unify ConstStruct and ConstList. -template -class ConstStruct { -public: - ConstStruct() = delete; - KJ_DISALLOW_COPY(ConstStruct); - inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {} - - inline typename T::Reader get() const { - return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs(); - } - - inline operator typename T::Reader() const { return get(); } - inline typename T::Reader operator*() const { return get(); } - inline TemporaryPointer operator->() const { return get(); } - -private: - const word* ptr; -}; - -template -class ConstList { -public: - ConstList() = delete; - KJ_DISALLOW_COPY(ConstList); - inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {} - - inline typename List::Reader get() const { - return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs>(); - } - - inline operator typename List::Reader() const { return get(); } - inline typename List::Reader operator*() const { return get(); } - inline TemporaryPointer::Reader> operator->() const { return get(); } - -private: - const word* ptr; -}; - -template -class ConstText { -public: - ConstText() = delete; - KJ_DISALLOW_COPY(ConstText); - inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {} - - inline Text::Reader get() const { - return Text::Reader(reinterpret_cast(ptr), size); - } - - inline operator Text::Reader() const { return get(); } - inline Text::Reader operator*() const { return get(); } - inline TemporaryPointer operator->() const { return get(); } - - inline kj::StringPtr toString() const { - return get(); - } - -private: - const word* ptr; -}; - -template -inline kj::StringPtr KJ_STRINGIFY(const ConstText& s) { - return s.get(); -} - -template -class ConstData { -public: - ConstData() = delete; - KJ_DISALLOW_COPY(ConstData); - inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {} - - inline Data::Reader get() const { - return Data::Reader(reinterpret_cast(ptr), size); - } - - inline operator Data::Reader() const { return get(); } - inline Data::Reader operator*() const { return get(); } - inline TemporaryPointer operator->() const { return get(); } - -private: - const word* ptr; -}; - -template -inline auto KJ_STRINGIFY(const ConstData& s) -> decltype(kj::toCharSequence(s.get())) { - return kj::toCharSequence(s.get()); -} - -} // namespace _ (private) - -template -inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; } -template ::typeId> -inline constexpr uint64_t typeId() { return id; } -// typeId() returns the type ID as defined in the schema. Works with structs, enums, and -// interfaces. - -template -inline constexpr uint sizeInWords() { - // Return the size, in words, of a Struct type, if allocated free-standing (not in a list). - // May be useful for pre-computing space needed in order to precisely allocate messages. - - return (WordCount32(_::structSize().data) + - _::structSize().pointers * WORDS_PER_POINTER) / WORDS; -} - -} // namespace capnp - -#if _MSC_VER -// MSVC doesn't understand floating-point constexpr yet. -// -// TODO(msvc): Remove this hack when MSVC is fixed. -#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) -#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value -#else -#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value -#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) -#endif - -#if CAPNP_LITE - -#define CAPNP_DECLARE_SCHEMA(id) \ - extern ::capnp::word const* const bp_##id - -#define CAPNP_DECLARE_ENUM(type, id) \ - inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ - return ::kj::str(static_cast(value)); \ - } \ - template <> struct EnumInfo { \ - struct IsEnum; \ - static constexpr uint64_t typeId = 0x##id; \ - static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ - } - -#if _MSC_VER -// TODO(msvc): MSVC dosen't expect constexprs to have definitions. -#define CAPNP_DEFINE_ENUM(type, id) -#else -#define CAPNP_DEFINE_ENUM(type, id) \ - constexpr uint64_t EnumInfo::typeId -#endif - -#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ - struct IsStruct; \ - static constexpr uint64_t typeId = 0x##id; \ - static constexpr uint16_t dataWordSize = dataWordSize_; \ - static constexpr uint16_t pointerCount = pointerCount_; \ - static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } - -#else // CAPNP_LITE - -#define CAPNP_DECLARE_SCHEMA(id) \ - extern ::capnp::word const* const bp_##id; \ - extern const ::capnp::_::RawSchema s_##id - -#define CAPNP_DECLARE_ENUM(type, id) \ - inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ - return ::capnp::_::enumString(value); \ - } \ - template <> struct EnumInfo { \ - struct IsEnum; \ - static constexpr uint64_t typeId = 0x##id; \ - static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ - static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \ - } -#define CAPNP_DEFINE_ENUM(type, id) \ - constexpr uint64_t EnumInfo::typeId; \ - constexpr ::capnp::_::RawSchema const* EnumInfo::schema - -#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ - struct IsStruct; \ - static constexpr uint64_t typeId = 0x##id; \ - static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \ - static constexpr uint16_t dataWordSize = dataWordSize_; \ - static constexpr uint16_t pointerCount = pointerCount_; \ - static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ - static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; - -#define CAPNP_DECLARE_INTERFACE_HEADER(id) \ - struct IsInterface; \ - static constexpr uint64_t typeId = 0x##id; \ - static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \ - static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ - static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; - -#endif // CAPNP_LITE, else - -#endif // CAPNP_GENERATED_HEADER_SUPPORT_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file is included from all generated headers. + +#ifndef CAPNP_GENERATED_HEADER_SUPPORT_H_ +#define CAPNP_GENERATED_HEADER_SUPPORT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "raw-schema.h" +#include "layout.h" +#include "list.h" +#include "orphan.h" +#include "pointer-helpers.h" +#include "any.h" +#include +#include + +namespace capnp { + +class MessageBuilder; // So that it can be declared a friend. + +template +struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. + +struct DynamicStruct; // So that it can be declared a friend. + +struct Capability; // To declare brandBindingFor() + +namespace _ { // private + +#if !CAPNP_LITE + +template +inline const RawSchema& rawSchema() { + return *CapnpPrivate::schema; +} +template ::typeId> +inline const RawSchema& rawSchema() { + return *schemas::EnumInfo::schema; +} + +template +inline const RawBrandedSchema& rawBrandedSchema() { + return *CapnpPrivate::brand(); +} +template ::typeId> +inline const RawBrandedSchema& rawBrandedSchema() { + return schemas::EnumInfo::schema->defaultBrand; +} + +template +struct ChooseBrand; +// If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a +// specific brand instance. TypeTag is the _capnpPrivate struct for the type in question. + +template +struct ChooseBrand { + // All params were AnyPointer. No specific brand needed. + static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; } +}; + +template +struct ChooseBrand: public ChooseBrand {}; +// The first parameter is AnyPointer, so recurse to check the rest. + +template +struct ChooseBrand { + // At least one parameter is not AnyPointer, so use the specificBrand constant. + static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::specificBrand; } +}; + +template ()> +struct BrandBindingFor_; + +#define HANDLE_TYPE(Type, which) \ + template <> \ + struct BrandBindingFor_ { \ + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \ + return { which, listDepth, nullptr }; \ + } \ + } +HANDLE_TYPE(Void, 0); +HANDLE_TYPE(bool, 1); +HANDLE_TYPE(int8_t, 2); +HANDLE_TYPE(int16_t, 3); +HANDLE_TYPE(int32_t, 4); +HANDLE_TYPE(int64_t, 5); +HANDLE_TYPE(uint8_t, 6); +HANDLE_TYPE(uint16_t, 7); +HANDLE_TYPE(uint32_t, 8); +HANDLE_TYPE(uint64_t, 9); +HANDLE_TYPE(float, 10); +HANDLE_TYPE(double, 11); +#undef HANDLE_TYPE + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 12, listDepth, nullptr }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 13, listDepth, nullptr }; + } +}; + +template +struct BrandBindingFor_, Kind::LIST> { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return BrandBindingFor_::get(listDepth + 1); + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 15, listDepth, nullptr }; + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 16, listDepth, T::_capnpPrivate::brand() }; + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 17, listDepth, T::_capnpPrivate::brand() }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 0 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 1 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 2 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 3 }; + } +}; + +template +constexpr RawBrandedSchema::Binding brandBindingFor() { + return BrandBindingFor_::get(0); +} + +kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema); +kj::String enumString(uint16_t value, const RawBrandedSchema& schema); +// 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 +inline kj::StringTree structString(StructReader reader) { + return structString(reader, rawBrandedSchema()); +} +template +inline kj::String enumString(T value) { + return enumString(static_cast(value), rawBrandedSchema()); +} + +#endif // !CAPNP_LITE + +// TODO(cleanup): Unify ConstStruct and ConstList. +template +class ConstStruct { +public: + ConstStruct() = delete; + KJ_DISALLOW_COPY(ConstStruct); + inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {} + + inline typename T::Reader get() const { + return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs(); + } + + inline operator typename T::Reader() const { return get(); } + inline typename T::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +class ConstList { +public: + ConstList() = delete; + KJ_DISALLOW_COPY(ConstList); + inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {} + + inline typename List::Reader get() const { + return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs>(); + } + + inline operator typename List::Reader() const { return get(); } + inline typename List::Reader operator*() const { return get(); } + inline TemporaryPointer::Reader> operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +class ConstText { +public: + ConstText() = delete; + KJ_DISALLOW_COPY(ConstText); + inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {} + + inline Text::Reader get() const { + return Text::Reader(reinterpret_cast(ptr), size); + } + + inline operator Text::Reader() const { return get(); } + inline Text::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + + inline kj::StringPtr toString() const { + return get(); + } + +private: + const word* ptr; +}; + +template +inline kj::StringPtr KJ_STRINGIFY(const ConstText& s) { + return s.get(); +} + +template +class ConstData { +public: + ConstData() = delete; + KJ_DISALLOW_COPY(ConstData); + inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {} + + inline Data::Reader get() const { + return Data::Reader(reinterpret_cast(ptr), size); + } + + inline operator Data::Reader() const { return get(); } + inline Data::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +inline auto KJ_STRINGIFY(const ConstData& s) -> decltype(kj::toCharSequence(s.get())) { + return kj::toCharSequence(s.get()); +} + +} // namespace _ (private) + +template +inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; } +template ::typeId> +inline constexpr uint64_t typeId() { return id; } +// typeId() returns the type ID as defined in the schema. Works with structs, enums, and +// interfaces. + +template +inline constexpr uint sizeInWords() { + // Return the size, in words, of a Struct type, if allocated free-standing (not in a list). + // May be useful for pre-computing space needed in order to precisely allocate messages. + + return unbound((upgradeBound(_::structSize().data) + + _::structSize().pointers * WORDS_PER_POINTER) / WORDS); +} + +} // namespace capnp + +#if _MSC_VER +// MSVC doesn't understand floating-point constexpr yet. +// +// TODO(msvc): Remove this hack when MSVC is fixed. +#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) +#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value +#else +#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value +#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) +#endif + +#if _MSC_VER +// TODO(msvc): A little hack to allow MSVC to use C++14 return type deduction in cases where the +// explicit type exposes bugs in the compiler. +#define CAPNP_AUTO_IF_MSVC(...) auto +#else +#define CAPNP_AUTO_IF_MSVC(...) __VA_ARGS__ +#endif + +#if CAPNP_LITE + +#define CAPNP_DECLARE_SCHEMA(id) \ + extern ::capnp::word const* const bp_##id + +#define CAPNP_DECLARE_ENUM(type, id) \ + inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ + return ::kj::str(static_cast(value)); \ + } \ + template <> struct EnumInfo { \ + struct IsEnum; \ + static constexpr uint64_t typeId = 0x##id; \ + static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ + } + +#if _MSC_VER +// TODO(msvc): MSVC dosen't expect constexprs to have definitions. +#define CAPNP_DEFINE_ENUM(type, id) +#else +#define CAPNP_DEFINE_ENUM(type, id) \ + constexpr uint64_t EnumInfo::typeId +#endif + +#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ + struct IsStruct; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr uint16_t dataWordSize = dataWordSize_; \ + static constexpr uint16_t pointerCount = pointerCount_; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } + +#else // CAPNP_LITE + +#define CAPNP_DECLARE_SCHEMA(id) \ + extern ::capnp::word const* const bp_##id; \ + extern const ::capnp::_::RawSchema s_##id + +#define CAPNP_DECLARE_ENUM(type, id) \ + inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ + return ::capnp::_::enumString(value); \ + } \ + template <> struct EnumInfo { \ + struct IsEnum; \ + static constexpr uint64_t typeId = 0x##id; \ + static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \ + } +#define CAPNP_DEFINE_ENUM(type, id) \ + constexpr uint64_t EnumInfo::typeId; \ + constexpr ::capnp::_::RawSchema const* EnumInfo::schema + +#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ + struct IsStruct; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \ + static constexpr uint16_t dataWordSize = dataWordSize_; \ + static constexpr uint16_t pointerCount = pointerCount_; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; + +#define CAPNP_DECLARE_INTERFACE_HEADER(id) \ + struct IsInterface; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; + +#endif // CAPNP_LITE, else + +#endif // CAPNP_GENERATED_HEADER_SUPPORT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/json.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/capnp/json.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,58 @@ +# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x8ef99297a43a5e34; + +$import "/capnp/c++.capnp".namespace("capnp"); + +struct JsonValue { + union { + null @0 :Void; + boolean @1 :Bool; + number @2 :Float64; + string @3 :Text; + array @4 :List(JsonValue); + object @5 :List(Field); + # Standard JSON values. + + call @6 :Call; + # Non-standard: A "function call", applying a named function (named by a single identifier) + # to a parameter list. Examples: + # + # BinData(0, "Zm9vCg==") + # ISODate("2015-04-15T08:44:50.218Z") + # + # Mongo DB users will recognize the above as exactly the syntax Mongo uses to represent BSON + # "binary" and "date" types in text, since JSON has no analog of these. This is basically the + # reason this extension exists. We do NOT recommend using `call` unless you specifically need + # to be compatible with some silly format that uses this syntax. + } + + struct Field { + name @0 :Text; + value @1 :JsonValue; + } + + struct Call { + function @0 :Text; + params @1 :List(JsonValue); + } +} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/layout.h --- a/osx/include/capnp/layout.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/layout.h Mon May 22 10:01:37 2017 +0100 @@ -1,1225 +1,1274 @@ -// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file is NOT intended for use by clients, except in generated code. -// -// This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout -// (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, -// as does other parts of the Cap'n proto library which provide a higher-level interface for -// dynamic introspection. - -#ifndef CAPNP_LAYOUT_H_ -#define CAPNP_LAYOUT_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include -#include "common.h" -#include "blob.h" -#include "endian.h" - -#if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) -#define CAPNP_CANONICALIZE_NAN 1 -// Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by -// __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN -// signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in -// particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. -// Canonicalizing them makes output consistent (which is important!), but hurts performance -// slightly. -// -// Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. -// Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. -// everyone else. It would be great if we could just flip that bit, but we can't, because if the -// significand is all-zero, then the value is infinity rather than NaN. This means that on most -// machines, where the bit indicates quietness, there is one more quiet NaN value than signalling -// NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic -// mapping that properly preserves quietness. Instead of doing something hacky, we just give up -// and blow away NaN payloads, because no one uses them anyway. -#endif - -namespace capnp { - -#if !CAPNP_LITE -class ClientHook; -#endif // !CAPNP_LITE - -namespace _ { // private - -class PointerBuilder; -class PointerReader; -class StructBuilder; -class StructReader; -class ListBuilder; -class ListReader; -class OrphanBuilder; -struct WirePointer; -struct WireHelpers; -class SegmentReader; -class SegmentBuilder; -class Arena; -class BuilderArena; - -// ============================================================================= - -typedef decltype(BITS / ELEMENTS) BitsPerElement; -typedef decltype(POINTERS / ELEMENTS) PointersPerElement; - -static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = { - 0 * BITS / ELEMENTS, - 1 * BITS / ELEMENTS, - 8 * BITS / ELEMENTS, - 16 * BITS / ELEMENTS, - 32 * BITS / ELEMENTS, - 64 * BITS / ELEMENTS, - 0 * BITS / ELEMENTS, - 0 * BITS / ELEMENTS -}; - -inline KJ_CONSTEXPR() BitsPerElement dataBitsPerElement(ElementSize size) { - return _::BITS_PER_ELEMENT_TABLE[static_cast(size)]; -} - -inline constexpr PointersPerElement pointersPerElement(ElementSize size) { - return size == ElementSize::POINTER ? 1 * POINTERS / ELEMENTS : 0 * POINTERS / ELEMENTS; -} - -template struct ElementSizeForByteSize; -template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; -template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; -template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; -template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; - -template struct ElementSizeForType { - static constexpr ElementSize value = - // Primitive types that aren't special-cased below can be determined from sizeof(). - CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize::value : - CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : - CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : - - // Everything else is a pointer. - ElementSize::POINTER; -}; - -// Void and bool are special. -template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::VOID; }; -template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::BIT; }; - -// Lists and blobs are pointers, not structs. -template struct ElementSizeForType> { - static constexpr ElementSize value = ElementSize::POINTER; -}; -template <> struct ElementSizeForType { - static constexpr ElementSize value = ElementSize::POINTER; -}; -template <> struct ElementSizeForType { - static constexpr ElementSize value = ElementSize::POINTER; -}; - -template -inline constexpr ElementSize elementSizeForType() { - return ElementSizeForType::value; -} - -struct MessageSizeCounts { - WordCount64 wordCount; - uint capCount; - - MessageSizeCounts& operator+=(const MessageSizeCounts& other) { - wordCount += other.wordCount; - capCount += other.capCount; - return *this; - } - - MessageSize asPublic() { - return MessageSize { wordCount / WORDS, capCount }; - } -}; - -// ============================================================================= - -template -union AlignedData { - // Useful for declaring static constant data blobs as an array of bytes, but forcing those - // bytes to be word-aligned. - - uint8_t bytes[wordCount * sizeof(word)]; - word words[wordCount]; -}; - -struct StructSize { - WordCount16 data; - WirePointerCount16 pointers; - - inline constexpr WordCount total() const { return data + pointers * WORDS_PER_POINTER; } - - StructSize() = default; - inline constexpr StructSize(WordCount data, WirePointerCount pointers) - : data(data), pointers(pointers) {} -}; - -template -inline constexpr StructSize structSize() { - return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); -} - -template > -inline constexpr StructSize minStructSizeForElement() { - // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough - // to hold a T. - - return StructSize(CapnpPrivate::dataWordSize * WORDS, CapnpPrivate::pointerCount * POINTERS); -} - -template > -inline constexpr StructSize minStructSizeForElement() { - // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough - // to hold a T. - - return StructSize( - dataBitsPerElement(elementSizeForType()) * ELEMENTS > 0 * BITS ? 1 * WORDS : 0 * WORDS, - pointersPerElement(elementSizeForType()) * ELEMENTS); -} - -// ------------------------------------------------------------------- -// Masking of default values - -template struct Mask_; -template struct Mask_ { typedef T Type; }; -template struct Mask_ { typedef uint16_t Type; }; -template <> struct Mask_ { typedef uint32_t Type; }; -template <> struct Mask_ { typedef uint64_t Type; }; - -template struct Mask_ { - // Union discriminants end up here. - static_assert(sizeof(T) == 2, "Don't know how to mask this type."); - typedef uint16_t Type; -}; - -template -using Mask = typename Mask_::Type; - -template -KJ_ALWAYS_INLINE(Mask mask(T value, Mask mask)); -template -KJ_ALWAYS_INLINE(T unmask(Mask value, Mask mask)); - -template -inline Mask mask(T value, Mask mask) { - return static_cast >(value) ^ mask; -} - -template <> -inline uint32_t mask(float value, uint32_t mask) { -#if CAPNP_CANONICALIZE_NAN - if (value != value) { - return 0x7fc00000u ^ mask; - } -#endif - - uint32_t i; - static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); - memcpy(&i, &value, sizeof(value)); - return i ^ mask; -} - -template <> -inline uint64_t mask(double value, uint64_t mask) { -#if CAPNP_CANONICALIZE_NAN - if (value != value) { - return 0x7ff8000000000000ull ^ mask; - } -#endif - - uint64_t i; - static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); - memcpy(&i, &value, sizeof(value)); - return i ^ mask; -} - -template -inline T unmask(Mask value, Mask mask) { - return static_cast(value ^ mask); -} - -template <> -inline float unmask(uint32_t value, uint32_t mask) { - value ^= mask; - float result; - static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); - memcpy(&result, &value, sizeof(value)); - return result; -} - -template <> -inline double unmask(uint64_t value, uint64_t mask) { - value ^= mask; - double result; - static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); - memcpy(&result, &value, sizeof(value)); - return result; -} - -// ------------------------------------------------------------------- - -class CapTableReader { -public: -#if !CAPNP_LITE - virtual kj::Maybe> extractCap(uint index) = 0; - // Extract the capability at the given index. If the index is invalid, returns null. -#endif // !CAPNP_LITE -}; - -class CapTableBuilder: public CapTableReader { -public: -#if !CAPNP_LITE - virtual uint injectCap(kj::Own&& cap) = 0; - // Add the capability to the message and return its index. If the same ClientHook is injected - // twice, this may return the same index both times, but in this case dropCap() needs to be - // called an equal number of times to actually remove the cap. - - virtual void dropCap(uint index) = 0; - // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. -#endif // !CAPNP_LITE -}; - -// ------------------------------------------------------------------- - -class PointerBuilder: public kj::DisallowConstCopy { - // Represents a single pointer, usually embedded in a struct or a list. - -public: - inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} - - static inline PointerBuilder getRoot( - SegmentBuilder* segment, CapTableBuilder* capTable, word* location); - // Get a PointerBuilder representing a message root located in the given segment at the given - // location. - - inline bool isNull() { return getPointerType() == PointerType::NULL_; } - PointerType getPointerType(); - - StructBuilder getStruct(StructSize size, const word* defaultValue); - ListBuilder getList(ElementSize elementSize, const word* defaultValue); - ListBuilder getStructList(StructSize elementSize, const word* defaultValue); - ListBuilder getListAnySize(const word* defaultValue); - template typename T::Builder getBlob(const void* defaultValue,ByteCount defaultSize); -#if !CAPNP_LITE - kj::Own getCapability(); -#endif // !CAPNP_LITE - // Get methods: Get the value. If it is null, initialize it to a copy of the default value. - // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a - // simple byte array for blobs. - - StructBuilder initStruct(StructSize size); - ListBuilder initList(ElementSize elementSize, ElementCount elementCount); - ListBuilder initStructList(ElementCount elementCount, StructSize size); - template typename T::Builder initBlob(ByteCount size); - // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing - // object. - - void setStruct(const StructReader& value, bool canonical = false); - void setList(const ListReader& value, bool canonical = false); - template void setBlob(typename T::Reader value); -#if !CAPNP_LITE - void setCapability(kj::Own&& cap); -#endif // !CAPNP_LITE - // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding - // the existing object. - - void adopt(OrphanBuilder&& orphan); - // Set the pointer to point at the given orphaned value. - - OrphanBuilder disown(); - // Set the pointer to null and return its previous value as an orphan. - - void clear(); - // Clear the pointer to null, discarding its previous value. - - void transferFrom(PointerBuilder other); - // Equivalent to `adopt(other.disown())`. - - void copyFrom(PointerReader other, bool canonical = false); - // Equivalent to `set(other.get())`. - // If you set the canonical flag, it will attempt to lay the target out - // canonically, provided enough space is available. - - PointerReader asReader() const; - - BuilderArena* getArena() const; - // Get the arena containing this pointer. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - PointerBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the pointer resides. - CapTableBuilder* capTable; // Table of capability indexes. - WirePointer* pointer; // Pointer to the pointer. - - inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) - : segment(segment), capTable(capTable), pointer(pointer) {} - - friend class StructBuilder; - friend class ListBuilder; - friend class OrphanBuilder; -}; - -class PointerReader { -public: - inline PointerReader() - : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} - - static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, - const word* location, int nestingLimit); - // Get a PointerReader representing a message root located in the given segment at the given - // location. - - static inline PointerReader getRootUnchecked(const word* location); - // Get a PointerReader for an unchecked message. - - MessageSizeCounts targetSize() const; - // Return the total size of the target object and everything to which it points. Does not count - // far pointer overhead. This is useful for deciding how much space is needed to copy the object - // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, - // use the result as a hint for allocating the first segment, do the copy, and then throw an - // exception if it overruns. - - inline bool isNull() const { return getPointerType() == PointerType::NULL_; } - PointerType getPointerType() const; - - StructReader getStruct(const word* defaultValue) const; - ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; - ListReader getListAnySize(const word* defaultValue) const; - template - typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; -#if !CAPNP_LITE - kj::Own getCapability() const; -#endif // !CAPNP_LITE - // Get methods: Get the value. If it is null, return the default value instead. - // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a - // simple byte array for blobs. - - const word* getUnchecked() const; - // If this is an unchecked message, get a word* pointing at the location of the pointer. This - // word* can actually be passed to readUnchecked() to read the designated sub-object later. If - // this isn't an unchecked message, throws an exception. - - kj::Maybe getArena() const; - // Get the arena containing this pointer. - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - PointerReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - -private: - SegmentReader* segment; // Memory segment in which the pointer resides. - CapTableReader* capTable; // Table of capability indexes. - const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - - inline PointerReader(SegmentReader* segment, CapTableReader* capTable, - const WirePointer* pointer, int nestingLimit) - : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} - - friend class StructReader; - friend class ListReader; - friend class PointerBuilder; - friend class OrphanBuilder; -}; - -// ------------------------------------------------------------------- - -class StructBuilder: public kj::DisallowConstCopy { -public: - inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} - - inline word* getLocation() { return reinterpret_cast(data); } - // Get the object's location. Only valid for independently-allocated objects (i.e. not list - // elements). - - inline BitCount getDataSectionSize() const { return dataSize; } - inline WirePointerCount getPointerSectionSize() const { return pointerCount; } - inline kj::ArrayPtr getDataSectionAsBlob(); - inline _::ListBuilder getPointerSectionAsList(); - - template - KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset)); - // Return true if the field is set to something other than its default value. - - template - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset)); - // Gets the data field value of the given type at the given offset. The offset is measured in - // multiples of the field size, determined by the type. - - template - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset, Mask mask)); - // Like getDataField() but applies the given XOR mask to the data on load. Used for reading - // fields with non-zero default values. - - template - KJ_ALWAYS_INLINE(void setDataField( - ElementCount offset, kj::NoInfer value)); - // Sets the data field value at the given offset. - - template - KJ_ALWAYS_INLINE(void setDataField( - ElementCount offset, kj::NoInfer value, Mask mask)); - // Like setDataField() but applies the given XOR mask before storing. Used for writing fields - // with non-zero default values. - - KJ_ALWAYS_INLINE(PointerBuilder getPointerField(WirePointerCount ptrIndex)); - // Get a builder for a pointer field given the index within the pointer section. - - void clearAll(); - // Clear all pointers and data. - - void transferContentFrom(StructBuilder other); - // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger - // than this, the extra data is not transferred, meaning there is a risk of data loss when - // transferring from messages built with future versions of the protocol. - - void copyContentFrom(StructReader other); - // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not - // copied, meaning there is a risk of data loss when copying from messages built with future - // versions of the protocol. - - StructReader asReader() const; - // Gets a StructReader pointing at the same memory. - - BuilderArena* getArena(); - // Gets the arena in which this object is allocated. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - StructBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the struct resides. - CapTableBuilder* capTable; // Table of capability indexes. - void* data; // Pointer to the encoded data. - WirePointer* pointers; // Pointer to the encoded pointers. - - BitCount32 dataSize; - // Size of data section. We use a bit count rather than a word count to more easily handle the - // case of struct lists encoded with less than a word per element. - - WirePointerCount16 pointerCount; // Size of the pointer section. - - inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, - void* data, WirePointer* pointers, - BitCount dataSize, WirePointerCount pointerCount) - : segment(segment), capTable(capTable), data(data), pointers(pointers), - dataSize(dataSize), pointerCount(pointerCount) {} - - friend class ListBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -class StructReader { -public: - inline StructReader() - : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), dataSize(0), - pointerCount(0), nestingLimit(0x7fffffff) {} - inline StructReader(kj::ArrayPtr data) - : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), - dataSize(data.size() * WORDS * BITS_PER_WORD), pointerCount(0), nestingLimit(0x7fffffff) {} - - const void* getLocation() const { return data; } - - inline BitCount getDataSectionSize() const { return dataSize; } - inline WirePointerCount getPointerSectionSize() const { return pointerCount; } - inline kj::ArrayPtr getDataSectionAsBlob(); - inline _::ListReader getPointerSectionAsList(); - - kj::Array canonicalize(); - - template - KJ_ALWAYS_INLINE(bool hasDataField(ElementCount offset) const); - // Return true if the field is set to something other than its default value. - - template - KJ_ALWAYS_INLINE(T getDataField(ElementCount offset) const); - // Get the data field value of the given type at the given offset. The offset is measured in - // multiples of the field size, determined by the type. Returns zero if the offset is past the - // end of the struct's data section. - - template - KJ_ALWAYS_INLINE( - T getDataField(ElementCount offset, Mask mask) const); - // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading - // fields with non-zero default values. - - KJ_ALWAYS_INLINE(PointerReader getPointerField(WirePointerCount ptrIndex) const); - // Get a reader for a pointer field given the index within the pointer section. If the index - // is out-of-bounds, returns a null pointer. - - MessageSizeCounts totalSize() const; - // Return the total size of the struct and everything to which it points. Does not count far - // pointer overhead. This is useful for deciding how much space is needed to copy the struct - // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, - // use the result as a hint for allocating the first segment, do the copy, and then throw an - // exception if it overruns. - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - StructReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead, const word **ptrHead, - bool *dataTrunc, bool *ptrTrunc); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - // - // If this function returns false, the struct is non-canonical. If it - // returns true, then: - // * If it is a composite in a list, it is canonical if at least one struct - // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 - // * If it is derived from a struct pointer, it is canonical if - // dataTrunc = 1 AND ptrTrunc = 1 - -private: - SegmentReader* segment; // Memory segment in which the struct resides. - CapTableReader* capTable; // Table of capability indexes. - - const void* data; - const WirePointer* pointers; - - BitCount32 dataSize; - // Size of data section. We use a bit count rather than a word count to more easily handle the - // case of struct lists encoded with less than a word per element. - - WirePointerCount16 pointerCount; // Size of the pointer section. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - // TODO(perf): Limit to 16 bits for better packing? - - inline StructReader(SegmentReader* segment, CapTableReader* capTable, - const void* data, const WirePointer* pointers, - BitCount dataSize, WirePointerCount pointerCount, int nestingLimit) - : segment(segment), capTable(capTable), data(data), pointers(pointers), - dataSize(dataSize), pointerCount(pointerCount), - nestingLimit(nestingLimit) {} - - friend class ListReader; - friend class StructBuilder; - friend struct WireHelpers; -}; - -// ------------------------------------------------------------------- - -class ListBuilder: public kj::DisallowConstCopy { -public: - inline explicit ListBuilder(ElementSize elementSize) - : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS), - step(0 * BITS / ELEMENTS), structDataSize(0 * BITS), structPointerCount(0 * POINTERS), - elementSize(elementSize) {} - - inline word* getLocation() { - // Get the object's location. - - if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { - return reinterpret_cast(ptr) - POINTER_SIZE_IN_WORDS; - } else { - return reinterpret_cast(ptr); - } - } - - inline ElementSize getElementSize() const { return elementSize; } - - inline ElementCount size() const; - // The number of elements in the list. - - Text::Builder asText(); - Data::Builder asData(); - // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. - - template - KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); - // Get the element of the given type at the given index. - - template - KJ_ALWAYS_INLINE(void setDataElement( - ElementCount index, kj::NoInfer value)); - // Set the element at the given index. - - KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); - - StructBuilder getStructElement(ElementCount index); - - ListReader asReader() const; - // Get a ListReader pointing at the same memory. - - BuilderArena* getArena(); - // Gets the arena in which this object is allocated. - - CapTableBuilder* getCapTable(); - // Gets the capability context in which this object is operating. - - ListBuilder imbue(CapTableBuilder* capTable); - // Return a copy of this builder except using the given capability context. - -private: - SegmentBuilder* segment; // Memory segment in which the list resides. - CapTableBuilder* capTable; // Table of capability indexes. - - byte* ptr; // Pointer to list content. - - ElementCount elementCount; // Number of elements in the list. - - decltype(BITS / ELEMENTS) step; - // The distance between elements. - - BitCount32 structDataSize; - WirePointerCount16 structPointerCount; - // The struct properties to use when interpreting the elements as structs. All lists can be - // interpreted as struct lists, so these are always filled in. - - ElementSize elementSize; - // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE - // from other types when the overall size is exactly zero or one words. - - inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, - decltype(BITS / ELEMENTS) step, ElementCount size, - BitCount structDataSize, WirePointerCount structPointerCount, - ElementSize elementSize) - : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), - elementCount(size), step(step), structDataSize(structDataSize), - structPointerCount(structPointerCount), elementSize(elementSize) {} - - friend class StructBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -class ListReader { -public: - inline explicit ListReader(ElementSize elementSize) - : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(0), - step(0 * BITS / ELEMENTS), structDataSize(0), structPointerCount(0), - elementSize(elementSize), nestingLimit(0x7fffffff) {} - - inline ElementCount size() const; - // The number of elements in the list. - - inline ElementSize getElementSize() const { return elementSize; } - - Text::Reader asText(); - Data::Reader asData(); - // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. - - kj::ArrayPtr asRawBytes(); - - template - KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); - // Get the element of the given type at the given index. - - KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); - - StructReader getStructElement(ElementCount index) const; - - CapTableReader* getCapTable(); - // Gets the capability context in which this object is operating. - - ListReader imbue(CapTableReader* capTable) const; - // Return a copy of this reader except using the given capability context. - - bool isCanonical(const word **readHead); - // Validate this pointer's canonicity, subject to the conditions: - // * All data to the left of readHead has been read thus far (for pointer - // ordering) - // * All pointers in preorder have already been checked - // * This pointer is in the first and only segment of the message - -private: - SegmentReader* segment; // Memory segment in which the list resides. - CapTableReader* capTable; // Table of capability indexes. - - const byte* ptr; // Pointer to list content. - - ElementCount elementCount; // Number of elements in the list. - - decltype(BITS / ELEMENTS) step; - // The distance between elements. - - BitCount32 structDataSize; - WirePointerCount16 structPointerCount; - // The struct properties to use when interpreting the elements as structs. All lists can be - // interpreted as struct lists, so these are always filled in. - - ElementSize elementSize; - // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE - // from other types when the overall size is exactly zero or one words. - - int nestingLimit; - // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. - // Once this reaches zero, further pointers will be pruned. - - inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, - ElementCount elementCount, decltype(BITS / ELEMENTS) step, - BitCount structDataSize, WirePointerCount structPointerCount, - ElementSize elementSize, int nestingLimit) - : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), - elementCount(elementCount), step(step), structDataSize(structDataSize), - structPointerCount(structPointerCount), elementSize(elementSize), - nestingLimit(nestingLimit) {} - - friend class StructReader; - friend class ListBuilder; - friend struct WireHelpers; - friend class OrphanBuilder; -}; - -// ------------------------------------------------------------------- - -class OrphanBuilder { -public: - inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { - memset(&tag, 0, sizeof(tag)); - } - OrphanBuilder(const OrphanBuilder& other) = delete; - inline OrphanBuilder(OrphanBuilder&& other) noexcept; - inline ~OrphanBuilder() noexcept(false); - - static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); - static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, - ElementCount elementCount, ElementSize elementSize); - static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, - ElementCount elementCount, StructSize elementSize); - static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); - static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); - - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); -#if !CAPNP_LITE - static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, - kj::Own copyFrom); -#endif // !CAPNP_LITE - - static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, - ElementSize expectedElementSize, StructSize expectedStructSize, - kj::ArrayPtr lists); - - static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); - - OrphanBuilder& operator=(const OrphanBuilder& other) = delete; - inline OrphanBuilder& operator=(OrphanBuilder&& other); - - inline bool operator==(decltype(nullptr)) const { return location == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } - - StructBuilder asStruct(StructSize size); - // Interpret as a struct, or throw an exception if not a struct. - - ListBuilder asList(ElementSize elementSize); - // Interpret as a list, or throw an exception if not a list. elementSize cannot be - // INLINE_COMPOSITE -- use asStructList() instead. - - ListBuilder asStructList(StructSize elementSize); - // Interpret as a struct list, or throw an exception if not a list. - - Text::Builder asText(); - Data::Builder asData(); - // Interpret as a blob, or throw an exception if not a blob. - - StructReader asStructReader(StructSize size) const; - ListReader asListReader(ElementSize elementSize) const; -#if !CAPNP_LITE - kj::Own asCapability() const; -#endif // !CAPNP_LITE - Text::Reader asTextReader() const; - Data::Reader asDataReader() const; - - bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; - // Resize the orphan list to the given size. Returns false if the list is currently empty but - // the requested size is non-zero, in which case the caller will need to allocate a new list. - - void truncate(ElementCount size, ElementSize elementSize); - void truncate(ElementCount size, StructSize elementSize); - void truncateText(ElementCount size); - // Versions of truncate() that know how to allocate a new list if needed. - -private: - static_assert(1 * POINTERS * WORDS_PER_POINTER == 1 * WORDS, - "This struct assumes a pointer is one word."); - word tag; - // Contains an encoded WirePointer representing this object. WirePointer is defined in - // layout.c++, but fits in a word. - // - // This may be a FAR pointer. Even in that case, `location` points to the eventual destination - // of that far pointer. The reason we keep the far pointer around rather than just making `tag` - // represent the final destination is because if the eventual adopter of the pointer is not in - // the target's segment then it may be useful to reuse the far pointer landing pad. - // - // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual - // target. - - SegmentBuilder* segment; - // Segment in which the object resides. - - CapTableBuilder* capTable; - // Table of capability indexes. - - word* location; - // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this - // 0x1 just so that it is non-null for operator==, but it is never used. - - inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, - CapTableBuilder* capTable, word* location) - : segment(segment), capTable(capTable), location(location) { - memcpy(&tag, tagPtr, sizeof(tag)); - } - - inline WirePointer* tagAsPtr() { return reinterpret_cast(&tag); } - inline const WirePointer* tagAsPtr() const { return reinterpret_cast(&tag); } - - void euthanize(); - // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when - // the OrphanBuilder is being destroyed or overwritten and it is non-null. - - friend struct WireHelpers; -}; - -// ======================================================================================= -// Internal implementation details... - -// These are defined in the source file. -template <> typename Text::Builder PointerBuilder::initBlob(ByteCount size); -template <> void PointerBuilder::setBlob(typename Text::Reader value); -template <> typename Text::Builder PointerBuilder::getBlob(const void* defaultValue, ByteCount defaultSize); -template <> typename Text::Reader PointerReader::getBlob(const void* defaultValue, ByteCount defaultSize) const; - -template <> typename Data::Builder PointerBuilder::initBlob(ByteCount size); -template <> void PointerBuilder::setBlob(typename Data::Reader value); -template <> typename Data::Builder PointerBuilder::getBlob(const void* defaultValue, ByteCount defaultSize); -template <> typename Data::Reader PointerReader::getBlob(const void* defaultValue, ByteCount defaultSize) const; - -inline PointerBuilder PointerBuilder::getRoot( - SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { - return PointerBuilder(segment, capTable, reinterpret_cast(location)); -} - -inline PointerReader PointerReader::getRootUnchecked(const word* location) { - return PointerReader(nullptr, nullptr, - reinterpret_cast(location), 0x7fffffff); -} - -// ------------------------------------------------------------------- - -inline kj::ArrayPtr StructBuilder::getDataSectionAsBlob() { - return kj::ArrayPtr(reinterpret_cast(data), dataSize / BITS_PER_BYTE / BYTES); -} - -inline _::ListBuilder StructBuilder::getPointerSectionAsList() { - return _::ListBuilder(segment, capTable, pointers, 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, - pointerCount * (1 * ELEMENTS / POINTERS), - 0 * BITS, 1 * POINTERS, ElementSize::POINTER); -} - -template -inline bool StructBuilder::hasDataField(ElementCount offset) { - return getDataField>(offset) != 0; -} - -template <> -inline bool StructBuilder::hasDataField(ElementCount offset) { - return false; -} - -template -inline T StructBuilder::getDataField(ElementCount offset) { - return reinterpret_cast*>(data)[offset / ELEMENTS].get(); -} - -template <> -inline bool StructBuilder::getDataField(ElementCount offset) { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; - return (*reinterpret_cast(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void StructBuilder::getDataField(ElementCount offset) { - return VOID; -} - -template -inline T StructBuilder::getDataField(ElementCount offset, Mask mask) { - return unmask(getDataField >(offset), mask); -} - -template -inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer value) { - reinterpret_cast*>(data)[offset / ELEMENTS].set(value); -} - -#if CAPNP_CANONICALIZE_NAN -// Use mask() on floats and doubles to make sure we canonicalize NaNs. -template <> -inline void StructBuilder::setDataField(ElementCount offset, float value) { - setDataField(offset, mask(value, 0)); -} -template <> -inline void StructBuilder::setDataField(ElementCount offset, double value) { - setDataField(offset, mask(value, 0)); -} -#endif - -template <> -inline void StructBuilder::setDataField(ElementCount offset, bool value) { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; - uint bitnum = boffset % BITS_PER_BYTE / BITS; - *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << bitnum)) - | (static_cast(value) << bitnum); -} - -template <> -inline void StructBuilder::setDataField(ElementCount offset, Void value) {} - -template -inline void StructBuilder::setDataField(ElementCount offset, kj::NoInfer value, Mask m) { - setDataField >(offset, mask(value, m)); -} - -inline PointerBuilder StructBuilder::getPointerField(WirePointerCount ptrIndex) { - // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). - return PointerBuilder(segment, capTable, reinterpret_cast( - reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER)); -} - -// ------------------------------------------------------------------- - -inline kj::ArrayPtr StructReader::getDataSectionAsBlob() { - return kj::ArrayPtr(reinterpret_cast(data), dataSize / BITS_PER_BYTE / BYTES); -} - -inline _::ListReader StructReader::getPointerSectionAsList() { - return _::ListReader(segment, capTable, pointers, pointerCount * (1 * ELEMENTS / POINTERS), - 1 * POINTERS * BITS_PER_POINTER / ELEMENTS, 0 * BITS, 1 * POINTERS, - ElementSize::POINTER, nestingLimit); -} - -template -inline bool StructReader::hasDataField(ElementCount offset) const { - return getDataField>(offset) != 0; -} - -template <> -inline bool StructReader::hasDataField(ElementCount offset) const { - return false; -} - -template -inline T StructReader::getDataField(ElementCount offset) const { - if ((offset + 1 * ELEMENTS) * capnp::bitsPerElement() <= dataSize) { - return reinterpret_cast*>(data)[offset / ELEMENTS].get(); - } else { - return static_cast(0); - } -} - -template <> -inline bool StructReader::getDataField(ElementCount offset) const { - BitCount boffset = offset * (1 * BITS / ELEMENTS); - if (boffset < dataSize) { - const byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; - return (*reinterpret_cast(b) & (1 << (boffset % BITS_PER_BYTE / BITS))) != 0; - } else { - return false; - } -} - -template <> -inline Void StructReader::getDataField(ElementCount offset) const { - return VOID; -} - -template -T StructReader::getDataField(ElementCount offset, Mask mask) const { - return unmask(getDataField >(offset), mask); -} - -inline PointerReader StructReader::getPointerField(WirePointerCount ptrIndex) const { - if (ptrIndex < pointerCount) { - // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). - return PointerReader(segment, capTable, reinterpret_cast( - reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); - } else{ - return PointerReader(); - } -} - -// ------------------------------------------------------------------- - -inline ElementCount ListBuilder::size() const { return elementCount; } - -template -inline T ListBuilder::getDataElement(ElementCount index) { - return reinterpret_cast*>(ptr + index * step / BITS_PER_BYTE)->get(); - - // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of - // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and - // the various non-inline methods that look up pointers. - // Also if using this, consider changing ptr back to void* instead of byte*. -// return reinterpret_cast*>(ptr)[ -// index / ELEMENTS * (step / capnp::bitsPerElement())].get(); -} - -template <> -inline bool ListBuilder::getDataElement(ElementCount index) { - // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - byte* b = ptr + bindex / BITS_PER_BYTE; - return (*reinterpret_cast(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void ListBuilder::getDataElement(ElementCount index) { - return VOID; -} - -template -inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer value) { - reinterpret_cast*>(ptr + index * step / BITS_PER_BYTE)->set(value); -} - -#if CAPNP_CANONICALIZE_NAN -// Use mask() on floats and doubles to make sure we canonicalize NaNs. -template <> -inline void ListBuilder::setDataElement(ElementCount index, float value) { - setDataElement(index, mask(value, 0)); -} -template <> -inline void ListBuilder::setDataElement(ElementCount index, double value) { - setDataElement(index, mask(value, 0)); -} -#endif - -template <> -inline void ListBuilder::setDataElement(ElementCount index, bool value) { - // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - byte* b = ptr + bindex / BITS_PER_BYTE; - uint bitnum = bindex % BITS_PER_BYTE / BITS; - *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << bitnum)) - | (static_cast(value) << bitnum); -} - -template <> -inline void ListBuilder::setDataElement(ElementCount index, Void value) {} - -inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { - return PointerBuilder(segment, capTable, - reinterpret_cast(ptr + index * step / BITS_PER_BYTE)); -} - -// ------------------------------------------------------------------- - -inline ElementCount ListReader::size() const { return elementCount; } - -template -inline T ListReader::getDataElement(ElementCount index) const { - return reinterpret_cast*>(ptr + index * step / BITS_PER_BYTE)->get(); -} - -template <> -inline bool ListReader::getDataElement(ElementCount index) const { - // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. - BitCount bindex = index * (1 * BITS / ELEMENTS); - const byte* b = ptr + bindex / BITS_PER_BYTE; - return (*reinterpret_cast(b) & (1 << (bindex % BITS_PER_BYTE / BITS))) != 0; -} - -template <> -inline Void ListReader::getDataElement(ElementCount index) const { - return VOID; -} - -inline PointerReader ListReader::getPointerElement(ElementCount index) const { - return PointerReader(segment, capTable, - reinterpret_cast(ptr + index * step / BITS_PER_BYTE), nestingLimit); -} - -// ------------------------------------------------------------------- - -inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept - : segment(other.segment), capTable(other.capTable), location(other.location) { - memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. - other.segment = nullptr; - other.location = nullptr; -} - -inline OrphanBuilder::~OrphanBuilder() noexcept(false) { - if (segment != nullptr) euthanize(); -} - -inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { - // With normal smart pointers, it's important to handle the case where the incoming pointer - // is actually transitively owned by this one. In this case, euthanize() would destroy `other` - // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only - // owns message objects, and `other` is not itself a message object, therefore cannot possibly - // be transitively owned by `this`. - - if (segment != nullptr) euthanize(); - segment = other.segment; - capTable = other.capTable; - location = other.location; - memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. - other.segment = nullptr; - other.location = nullptr; - return *this; -} - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_LAYOUT_H_ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file is NOT intended for use by clients, except in generated code. +// +// This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout +// (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, +// as does other parts of the Cap'n proto library which provide a higher-level interface for +// dynamic introspection. + +#ifndef CAPNP_LAYOUT_H_ +#define CAPNP_LAYOUT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include "common.h" +#include "blob.h" +#include "endian.h" + +#if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) +#define CAPNP_CANONICALIZE_NAN 1 +// Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by +// __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN +// signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in +// particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. +// Canonicalizing them makes output consistent (which is important!), but hurts performance +// slightly. +// +// Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. +// Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. +// everyone else. It would be great if we could just flip that bit, but we can't, because if the +// significand is all-zero, then the value is infinity rather than NaN. This means that on most +// machines, where the bit indicates quietness, there is one more quiet NaN value than signalling +// NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic +// mapping that properly preserves quietness. Instead of doing something hacky, we just give up +// and blow away NaN payloads, because no one uses them anyway. +#endif + +namespace capnp { + +#if !CAPNP_LITE +class ClientHook; +#endif // !CAPNP_LITE + +namespace _ { // private + +class PointerBuilder; +class PointerReader; +class StructBuilder; +class StructReader; +class ListBuilder; +class ListReader; +class OrphanBuilder; +struct WirePointer; +struct WireHelpers; +class SegmentReader; +class SegmentBuilder; +class Arena; +class BuilderArena; + +// ============================================================================= + +#if CAPNP_DEBUG_TYPES +typedef kj::UnitRatio, BitLabel, ElementLabel> BitsPerElementTableType; +#else +typedef uint BitsPerElementTableType; +#endif + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType dataBitsPerElement(ElementSize size) { + return _::BITS_PER_ELEMENT_TABLE[static_cast(size)]; +} + +inline constexpr PointersPerElementN<1> pointersPerElement(ElementSize size) { + return size == ElementSize::POINTER + ? PointersPerElementN<1>(ONE * POINTERS / ELEMENTS) + : PointersPerElementN<1>(ZERO * POINTERS / ELEMENTS); +} + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType bitsPerElementIncludingPointers(ElementSize size) { + return _::BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[static_cast(size)]; +} + +template struct ElementSizeForByteSize; +template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; +template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; +template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; +template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; + +template struct ElementSizeForType { + static constexpr ElementSize value = + // Primitive types that aren't special-cased below can be determined from sizeof(). + CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize::value : + CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : + CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : + + // Everything else is a pointer. + ElementSize::POINTER; +}; + +// Void and bool are special. +template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::VOID; }; +template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::BIT; }; + +// Lists and blobs are pointers, not structs. +template struct ElementSizeForType> { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType { + static constexpr ElementSize value = ElementSize::POINTER; +}; + +template +inline constexpr ElementSize elementSizeForType() { + return ElementSizeForType::value; +} + +struct MessageSizeCounts { + WordCountN<61, uint64_t> wordCount; // 2^64 bytes + uint capCount; + + MessageSizeCounts& operator+=(const MessageSizeCounts& other) { + // OK to truncate unchecked because this class is used to count actual stuff in memory, and + // we couldn't possibly have anywhere near 2^61 words. + wordCount = assumeBits<61>(wordCount + other.wordCount); + capCount += other.capCount; + return *this; + } + + void addWords(WordCountN<61, uint64_t> other) { + wordCount = assumeBits<61>(wordCount + other); + } + + MessageSize asPublic() { + return MessageSize { unbound(wordCount / WORDS), capCount }; + } +}; + +// ============================================================================= + +template +union AlignedData { + // Useful for declaring static constant data blobs as an array of bytes, but forcing those + // bytes to be word-aligned. + + uint8_t bytes[wordCount * sizeof(word)]; + word words[wordCount]; +}; + +struct StructSize { + StructDataWordCount data; + StructPointerCount pointers; + + inline constexpr WordCountN<17> total() const { return data + pointers * WORDS_PER_POINTER; } + + StructSize() = default; + inline constexpr StructSize(StructDataWordCount data, StructPointerCount pointers) + : data(data), pointers(pointers) {} +}; + +template +inline constexpr StructSize structSize() { + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template > +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template > +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize( + dataBitsPerElement(elementSizeForType()) * ELEMENTS > ZERO * BITS + ? StructDataWordCount(ONE * WORDS) : StructDataWordCount(ZERO * WORDS), + pointersPerElement(elementSizeForType()) * ELEMENTS); +} + +// ------------------------------------------------------------------- +// Masking of default values + +template struct Mask_; +template struct Mask_ { typedef T Type; }; +template struct Mask_ { typedef uint16_t Type; }; +template <> struct Mask_ { typedef uint32_t Type; }; +template <> struct Mask_ { typedef uint64_t Type; }; + +template struct Mask_ { + // Union discriminants end up here. + static_assert(sizeof(T) == 2, "Don't know how to mask this type."); + typedef uint16_t Type; +}; + +template +using Mask = typename Mask_::Type; + +template +KJ_ALWAYS_INLINE(Mask mask(T value, Mask mask)); +template +KJ_ALWAYS_INLINE(T unmask(Mask value, Mask mask)); + +template +inline Mask mask(T value, Mask mask) { + return static_cast >(value) ^ mask; +} + +template <> +inline uint32_t mask(float value, uint32_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7fc00000u ^ mask; + } +#endif + + uint32_t i; + static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template <> +inline uint64_t mask(double value, uint64_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7ff8000000000000ull ^ mask; + } +#endif + + uint64_t i; + static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template +inline T unmask(Mask value, Mask mask) { + return static_cast(value ^ mask); +} + +template <> +inline float unmask(uint32_t value, uint32_t mask) { + value ^= mask; + float result; + static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +template <> +inline double unmask(uint64_t value, uint64_t mask) { + value ^= mask; + double result; + static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +// ------------------------------------------------------------------- + +class CapTableReader { +public: +#if !CAPNP_LITE + virtual kj::Maybe> extractCap(uint index) = 0; + // Extract the capability at the given index. If the index is invalid, returns null. +#endif // !CAPNP_LITE +}; + +class CapTableBuilder: public CapTableReader { +public: +#if !CAPNP_LITE + virtual uint injectCap(kj::Own&& cap) = 0; + // Add the capability to the message and return its index. If the same ClientHook is injected + // twice, this may return the same index both times, but in this case dropCap() needs to be + // called an equal number of times to actually remove the cap. + + virtual void dropCap(uint index) = 0; + // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. +#endif // !CAPNP_LITE +}; + +// ------------------------------------------------------------------- + +class PointerBuilder: public kj::DisallowConstCopy { + // Represents a single pointer, usually embedded in a struct or a list. + +public: + inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} + + static inline PointerBuilder getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location); + // Get a PointerBuilder representing a message root located in the given segment at the given + // location. + + inline bool isNull() { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructBuilder getStruct(StructSize size, const word* defaultValue); + ListBuilder getList(ElementSize elementSize, const word* defaultValue); + ListBuilder getStructList(StructSize elementSize, const word* defaultValue); + ListBuilder getListAnySize(const word* defaultValue); + template typename T::Builder getBlob( + const void* defaultValue, ByteCount defaultSize); +#if !CAPNP_LITE + kj::Own getCapability(); +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, initialize it to a copy of the default value. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + StructBuilder initStruct(StructSize size); + ListBuilder initList(ElementSize elementSize, ElementCount elementCount); + ListBuilder initStructList(ElementCount elementCount, StructSize size); + template typename T::Builder initBlob(ByteCount size); + // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing + // object. + + void setStruct(const StructReader& value, bool canonical = false); + void setList(const ListReader& value, bool canonical = false); + template void setBlob(typename T::Reader value); +#if !CAPNP_LITE + void setCapability(kj::Own&& cap); +#endif // !CAPNP_LITE + // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding + // the existing object. + + void adopt(OrphanBuilder&& orphan); + // Set the pointer to point at the given orphaned value. + + OrphanBuilder disown(); + // Set the pointer to null and return its previous value as an orphan. + + void clear(); + // Clear the pointer to null, discarding its previous value. + + void transferFrom(PointerBuilder other); + // Equivalent to `adopt(other.disown())`. + + void copyFrom(PointerReader other, bool canonical = false); + // Equivalent to `set(other.get())`. + // If you set the canonical flag, it will attempt to lay the target out + // canonically, provided enough space is available. + + PointerReader asReader() const; + + BuilderArena* getArena() const; + // Get the arena containing this pointer. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the pointer resides. + CapTableBuilder* capTable; // Table of capability indexes. + WirePointer* pointer; // Pointer to the pointer. + + inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) + : segment(segment), capTable(capTable), pointer(pointer) {} + + friend class StructBuilder; + friend class ListBuilder; + friend class OrphanBuilder; +}; + +class PointerReader { +public: + inline PointerReader() + : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} + + static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, + const word* location, int nestingLimit); + // Get a PointerReader representing a message root located in the given segment at the given + // location. + + static inline PointerReader getRootUnchecked(const word* location); + // Get a PointerReader for an unchecked message. + + MessageSizeCounts targetSize() const; + // Return the total size of the target object and everything to which it points. Does not count + // far pointer overhead. This is useful for deciding how much space is needed to copy the object + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + inline bool isNull() const { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructReader getStruct(const word* defaultValue) const; + ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; + ListReader getListAnySize(const word* defaultValue) const; + template + typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; +#if !CAPNP_LITE + kj::Own getCapability() const; +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, return the default value instead. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + const word* getUnchecked() const; + // If this is an unchecked message, get a word* pointing at the location of the pointer. This + // word* can actually be passed to readUnchecked() to read the designated sub-object later. If + // this isn't an unchecked message, throws an exception. + + kj::Maybe getArena() const; + // Get the arena containing this pointer. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the pointer resides. + CapTableReader* capTable; // Table of capability indexes. + const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline PointerReader(SegmentReader* segment, CapTableReader* capTable, + const WirePointer* pointer, int nestingLimit) + : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListReader; + friend class PointerBuilder; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class StructBuilder: public kj::DisallowConstCopy { +public: + inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} + + inline word* getLocation() { return reinterpret_cast(data); } + // Get the object's location. Only valid for independently-allocated objects (i.e. not list + // elements). + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr getDataSectionAsBlob(); + inline _::ListBuilder getPointerSectionAsList(); + + template + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset)); + // Return true if the field is set to something other than its default value. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset)); + // Gets the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask mask)); + // Like getDataField() but applies the given XOR mask to the data on load. Used for reading + // fields with non-zero default values. + + template + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, kj::NoInfer value)); + // Sets the data field value at the given offset. + + template + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, + kj::NoInfer value, Mask mask)); + // Like setDataField() but applies the given XOR mask before storing. Used for writing fields + // with non-zero default values. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerField(StructPointerOffset ptrIndex)); + // Get a builder for a pointer field given the index within the pointer section. + + void clearAll(); + // Clear all pointers and data. + + void transferContentFrom(StructBuilder other); + // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger + // than this, the extra data is not transferred, meaning there is a risk of data loss when + // transferring from messages built with future versions of the protocol. + + void copyContentFrom(StructReader other); + // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not + // copied, meaning there is a risk of data loss when copying from messages built with future + // versions of the protocol. + + StructReader asReader() const; + // Gets a StructReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + StructBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the struct resides. + CapTableBuilder* capTable; // Table of capability indexes. + void* data; // Pointer to the encoded data. + WirePointer* pointers; // Pointer to the encoded pointers. + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, + void* data, WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount) {} + + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class StructReader { +public: + inline StructReader() + : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), + dataSize(ZERO * BITS), pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + inline StructReader(kj::ArrayPtr data) + : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), + dataSize(assumeBits(data.size()) * WORDS * BITS_PER_WORD), + pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + + const void* getLocation() const { return data; } + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr getDataSectionAsBlob(); + inline _::ListReader getPointerSectionAsList(); + + kj::Array canonicalize(); + + template + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset) const); + // Return true if the field is set to something other than its default value. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset) const); + // Get the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. Returns zero if the offset is past the + // end of the struct's data section. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask mask) const); + // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading + // fields with non-zero default values. + + KJ_ALWAYS_INLINE(PointerReader getPointerField(StructPointerOffset ptrIndex) const); + // Get a reader for a pointer field given the index within the pointer section. If the index + // is out-of-bounds, returns a null pointer. + + MessageSizeCounts totalSize() const; + // Return the total size of the struct and everything to which it points. Does not count far + // pointer overhead. This is useful for deciding how much space is needed to copy the struct + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + StructReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const word **ptrHead, + bool *dataTrunc, bool *ptrTrunc); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + // + // If this function returns false, the struct is non-canonical. If it + // returns true, then: + // * If it is a composite in a list, it is canonical if at least one struct + // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 + // * If it is derived from a struct pointer, it is canonical if + // dataTrunc = 1 AND ptrTrunc = 1 + +private: + SegmentReader* segment; // Memory segment in which the struct resides. + CapTableReader* capTable; // Table of capability indexes. + + const void* data; + const WirePointer* pointers; + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + // TODO(perf): Limit to 16 bits for better packing? + + inline StructReader(SegmentReader* segment, CapTableReader* capTable, + const void* data, const WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount, + int nestingLimit) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount), + nestingLimit(nestingLimit) {} + + friend class ListReader; + friend class StructBuilder; + friend struct WireHelpers; +}; + +// ------------------------------------------------------------------- + +class ListBuilder: public kj::DisallowConstCopy { +public: + inline explicit ListBuilder(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize) {} + + inline word* getLocation() { + // Get the object's location. + + if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { + return reinterpret_cast(ptr) - POINTER_SIZE_IN_WORDS; + } else { + return reinterpret_cast(ptr); + } + } + + inline ElementSize getElementSize() const { return elementSize; } + + inline ListElementCount size() const; + // The number of elements in the list. + + Text::Builder asText(); + Data::Builder asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + template + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); + // Get the element of the given type at the given index. + + template + KJ_ALWAYS_INLINE(void setDataElement(ElementCount index, kj::NoInfer value)); + // Set the element at the given index. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); + + StructBuilder getStructElement(ElementCount index); + + ListReader asReader() const; + // Get a ListReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + ListBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the list resides. + CapTableBuilder* capTable; // Table of capability indexes. + + byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 128 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, + BitsPerElementN<23> step, ListElementCount size, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize) + : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), + elementCount(size), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize) {} + + friend class StructBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class ListReader { +public: + inline explicit ListReader(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize), nestingLimit(0x7fffffff) {} + + inline ListElementCount size() const; + // The number of elements in the list. + + inline ElementSize getElementSize() const { return elementSize; } + + Text::Reader asText(); + Data::Reader asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + kj::ArrayPtr asRawBytes(); + + template + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); + // Get the element of the given type at the given index. + + KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); + + StructReader getStructElement(ElementCount index) const; + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + ListReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const WirePointer* ref); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the list resides. + CapTableReader* capTable; // Table of capability indexes. + + const byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 2 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, + ListElementCount elementCount, BitsPerElementN<23> step, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize, int nestingLimit) + : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), + elementCount(elementCount), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize), + nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class OrphanBuilder { +public: + inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { + memset(&tag, 0, sizeof(tag)); + } + OrphanBuilder(const OrphanBuilder& other) = delete; + inline OrphanBuilder(OrphanBuilder&& other) noexcept; + inline ~OrphanBuilder() noexcept(false); + + static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); + static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, ElementSize elementSize); + static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, StructSize elementSize); + static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); +#if !CAPNP_LITE + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, + kj::Own copyFrom); +#endif // !CAPNP_LITE + + static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, + ElementSize expectedElementSize, StructSize expectedStructSize, + kj::ArrayPtr lists); + + static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); + + OrphanBuilder& operator=(const OrphanBuilder& other) = delete; + inline OrphanBuilder& operator=(OrphanBuilder&& other); + + inline bool operator==(decltype(nullptr)) const { return location == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } + + StructBuilder asStruct(StructSize size); + // Interpret as a struct, or throw an exception if not a struct. + + ListBuilder asList(ElementSize elementSize); + // Interpret as a list, or throw an exception if not a list. elementSize cannot be + // INLINE_COMPOSITE -- use asStructList() instead. + + ListBuilder asStructList(StructSize elementSize); + // Interpret as a struct list, or throw an exception if not a list. + + ListBuilder asListAnySize(); + // For AnyList. + + Text::Builder asText(); + Data::Builder asData(); + // Interpret as a blob, or throw an exception if not a blob. + + StructReader asStructReader(StructSize size) const; + ListReader asListReader(ElementSize elementSize) const; + ListReader asListReaderAnySize() const; +#if !CAPNP_LITE + kj::Own asCapability() const; +#endif // !CAPNP_LITE + Text::Reader asTextReader() const; + Data::Reader asDataReader() const; + + bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; + // Resize the orphan list to the given size. Returns false if the list is currently empty but + // the requested size is non-zero, in which case the caller will need to allocate a new list. + + void truncate(ElementCount size, ElementSize elementSize); + void truncate(ElementCount size, StructSize elementSize); + void truncateText(ElementCount size); + // Versions of truncate() that know how to allocate a new list if needed. + +private: + static_assert(ONE * POINTERS * WORDS_PER_POINTER == ONE * WORDS, + "This struct assumes a pointer is one word."); + word tag; + // Contains an encoded WirePointer representing this object. WirePointer is defined in + // layout.c++, but fits in a word. + // + // This may be a FAR pointer. Even in that case, `location` points to the eventual destination + // of that far pointer. The reason we keep the far pointer around rather than just making `tag` + // represent the final destination is because if the eventual adopter of the pointer is not in + // the target's segment then it may be useful to reuse the far pointer landing pad. + // + // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual + // target. + + SegmentBuilder* segment; + // Segment in which the object resides. + + CapTableBuilder* capTable; + // Table of capability indexes. + + word* location; + // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this + // 0x1 just so that it is non-null for operator==, but it is never used. + + inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, + CapTableBuilder* capTable, word* location) + : segment(segment), capTable(capTable), location(location) { + memcpy(&tag, tagPtr, sizeof(tag)); + } + + inline WirePointer* tagAsPtr() { return reinterpret_cast(&tag); } + inline const WirePointer* tagAsPtr() const { return reinterpret_cast(&tag); } + + void euthanize(); + // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when + // the OrphanBuilder is being destroyed or overwritten and it is non-null. + + friend struct WireHelpers; +}; + +// ======================================================================================= +// Internal implementation details... + +// These are defined in the source file. +template <> typename Text::Builder PointerBuilder::initBlob(ByteCount size); +template <> void PointerBuilder::setBlob(typename Text::Reader value); +template <> typename Text::Builder PointerBuilder::getBlob( + const void* defaultValue, ByteCount defaultSize); +template <> typename Text::Reader PointerReader::getBlob( + const void* defaultValue, ByteCount defaultSize) const; + +template <> typename Data::Builder PointerBuilder::initBlob(ByteCount size); +template <> void PointerBuilder::setBlob(typename Data::Reader value); +template <> typename Data::Builder PointerBuilder::getBlob( + const void* defaultValue, ByteCount defaultSize); +template <> typename Data::Reader PointerReader::getBlob( + const void* defaultValue, ByteCount defaultSize) const; + +inline PointerBuilder PointerBuilder::getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { + return PointerBuilder(segment, capTable, reinterpret_cast(location)); +} + +inline PointerReader PointerReader::getRootUnchecked(const word* location) { + return PointerReader(nullptr, nullptr, + reinterpret_cast(location), 0x7fffffff); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr StructBuilder::getDataSectionAsBlob() { + return kj::ArrayPtr(reinterpret_cast(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListBuilder StructBuilder::getPointerSectionAsList() { + return _::ListBuilder(segment, capTable, pointers, ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, + pointerCount * (ONE * ELEMENTS / POINTERS), + ZERO * BITS, ONE * POINTERS, ElementSize::POINTER); +} + +template +inline bool StructBuilder::hasDataField(StructDataOffset offset) { + return getDataField>(offset) != 0; +} + +template <> +inline bool StructBuilder::hasDataField(StructDataOffset offset) { + return false; +} + +template +inline T StructBuilder::getDataField(StructDataOffset offset) { + return reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].get(); +} + +template <> +inline bool StructBuilder::getDataField(StructDataOffset offset) { + BitCount32 boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void StructBuilder::getDataField(StructDataOffset offset) { + return VOID; +} + +template +inline T StructBuilder::getDataField(StructDataOffset offset, Mask mask) { + return unmask(getDataField >(offset), mask); +} + +template +inline void StructBuilder::setDataField(StructDataOffset offset, kj::NoInfer value) { + reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, float value) { + setDataField(offset, mask(value, 0)); +} +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, double value) { + setDataField(offset, mask(value, 0)); +} +#endif + +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, bool value) { + auto boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + uint bitnum = unboundMaxBits<3>(boffset % BITS_PER_BYTE / BITS); + *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << bitnum)) + | (static_cast(value) << bitnum); +} + +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, Void value) {} + +template +inline void StructBuilder::setDataField(StructDataOffset offset, + kj::NoInfer value, Mask m) { + setDataField >(offset, mask(value, m)); +} + +inline PointerBuilder StructBuilder::getPointerField(StructPointerOffset ptrIndex) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerBuilder(segment, capTable, reinterpret_cast( + reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER)); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr StructReader::getDataSectionAsBlob() { + return kj::ArrayPtr(reinterpret_cast(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListReader StructReader::getPointerSectionAsList() { + return _::ListReader(segment, capTable, pointers, pointerCount * (ONE * ELEMENTS / POINTERS), + ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, ZERO * BITS, ONE * POINTERS, + ElementSize::POINTER, nestingLimit); +} + +template +inline bool StructReader::hasDataField(StructDataOffset offset) const { + return getDataField>(offset) != 0; +} + +template <> +inline bool StructReader::hasDataField(StructDataOffset offset) const { + return false; +} + +template +inline T StructReader::getDataField(StructDataOffset offset) const { + if ((offset + ONE * ELEMENTS) * capnp::bitsPerElement() <= dataSize) { + return reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].get(); + } else { + return static_cast(0); + } +} + +template <> +inline bool StructReader::getDataField(StructDataOffset offset) const { + auto boffset = offset * (ONE * BITS / ELEMENTS); + if (boffset < dataSize) { + const byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; + } else { + return false; + } +} + +template <> +inline Void StructReader::getDataField(StructDataOffset offset) const { + return VOID; +} + +template +T StructReader::getDataField(StructDataOffset offset, Mask mask) const { + return unmask(getDataField >(offset), mask); +} + +inline PointerReader StructReader::getPointerField(StructPointerOffset ptrIndex) const { + if (ptrIndex < pointerCount) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerReader(segment, capTable, reinterpret_cast( + reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); + } else{ + return PointerReader(); + } +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListBuilder::size() const { return elementCount; } + +template +inline T ListBuilder::getDataElement(ElementCount index) { + return reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->get(); + + // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of + // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and + // the various non-inline methods that look up pointers. + // Also if using this, consider changing ptr back to void* instead of byte*. +// return reinterpret_cast*>(ptr)[ +// index / ELEMENTS * (step / capnp::bitsPerElement())].get(); +} + +template <> +inline bool ListBuilder::getDataElement(ElementCount index) { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListBuilder::getDataElement(ElementCount index) { + return VOID; +} + +template +inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer value) { + reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void ListBuilder::setDataElement(ElementCount index, float value) { + setDataElement(index, mask(value, 0)); +} +template <> +inline void ListBuilder::setDataElement(ElementCount index, double value) { + setDataElement(index, mask(value, 0)); +} +#endif + +template <> +inline void ListBuilder::setDataElement(ElementCount index, bool value) { + // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + auto bitnum = bindex % BITS_PER_BYTE / BITS; + *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << unbound(bitnum))) + | (static_cast(value) << unbound(bitnum)); +} + +template <> +inline void ListBuilder::setDataElement(ElementCount index, Void value) {} + +inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { + return PointerBuilder(segment, capTable, reinterpret_cast(ptr + + upgradeBound(index) * step / BITS_PER_BYTE)); +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListReader::size() const { return elementCount; } + +template +inline T ListReader::getDataElement(ElementCount index) const { + return reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->get(); +} + +template <> +inline bool ListReader::getDataElement(ElementCount index) const { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + const byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListReader::getDataElement(ElementCount index) const { + return VOID; +} + +inline PointerReader ListReader::getPointerElement(ElementCount index) const { + return PointerReader(segment, capTable, reinterpret_cast( + ptr + upgradeBound(index) * step / BITS_PER_BYTE), nestingLimit); +} + +// ------------------------------------------------------------------- + +inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept + : segment(other.segment), capTable(other.capTable), location(other.location) { + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; +} + +inline OrphanBuilder::~OrphanBuilder() noexcept(false) { + if (segment != nullptr) euthanize(); +} + +inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { + // With normal smart pointers, it's important to handle the case where the incoming pointer + // is actually transitively owned by this one. In this case, euthanize() would destroy `other` + // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only + // owns message objects, and `other` is not itself a message object, therefore cannot possibly + // be transitively owned by `this`. + + if (segment != nullptr) euthanize(); + segment = other.segment; + capTable = other.capTable; + location = other.location; + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; + return *this; +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_LAYOUT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/list.h --- a/osx/include/capnp/list.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/list.h Mon May 22 10:01:37 2017 +0100 @@ -1,543 +1,546 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_LIST_H_ -#define CAPNP_LIST_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "layout.h" -#include "orphan.h" -#include -#ifdef KJ_STD_COMPAT -#include -#endif // KJ_STD_COMPAT - -namespace capnp { -namespace _ { // private - -template -class TemporaryPointer { - // This class is a little hack which lets us define operator->() in cases where it needs to - // return a pointer to a temporary value. We instead construct a TemporaryPointer and return that - // (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is - // able to return a real pointer to its member. - -public: - TemporaryPointer(T&& value): value(kj::mv(value)) {} - TemporaryPointer(const T& value): value(value) {} - - inline T* operator->() { return &value; } -private: - T value; -}; - -template -class IndexingIterator { -public: - IndexingIterator() = default; - - inline Element operator*() const { return (*container)[index]; } - inline TemporaryPointer operator->() const { - return TemporaryPointer((*container)[index]); - } - inline Element operator[]( int off) const { return (*container)[index]; } - inline Element operator[](uint off) const { return (*container)[index]; } - - inline IndexingIterator& operator++() { ++index; return *this; } - inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; } - inline IndexingIterator& operator--() { --index; return *this; } - inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; } - - inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); } - inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); } - inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); } - inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); } - - inline int operator-(const IndexingIterator& other) const { return index - other.index; } - - inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; } - inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; } - inline IndexingIterator& operator+=( int amount) { index += amount; return *this; } - inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; } - - // STL says comparing iterators of different containers is not allowed, so we only compare - // indices here. - inline bool operator==(const IndexingIterator& other) const { return index == other.index; } - inline bool operator!=(const IndexingIterator& other) const { return index != other.index; } - inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; } - inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; } - inline bool operator< (const IndexingIterator& other) const { return index < other.index; } - inline bool operator> (const IndexingIterator& other) const { return index > other.index; } - -private: - Container* container; - uint index; - - friend Container; - inline IndexingIterator(Container* container, uint index) - : container(container), index(index) {} -}; - -} // namespace _ (private) - -template -struct List { - // List of primitives. - - List() = delete; - - class Reader { - public: - typedef List Reads; - - inline Reader(): reader(_::elementSizeForType()) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline T operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return reader.template getDataElement(index * ELEMENTS); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List Builds; - - inline Builder(): builder(_::elementSizeForType()) {} - inline Builder(decltype(nullptr)) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline T operator[](uint index) { - KJ_IREQUIRE(index < size()); - return builder.template getDataElement(index * ELEMENTS); - } - inline void set(uint index, T value) { - // Alas, it is not possible to make operator[] return a reference to which you can assign, - // since the encoded representation does not necessarily match the compiler's representation - // of the type. We can't even return a clever class that implements operator T() and - // operator=() because it will lead to surprising behavior when using type inference (e.g. - // calling a template function with inferred argument types, or using "auto" or "decltype"). - - builder.template setDataElement(index * ELEMENTS, value); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Pipeline {}; - -private: - inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { - return builder.initList(_::elementSizeForType(), size * ELEMENTS); - } - inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { - return builder.getList(_::elementSizeForType(), defaultValue); - } - inline static _::ListReader getFromPointer( - const _::PointerReader& reader, const word* defaultValue) { - return reader.getList(_::elementSizeForType(), defaultValue); - } - - template - friend struct List; - template - friend struct _::PointerHelpers; -}; - -template -struct List: public List {}; - -template -struct List { - // List of structs. - - List() = delete; - - class Reader { - public: - typedef List Reads; - - inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline typename T::Reader operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return typename T::Reader(reader.getStructElement(index * ELEMENTS)); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List Builds; - - inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {} - inline Builder(decltype(nullptr)) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline typename T::Builder operator[](uint index) { - KJ_IREQUIRE(index < size()); - return typename T::Builder(builder.getStructElement(index * ELEMENTS)); - } - - inline void adoptWithCaveats(uint index, Orphan&& orphan) { - // Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from - // the fact that structs in a struct list are allocated inline rather than by pointer: - // * This actually performs a shallow copy, effectively adopting each of the orphan's - // children rather than adopting the orphan itself. The orphan ends up being discarded, - // possibly wasting space in the message object. - // * If the orphan is larger than the target struct -- say, because the orphan was built - // using a newer version of the schema that has additional fields -- it will be truncated, - // losing data. - - KJ_IREQUIRE(index < size()); - - // We pass a zero-valued StructSize to asStruct() because we do not want the struct to be - // expanded under any circumstances. We're just going to throw it away anyway, and - // transferContentFrom() already carefully compares the struct sizes before transferring. - builder.getStructElement(index * ELEMENTS).transferContentFrom( - orphan.builder.asStruct(_::StructSize(0 * WORDS, 0 * POINTERS))); - } - inline void setWithCaveats(uint index, const typename T::Reader& reader) { - // Mostly behaves like you'd expect `set` to behave, but with a caveat originating from - // the fact that structs in a struct list are allocated inline rather than by pointer: - // If the source struct is larger than the target struct -- say, because the source was built - // using a newer version of the schema that has additional fields -- it will be truncated, - // losing data. - // - // Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to - // do it without losing any data in case the source lists come from a newer version of the - // protocol. (Plus, it's easier to use anyhow.) - - KJ_IREQUIRE(index < size()); - builder.getStructElement(index * ELEMENTS).copyContentFrom(reader._reader); - } - - // There are no init(), set(), adopt(), or disown() methods for lists of structs because the - // elements of the list are inlined and are initialized when the list is initialized. This - // means that init() would be redundant, and set() would risk data loss if the input struct - // were from a newer version of the protocol. - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Pipeline {}; - -private: - inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { - return builder.initStructList(size * ELEMENTS, _::structSize()); - } - inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { - return builder.getStructList(_::structSize(), defaultValue); - } - inline static _::ListReader getFromPointer( - const _::PointerReader& reader, const word* defaultValue) { - return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue); - } - - template - friend struct List; - template - friend struct _::PointerHelpers; -}; - -template -struct List, Kind::LIST> { - // List of lists. - - List() = delete; - - class Reader { - public: - typedef List> Reads; - - inline Reader(): reader(ElementSize::POINTER) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline typename List::Reader operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return typename List::Reader( - _::PointerHelpers>::get(reader.getPointerElement(index * ELEMENTS))); - } - - typedef _::IndexingIterator::Reader> Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List> Builds; - - inline Builder(): builder(ElementSize::POINTER) {} - inline Builder(decltype(nullptr)) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline typename List::Builder operator[](uint index) { - KJ_IREQUIRE(index < size()); - return typename List::Builder( - _::PointerHelpers>::get(builder.getPointerElement(index * ELEMENTS))); - } - inline typename List::Builder init(uint index, uint size) { - KJ_IREQUIRE(index < this->size()); - return typename List::Builder( - _::PointerHelpers>::init(builder.getPointerElement(index * ELEMENTS), size)); - } - inline void set(uint index, typename List::Reader value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).setList(value.reader); - } - void set(uint index, std::initializer_list> value) { - KJ_IREQUIRE(index < size()); - auto l = init(index, value.size()); - uint i = 0; - for (auto& element: value) { - l.set(i++, element); - } - } - inline void adopt(uint index, Orphan&& value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value.builder)); - } - inline Orphan disown(uint index) { - KJ_IREQUIRE(index < size()); - return Orphan(builder.getPointerElement(index * ELEMENTS).disown()); - } - - typedef _::IndexingIterator::Builder> Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Pipeline {}; - -private: - inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { - return builder.initList(ElementSize::POINTER, size * ELEMENTS); - } - inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { - return builder.getList(ElementSize::POINTER, defaultValue); - } - inline static _::ListReader getFromPointer( - const _::PointerReader& reader, const word* defaultValue) { - return reader.getList(ElementSize::POINTER, defaultValue); - } - - template - friend struct List; - template - friend struct _::PointerHelpers; -}; - -template -struct List { - List() = delete; - - class Reader { - public: - typedef List Reads; - - inline Reader(): reader(ElementSize::POINTER) {} - inline explicit Reader(_::ListReader reader): reader(reader) {} - - inline uint size() const { return reader.size() / ELEMENTS; } - inline typename T::Reader operator[](uint index) const { - KJ_IREQUIRE(index < size()); - return reader.getPointerElement(index * ELEMENTS).template getBlob(nullptr, 0 * BYTES); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - - private: - _::ListReader reader; - template - friend struct _::PointerHelpers; - template - friend struct List; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Builder { - public: - typedef List Builds; - - inline Builder(): builder(ElementSize::POINTER) {} - inline Builder(decltype(nullptr)) {} - inline explicit Builder(_::ListBuilder builder): builder(builder) {} - - inline operator Reader() const { return Reader(builder.asReader()); } - inline Reader asReader() const { return Reader(builder.asReader()); } - - inline uint size() const { return builder.size() / ELEMENTS; } - inline typename T::Builder operator[](uint index) { - KJ_IREQUIRE(index < size()); - return builder.getPointerElement(index * ELEMENTS).template getBlob(nullptr, 0 * BYTES); - } - inline void set(uint index, typename T::Reader value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).template setBlob(value); - } - inline typename T::Builder init(uint index, uint size) { - KJ_IREQUIRE(index < this->size()); - return builder.getPointerElement(index * ELEMENTS).template initBlob(size * BYTES); - } - inline void adopt(uint index, Orphan&& value) { - KJ_IREQUIRE(index < size()); - builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value.builder)); - } - inline Orphan disown(uint index) { - KJ_IREQUIRE(index < size()); - return Orphan(builder.getPointerElement(index * ELEMENTS).disown()); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - private: - _::ListBuilder builder; - template - friend struct _::PointerHelpers; - friend class Orphanage; - template - friend struct ToDynamic_; - }; - - class Pipeline {}; - -private: - inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { - return builder.initList(ElementSize::POINTER, size * ELEMENTS); - } - inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { - return builder.getList(ElementSize::POINTER, defaultValue); - } - inline static _::ListReader getFromPointer( - const _::PointerReader& reader, const word* defaultValue) { - return reader.getList(ElementSize::POINTER, defaultValue); - } - - template - friend struct List; - template - friend struct _::PointerHelpers; -}; - -} // namespace capnp - -#ifdef KJ_STD_COMPAT -namespace std { - -template -struct iterator_traits> - : public std::iterator {}; - -} // namespace std -#endif // KJ_STD_COMPAT - -#endif // CAPNP_LIST_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_LIST_H_ +#define CAPNP_LIST_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "orphan.h" +#include +#ifdef KJ_STD_COMPAT +#include +#endif // KJ_STD_COMPAT + +namespace capnp { +namespace _ { // private + +template +class TemporaryPointer { + // This class is a little hack which lets us define operator->() in cases where it needs to + // return a pointer to a temporary value. We instead construct a TemporaryPointer and return that + // (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is + // able to return a real pointer to its member. + +public: + TemporaryPointer(T&& value): value(kj::mv(value)) {} + TemporaryPointer(const T& value): value(value) {} + + inline T* operator->() { return &value; } +private: + T value; +}; + +template +class IndexingIterator { +public: + IndexingIterator() = default; + + inline Element operator*() const { return (*container)[index]; } + inline TemporaryPointer operator->() const { + return TemporaryPointer((*container)[index]); + } + inline Element operator[]( int off) const { return (*container)[index]; } + inline Element operator[](uint off) const { return (*container)[index]; } + + inline IndexingIterator& operator++() { ++index; return *this; } + inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; } + inline IndexingIterator& operator--() { --index; return *this; } + inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; } + + inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); } + inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); } + inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); } + inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); } + + inline int operator-(const IndexingIterator& other) const { return index - other.index; } + + inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; } + inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; } + inline IndexingIterator& operator+=( int amount) { index += amount; return *this; } + inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; } + + // STL says comparing iterators of different containers is not allowed, so we only compare + // indices here. + inline bool operator==(const IndexingIterator& other) const { return index == other.index; } + inline bool operator!=(const IndexingIterator& other) const { return index != other.index; } + inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; } + inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; } + inline bool operator< (const IndexingIterator& other) const { return index < other.index; } + inline bool operator> (const IndexingIterator& other) const { return index > other.index; } + +private: + Container* container; + uint index; + + friend Container; + inline IndexingIterator(Container* container, uint index) + : container(container), index(index) {} +}; + +} // namespace _ (private) + +template +struct List { + // List of primitives. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(_::elementSizeForType()) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline T operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return reader.template getDataElement(bounded(index) * ELEMENTS); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(_::elementSizeForType()) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline T operator[](uint index) { + KJ_IREQUIRE(index < size()); + return builder.template getDataElement(bounded(index) * ELEMENTS); + } + inline void set(uint index, T value) { + // Alas, it is not possible to make operator[] return a reference to which you can assign, + // since the encoded representation does not necessarily match the compiler's representation + // of the type. We can't even return a clever class that implements operator T() and + // operator=() because it will lead to surprising behavior when using type inference (e.g. + // calling a template function with inferred argument types, or using "auto" or "decltype"). + + builder.template setDataElement(bounded(index) * ELEMENTS, value); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(_::elementSizeForType(), bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(_::elementSizeForType(), defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(_::elementSizeForType(), defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List: public List {}; + +template +struct List { + // List of structs. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename T::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename T::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); + } + + inline void adoptWithCaveats(uint index, Orphan&& orphan) { + // Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from + // the fact that structs in a struct list are allocated inline rather than by pointer: + // * This actually performs a shallow copy, effectively adopting each of the orphan's + // children rather than adopting the orphan itself. The orphan ends up being discarded, + // possibly wasting space in the message object. + // * If the orphan is larger than the target struct -- say, because the orphan was built + // using a newer version of the schema that has additional fields -- it will be truncated, + // losing data. + + KJ_IREQUIRE(index < size()); + + // We pass a zero-valued StructSize to asStruct() because we do not want the struct to be + // expanded under any circumstances. We're just going to throw it away anyway, and + // transferContentFrom() already carefully compares the struct sizes before transferring. + builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom( + orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + inline void setWithCaveats(uint index, const typename T::Reader& reader) { + // Mostly behaves like you'd expect `set` to behave, but with a caveat originating from + // the fact that structs in a struct list are allocated inline rather than by pointer: + // If the source struct is larger than the target struct -- say, because the source was built + // using a newer version of the schema that has additional fields -- it will be truncated, + // losing data. + // + // Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to + // do it without losing any data in case the source lists come from a newer version of the + // protocol. (Plus, it's easier to use anyhow.) + + KJ_IREQUIRE(index < size()); + builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(reader._reader); + } + + // There are no init(), set(), adopt(), or disown() methods for lists of structs because the + // elements of the list are inlined and are initialized when the list is initialized. This + // means that init() would be redundant, and set() would risk data loss if the input struct + // were from a newer version of the protocol. + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initStructList(bounded(size) * ELEMENTS, _::structSize()); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getStructList(_::structSize(), defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List, Kind::LIST> { + // List of lists. + + List() = delete; + + class Reader { + public: + typedef List> Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename List::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename List::Reader(_::PointerHelpers>::get( + reader.getPointerElement(bounded(index) * ELEMENTS))); + } + + typedef _::IndexingIterator::Reader> Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List> Builds; + + inline Builder(): builder(ElementSize::POINTER) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename List::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename List::Builder(_::PointerHelpers>::get( + builder.getPointerElement(bounded(index) * ELEMENTS))); + } + inline typename List::Builder init(uint index, uint size) { + KJ_IREQUIRE(index < this->size()); + return typename List::Builder(_::PointerHelpers>::init( + builder.getPointerElement(bounded(index) * ELEMENTS), size)); + } + inline void set(uint index, typename List::Reader value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).setList(value.reader); + } + void set(uint index, std::initializer_list> value) { + KJ_IREQUIRE(index < size()); + auto l = init(index, value.size()); + uint i = 0; + for (auto& element: value) { + l.set(i++, element); + } + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator::Builder> Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List { + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return reader.getPointerElement(bounded(index) * ELEMENTS) + .template getBlob(nullptr, ZERO * BYTES); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(ElementSize::POINTER) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return builder.getPointerElement(bounded(index) * ELEMENTS) + .template getBlob(nullptr, ZERO * BYTES); + } + inline void set(uint index, typename T::Reader value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).template setBlob(value); + } + inline typename T::Builder init(uint index, uint size) { + KJ_IREQUIRE(index < this->size()); + return builder.getPointerElement(bounded(index) * ELEMENTS) + .template initBlob(bounded(size) * BYTES); + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +} // namespace capnp + +#ifdef KJ_STD_COMPAT +namespace std { + +template +struct iterator_traits> + : public std::iterator {}; + +} // namespace std +#endif // KJ_STD_COMPAT + +#endif // CAPNP_LIST_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/membrane.h --- a/osx/include/capnp/membrane.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/membrane.h Mon May 22 10:01:37 2017 +0100 @@ -1,202 +1,202 @@ -// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_MEMBRANE_H_ -#define CAPNP_MEMBRANE_H_ -// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards -// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a -// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely -// introducing new objects. -// -// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability -// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this -// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice -// indicates it should be revoked, after which all calls through the wrapper will throw exceptions. -// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new -// capability in that call, or if Carol returns a capability to Bob in the response to a call, then -// the two are now able to communicate using this new capability, which Alice cannot revoke. In -// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which -// recursively wraps all objects that pass through it in either direction. Thus, all connections -// formed between Bob and Carol (originating from Alice's original introduction) can be revoked -// together by revoking the membrane. -// -// Note that when a capability is passed into a membrane and then passed back out, the result is -// the original capability, not a double-membraned capability. This means that in our revocation -// example, if Bob uses his capability to Carol to obtain another capability from her, then send -// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to -// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use -// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then -// passed back can be recognized as the original capability. -// -// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html - -#include "capability.h" - -namespace capnp { - -class MembranePolicy { - // Applications may implement this interface to define a membrane policy, which allows some - // calls crossing the membrane to be blocked or redirected. - -public: - virtual kj::Maybe inboundCall( - uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; - // Given an inbound call (a call originating "outside" the membrane destined for an object - // "inside" the membrane), decides what to do with it. The policy may: - // - // - Return null to indicate that the call should proceed to the destination. All capabilities - // in the parameters or result will be properly wrapped in the same membrane. - // - Return a capability to have the call redirected to that capability. Note that the redirect - // capability will be treated as outside the membrane, so the params and results will not be - // auto-wrapped; however, the callee can easily wrap the returned capability in the membrane - // itself before returning to achieve this effect. - // - Throw an exception to cause the call to fail with that exception. - // - // `target` is the underlying capability (*inside* the membrane) for which the call is destined. - // Generally, the only way you should use `target` is to wrap it in some capability which you - // return as a redirect. The redirect capability may modify the call in some way and send it to - // `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when - // copying parameters or results across the membrane. - // - // Note that since `target` is inside the capability, if you were to directly return it (rather - // than return null), the effect would be that the membrane would be broken: the call would - // proceed directly and any new capabilities introduced through it would not be membraned. You - // generally should not do that. - - virtual kj::Maybe outboundCall( - uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; - // Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating - // outside. - // - // Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases - // that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would - // redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run - // into inconsistent behavion when a promise is returned across a membrane, and that promise - // later resolves to a capability on the other side of the membrane: calls on the promise - // will enter and then exit the membrane, but calls on the eventual resolution will not cross - // the membrane at all, so it is important that these two cases behave the same. - - virtual kj::Own addRef() = 0; - // Return a new owned pointer to the same policy. - // - // Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement - // `addRef()` as `return kj::addRef(*this);`. - // - // Note that the membraning system considers two membranes created with the same MembranePolicy - // object actually to be the *same* membrane. This is relevant when an object passes into the - // membrane and then back out (or out and then back in): instead of double-wrapping the object, - // the wrapping will be removed. -}; - -Capability::Client membrane(Capability::Client inner, kj::Own policy); -// Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane, -// while the returned capability should only be called from outside the membrane. - -Capability::Client reverseMembrane(Capability::Client outer, kj::Own policy); -// Like `membrane` but treat the input capability as "outside" the membrane, and return a -// capability appropriate for use inside. -// -// Applications typically won't use this directly; the membraning code automatically sets up -// reverse membranes where needed. - -template -ClientType membrane(ClientType inner, kj::Own policy); -template -ClientType reverseMembrane(ClientType inner, kj::Own policy); -// Convenience templates which return the same interface type as the input. - -template -typename ServerType::Serves::Client membrane( - kj::Own inner, kj::Own policy); -template -typename ServerType::Serves::Client reverseMembrane( - kj::Own inner, kj::Own policy); -// Convenience templates which input a capability server type and return the appropriate client -// type. - -template -Orphan::Reads> copyIntoMembrane( - Reader&& from, Orphanage to, kj::Own policy); -// Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities -// found within it. `from` is interpreted as "outside" the membrane while `to` is "inside". - -template -Orphan::Reads> copyOutOfMembrane( - Reader&& from, Orphanage to, kj::Own policy); -// Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside". - -// ======================================================================================= -// inline implementation details - -template -ClientType membrane(ClientType inner, kj::Own policy) { - return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) - .castAs(); -} -template -ClientType reverseMembrane(ClientType inner, kj::Own policy) { - return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) - .castAs(); -} - -template -typename ServerType::Serves::Client membrane( - kj::Own inner, kj::Own policy) { - return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) - .castAs(); -} -template -typename ServerType::Serves::Client reverseMembrane( - kj::Own inner, kj::Own policy) { - return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) - .castAs(); -} - -namespace _ { // private - -OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to, - kj::Own policy, bool reverse); -OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to, - kj::Own policy, bool reverse); -OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to, - kj::Own policy, bool reverse); - -} // namespace _ (private) - -template -Orphan::Reads> copyIntoMembrane( - Reader&& from, Orphanage to, kj::Own policy) { - return _::copyOutOfMembrane( - _::PointerHelpers::Reads>::getInternalReader(from), - to, kj::mv(policy), true); -} - -template -Orphan::Reads> copyOutOfMembrane( - Reader&& from, Orphanage to, kj::Own policy) { - return _::copyOutOfMembrane( - _::PointerHelpers::Reads>::getInternalReader(from), - to, kj::mv(policy), false); -} - -} // namespace capnp - -#endif // CAPNP_MEMBRANE_H_ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_MEMBRANE_H_ +#define CAPNP_MEMBRANE_H_ +// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards +// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a +// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely +// introducing new objects. +// +// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability +// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this +// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice +// indicates it should be revoked, after which all calls through the wrapper will throw exceptions. +// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new +// capability in that call, or if Carol returns a capability to Bob in the response to a call, then +// the two are now able to communicate using this new capability, which Alice cannot revoke. In +// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which +// recursively wraps all objects that pass through it in either direction. Thus, all connections +// formed between Bob and Carol (originating from Alice's original introduction) can be revoked +// together by revoking the membrane. +// +// Note that when a capability is passed into a membrane and then passed back out, the result is +// the original capability, not a double-membraned capability. This means that in our revocation +// example, if Bob uses his capability to Carol to obtain another capability from her, then send +// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to +// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use +// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then +// passed back can be recognized as the original capability. +// +// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html + +#include "capability.h" + +namespace capnp { + +class MembranePolicy { + // Applications may implement this interface to define a membrane policy, which allows some + // calls crossing the membrane to be blocked or redirected. + +public: + virtual kj::Maybe inboundCall( + uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; + // Given an inbound call (a call originating "outside" the membrane destined for an object + // "inside" the membrane), decides what to do with it. The policy may: + // + // - Return null to indicate that the call should proceed to the destination. All capabilities + // in the parameters or result will be properly wrapped in the same membrane. + // - Return a capability to have the call redirected to that capability. Note that the redirect + // capability will be treated as outside the membrane, so the params and results will not be + // auto-wrapped; however, the callee can easily wrap the returned capability in the membrane + // itself before returning to achieve this effect. + // - Throw an exception to cause the call to fail with that exception. + // + // `target` is the underlying capability (*inside* the membrane) for which the call is destined. + // Generally, the only way you should use `target` is to wrap it in some capability which you + // return as a redirect. The redirect capability may modify the call in some way and send it to + // `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when + // copying parameters or results across the membrane. + // + // Note that since `target` is inside the capability, if you were to directly return it (rather + // than return null), the effect would be that the membrane would be broken: the call would + // proceed directly and any new capabilities introduced through it would not be membraned. You + // generally should not do that. + + virtual kj::Maybe outboundCall( + uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; + // Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating + // outside. + // + // Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases + // that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would + // redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run + // into inconsistent behavion when a promise is returned across a membrane, and that promise + // later resolves to a capability on the other side of the membrane: calls on the promise + // will enter and then exit the membrane, but calls on the eventual resolution will not cross + // the membrane at all, so it is important that these two cases behave the same. + + virtual kj::Own addRef() = 0; + // Return a new owned pointer to the same policy. + // + // Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement + // `addRef()` as `return kj::addRef(*this);`. + // + // Note that the membraning system considers two membranes created with the same MembranePolicy + // object actually to be the *same* membrane. This is relevant when an object passes into the + // membrane and then back out (or out and then back in): instead of double-wrapping the object, + // the wrapping will be removed. +}; + +Capability::Client membrane(Capability::Client inner, kj::Own policy); +// Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane, +// while the returned capability should only be called from outside the membrane. + +Capability::Client reverseMembrane(Capability::Client outer, kj::Own policy); +// Like `membrane` but treat the input capability as "outside" the membrane, and return a +// capability appropriate for use inside. +// +// Applications typically won't use this directly; the membraning code automatically sets up +// reverse membranes where needed. + +template +ClientType membrane(ClientType inner, kj::Own policy); +template +ClientType reverseMembrane(ClientType inner, kj::Own policy); +// Convenience templates which return the same interface type as the input. + +template +typename ServerType::Serves::Client membrane( + kj::Own inner, kj::Own policy); +template +typename ServerType::Serves::Client reverseMembrane( + kj::Own inner, kj::Own policy); +// Convenience templates which input a capability server type and return the appropriate client +// type. + +template +Orphan::Reads> copyIntoMembrane( + Reader&& from, Orphanage to, kj::Own policy); +// Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities +// found within it. `from` is interpreted as "outside" the membrane while `to` is "inside". + +template +Orphan::Reads> copyOutOfMembrane( + Reader&& from, Orphanage to, kj::Own policy); +// Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside". + +// ======================================================================================= +// inline implementation details + +template +ClientType membrane(ClientType inner, kj::Own policy) { + return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} +template +ClientType reverseMembrane(ClientType inner, kj::Own policy) { + return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} + +template +typename ServerType::Serves::Client membrane( + kj::Own inner, kj::Own policy) { + return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} +template +typename ServerType::Serves::Client reverseMembrane( + kj::Own inner, kj::Own policy) { + return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} + +namespace _ { // private + +OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to, + kj::Own policy, bool reverse); +OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to, + kj::Own policy, bool reverse); +OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to, + kj::Own policy, bool reverse); + +} // namespace _ (private) + +template +Orphan::Reads> copyIntoMembrane( + Reader&& from, Orphanage to, kj::Own policy) { + return _::copyOutOfMembrane( + _::PointerHelpers::Reads>::getInternalReader(from), + to, kj::mv(policy), true); +} + +template +Orphan::Reads> copyOutOfMembrane( + Reader&& from, Orphanage to, kj::Own policy) { + return _::copyOutOfMembrane( + _::PointerHelpers::Reads>::getInternalReader(from), + to, kj::mv(policy), false); +} + +} // namespace capnp + +#endif // CAPNP_MEMBRANE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/message.h --- a/osx/include/capnp/message.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/message.h Mon May 22 10:01:37 2017 +0100 @@ -1,508 +1,508 @@ -// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include -#include "common.h" -#include "layout.h" -#include "any.h" - -#ifndef CAPNP_MESSAGE_H_ -#define CAPNP_MESSAGE_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -namespace capnp { - -namespace _ { // private - class ReaderArena; - class BuilderArena; -} - -class StructSchema; -class Orphanage; -template -class Orphan; - -// ======================================================================================= - -struct ReaderOptions { - // Options controlling how data is read. - - uint64_t traversalLimitInWords = 8 * 1024 * 1024; - // Limits how many total words of data are allowed to be traversed. Traversal is counted when - // a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling - // the getter for the same sub-struct multiple times will cause it to be double-counted. Once - // the traversal limit is reached, an error will be reported. - // - // This limit exists for security reasons. It is possible for an attacker to construct a message - // in which multiple pointers point at the same location. This is technically invalid, but hard - // to detect. Using such a message, an attacker could cause a message which is small on the wire - // to appear much larger when actually traversed, possibly exhausting server resources leading to - // denial-of-service. - // - // It makes sense to set a traversal limit that is much larger than the underlying message. - // Together with sensible coding practices (e.g. trying to avoid calling sub-object getters - // multiple times, which is expensive anyway), this should provide adequate protection without - // inconvenience. - // - // The default limit is 64 MiB. This may or may not be a sensible number for any given use case, - // but probably at least prevents easy exploitation while also avoiding causing problems in most - // typical cases. - - int nestingLimit = 64; - // Limits how deeply-nested a message structure can be, e.g. structs containing other structs or - // lists of structs. - // - // Like the traversal limit, this limit exists for security reasons. Since it is common to use - // recursive code to traverse recursive data structures, an attacker could easily cause a stack - // overflow by sending a very-deeply-nested (or even cyclic) message, without the message even - // being very large. The default limit of 64 is probably low enough to prevent any chance of - // stack overflow, yet high enough that it is never a problem in practice. -}; - -class MessageReader { - // Abstract interface for an object used to read a Cap'n Proto message. Subclasses of - // MessageReader are responsible for reading the raw, flat message content. Callers should - // usually call `messageReader.getRoot()` to get a `MyStructType::Reader` - // representing the root of the message, then use that to traverse the message content. - // - // Some common subclasses of `MessageReader` include `SegmentArrayMessageReader`, whose - // constructor accepts pointers to the raw data, and `StreamFdMessageReader` (from - // `serialize.h`), which reads the message from a file descriptor. One might implement other - // subclasses to handle things like reading from shared memory segments, mmap()ed files, etc. - -public: - MessageReader(ReaderOptions options); - // It is suggested that subclasses take ReaderOptions as a constructor parameter, but give it a - // default value of "ReaderOptions()". The base class constructor doesn't have a default value - // in order to remind subclasses that they really need to give the user a way to provide this. - - virtual ~MessageReader() noexcept(false); - - virtual kj::ArrayPtr getSegment(uint id) = 0; - // Gets the segment with the given ID, or returns null if no such segment exists. This method - // will be called at most once for each segment ID. - - inline const ReaderOptions& getOptions(); - // Get the options passed to the constructor. - - template - typename RootType::Reader getRoot(); - // Get the root struct of the message, interpreting it as the given struct type. - - template - typename RootType::Reader getRoot(SchemaType schema); - // Dynamically interpret the root struct of the message using the given schema (a StructSchema). - // RootType in this case must be DynamicStruct, and you must #include to - // use this. - - bool isCanonical(); - // Returns whether the message encoded in the reader is in canonical form. - -private: - ReaderOptions options; - - // Space in which we can construct a ReaderArena. We don't use ReaderArena directly here - // because we don't want clients to have to #include arena.h, which itself includes a bunch of - // big STL headers. We don't use a pointer to a ReaderArena because that would require an - // extra malloc on every message which could be expensive when processing small messages. - void* arenaSpace[15 + sizeof(kj::MutexGuarded) / sizeof(void*)]; - bool allocatedArena; - - _::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); } - AnyPointer::Reader getRootInternal(); -}; - -class MessageBuilder { - // Abstract interface for an object used to allocate and build a message. Subclasses of - // MessageBuilder are responsible for allocating the space in which the message will be written. - // The most common subclass is `MallocMessageBuilder`, but other subclasses may be used to do - // tricky things like allocate messages in shared memory or mmap()ed files. - // - // Creating a new message ususually means allocating a new MessageBuilder (ideally on the stack) - // and then calling `messageBuilder.initRoot()` to get a `MyStructType::Builder`. - // That, in turn, can be used to fill in the message content. When done, you can call - // `messageBuilder.getSegmentsForOutput()` to get a list of flat data arrays containing the - // message. - -public: - MessageBuilder(); - virtual ~MessageBuilder() noexcept(false); - KJ_DISALLOW_COPY(MessageBuilder); - - struct SegmentInit { - kj::ArrayPtr space; - - size_t wordsUsed; - // Number of words in `space` which are used; the rest are free space in which additional - // objects may be allocated. - }; - - explicit MessageBuilder(kj::ArrayPtr segments); - // Create a MessageBuilder backed by existing memory. This is an advanced interface that most - // people should not use. THIS METHOD IS INSECURE; see below. - // - // This allows a MessageBuilder to be constructed to modify an in-memory message without first - // making a copy of the content. This is especially useful in conjunction with mmap(). - // - // The contents of each segment must outlive the MessageBuilder, but the SegmentInit array itself - // only need outlive the constructor. - // - // SECURITY: Do not use this in conjunction with untrusted data. This constructor assumes that - // the input message is valid. This constructor is designed to be used with data you control, - // e.g. an mmap'd file which is owned and accessed by only one program. When reading data you - // do not trust, you *must* load it into a Reader and then copy into a Builder as a means of - // validating the content. - // - // WARNING: It is NOT safe to initialize a MessageBuilder in this way from memory that is - // currently in use by another MessageBuilder or MessageReader. Other readers/builders will - // not observe changes to the segment sizes nor newly-allocated segments caused by allocating - // new objects in this message. - - virtual kj::ArrayPtr allocateSegment(uint minimumSize) = 0; - // Allocates an array of at least the given number of words, throwing an exception or crashing if - // this is not possible. It is expected that this method will usually return more space than - // requested, and the caller should use that extra space as much as possible before allocating - // more. The returned space remains valid at least until the MessageBuilder is destroyed. - // - // Cap'n Proto will only call this once at a time, so the subclass need not worry about - // thread-safety. - - template - typename RootType::Builder initRoot(); - // Initialize the root struct of the message as the given struct type. - - template - void setRoot(Reader&& value); - // Set the root struct to a deep copy of the given struct. - - template - typename RootType::Builder getRoot(); - // Get the root struct of the message, interpreting it as the given struct type. - - template - typename RootType::Builder getRoot(SchemaType schema); - // Dynamically interpret the root struct of the message using the given schema (a StructSchema). - // RootType in this case must be DynamicStruct, and you must #include to - // use this. - - template - typename RootType::Builder initRoot(SchemaType schema); - // Dynamically init the root struct of the message using the given schema (a StructSchema). - // RootType in this case must be DynamicStruct, and you must #include to - // use this. - - template - void adoptRoot(Orphan&& orphan); - // Like setRoot() but adopts the orphan without copying. - - kj::ArrayPtr> getSegmentsForOutput(); - // Get the raw data that makes up the message. - - Orphanage getOrphanage(); - - bool isCanonical(); - // Check whether the message builder is in canonical form - -private: - void* arenaSpace[22]; - // Space in which we can construct a BuilderArena. We don't use BuilderArena directly here - // because we don't want clients to have to #include arena.h, which itself includes a bunch of - // big STL headers. We don't use a pointer to a BuilderArena because that would require an - // extra malloc on every message which could be expensive when processing small messages. - - bool allocatedArena = false; - // We have to initialize the arena lazily because when we do so we want to allocate the root - // pointer immediately, and this will allocate a segment, which requires a virtual function - // call on the MessageBuilder. We can't do such a call in the constructor since the subclass - // isn't constructed yet. This is kind of annoying because it means that getOrphanage() is - // not thread-safe, but that shouldn't be a huge deal... - - _::BuilderArena* arena() { return reinterpret_cast<_::BuilderArena*>(arenaSpace); } - _::SegmentBuilder* getRootSegment(); - AnyPointer::Builder getRootInternal(); -}; - -template -typename RootType::Reader readMessageUnchecked(const word* data); -// IF THE INPUT IS INVALID, THIS MAY CRASH, CORRUPT MEMORY, CREATE A SECURITY HOLE IN YOUR APP, -// MURDER YOUR FIRST-BORN CHILD, AND/OR BRING ABOUT ETERNAL DAMNATION ON ALL OF HUMANITY. DO NOT -// USE UNLESS YOU UNDERSTAND THE CONSEQUENCES. -// -// Given a pointer to a known-valid message located in a single contiguous memory segment, -// returns a reader for that message. No bounds-checking will be done while traversing this -// message. Use this only if you have already verified that all pointers are valid and in-bounds, -// and there are no far pointers in the message. -// -// To create a message that can be passed to this function, build a message using a MallocAllocator -// whose preferred segment size is larger than the message size. This guarantees that the message -// will be allocated as a single segment, meaning getSegmentsForOutput() returns a single word -// array. That word array is your message; you may pass a pointer to its first word into -// readMessageUnchecked() to read the message. -// -// This can be particularly handy for embedding messages in generated code: you can -// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way -// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have -// a message MyMessage, you can read its default value like so: -// MyMessage::Reader reader = Message::readMessageUnchecked(MyMessage::DEFAULT.words); -// -// To sanitize a message from an untrusted source such that it can be safely passed to -// readMessageUnchecked(), use copyToUnchecked(). - -template -void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer); -// Copy the content of the given reader into the given buffer, such that it can safely be passed to -// readMessageUnchecked(). The buffer's size must be exactly reader.totalSizeInWords() + 1, -// otherwise an exception will be thrown. The buffer must be zero'd before calling. - -template -typename RootType::Reader readDataStruct(kj::ArrayPtr data); -// Interprets the given data as a single, data-only struct. Only primitive fields (booleans, -// numbers, and enums) will be readable; all pointers will be null. This is useful if you want -// to use Cap'n Proto as a language/platform-neutral way to pack some bits. -// -// The input is a word array rather than a byte array to enforce alignment. If you have a byte -// array which you know is word-aligned (or if your platform supports unaligned reads and you don't -// mind the performance penalty), then you can use `reinterpret_cast` to convert a byte array into -// a word array: -// -// kj::arrayPtr(reinterpret_cast(bytes.begin()), -// reinterpret_cast(bytes.end())) - -template -typename kj::ArrayPtr writeDataStruct(BuilderType builder); -// Given a struct builder, get the underlying data section as a word array, suitable for passing -// to `readDataStruct()`. -// -// Note that you may call `.toBytes()` on the returned value to convert to `ArrayPtr`. - -template -static typename Type::Reader defaultValue(); -// Get a default instance of the given struct or list type. -// -// TODO(cleanup): Find a better home for this function? - -// ======================================================================================= - -class SegmentArrayMessageReader: public MessageReader { - // A simple MessageReader that reads from an array of word arrays representing all segments. - // In particular you can read directly from the output of MessageBuilder::getSegmentsForOutput() - // (although it would probably make more sense to call builder.getRoot().asReader() in that case). - -public: - SegmentArrayMessageReader(kj::ArrayPtr> segments, - ReaderOptions options = ReaderOptions()); - // Creates a message pointing at the given segment array, without taking ownership of the - // segments. All arrays passed in must remain valid until the MessageReader is destroyed. - - KJ_DISALLOW_COPY(SegmentArrayMessageReader); - ~SegmentArrayMessageReader() noexcept(false); - - virtual kj::ArrayPtr getSegment(uint id) override; - -private: - kj::ArrayPtr> segments; -}; - -enum class AllocationStrategy: uint8_t { - FIXED_SIZE, - // The builder will prefer to allocate the same amount of space for each segment with no - // heuristic growth. It will still allocate larger segments when the preferred size is too small - // for some single object. This mode is generally not recommended, but can be particularly useful - // for testing in order to force a message to allocate a predictable number of segments. Note - // that you can force every single object in the message to be located in a separate segment by - // using this mode with firstSegmentWords = 0. - - GROW_HEURISTICALLY - // The builder will heuristically decide how much space to allocate for each segment. Each - // allocated segment will be progressively larger than the previous segments on the assumption - // that message sizes are exponentially distributed. The total number of segments that will be - // allocated for a message of size n is O(log n). -}; - -constexpr uint SUGGESTED_FIRST_SEGMENT_WORDS = 1024; -constexpr AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy::GROW_HEURISTICALLY; - -class MallocMessageBuilder: public MessageBuilder { - // A simple MessageBuilder that uses malloc() (actually, calloc()) to allocate segments. This - // implementation should be reasonable for any case that doesn't require writing the message to - // a specific location in memory. - -public: - explicit MallocMessageBuilder(uint firstSegmentWords = SUGGESTED_FIRST_SEGMENT_WORDS, - AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); - // Creates a BuilderContext which allocates at least the given number of words for the first - // segment, and then uses the given strategy to decide how much to allocate for subsequent - // segments. When choosing a value for firstSegmentWords, consider that: - // 1) Reading and writing messages gets slower when multiple segments are involved, so it's good - // if most messages fit in a single segment. - // 2) Unused bytes will not be written to the wire, so generally it is not a big deal to allocate - // more space than you need. It only becomes problematic if you are allocating many messages - // in parallel and thus use lots of memory, or if you allocate so much extra space that just - // zeroing it out becomes a bottleneck. - // The defaults have been chosen to be reasonable for most people, so don't change them unless you - // have reason to believe you need to. - - explicit MallocMessageBuilder(kj::ArrayPtr firstSegment, - AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); - // This version always returns the given array for the first segment, and then proceeds with the - // allocation strategy. This is useful for optimization when building lots of small messages in - // a tight loop: you can reuse the space for the first segment. - // - // firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros - // over any space that was used so that it can be reused. - - KJ_DISALLOW_COPY(MallocMessageBuilder); - virtual ~MallocMessageBuilder() noexcept(false); - - virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; - -private: - uint nextSize; - AllocationStrategy allocationStrategy; - - bool ownFirstSegment; - bool returnedFirstSegment; - - void* firstSegment; - - struct MoreSegments; - kj::Maybe> moreSegments; -}; - -class FlatMessageBuilder: public MessageBuilder { - // THIS IS NOT THE CLASS YOU'RE LOOKING FOR. - // - // If you want to write a message into already-existing scratch space, use `MallocMessageBuilder` - // and pass the scratch space to its constructor. It will then only fall back to malloc() if - // the scratch space is not large enough. - // - // Do NOT use this class unless you really know what you're doing. This class is problematic - // because it requires advance knowledge of the size of your message, which is usually impossible - // to determine without actually building the message. The class was created primarily to - // implement `copyToUnchecked()`, which itself exists only to support other internal parts of - // the Cap'n Proto implementation. - -public: - explicit FlatMessageBuilder(kj::ArrayPtr array); - KJ_DISALLOW_COPY(FlatMessageBuilder); - virtual ~FlatMessageBuilder() noexcept(false); - - void requireFilled(); - // Throws an exception if the flat array is not exactly full. - - virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; - -private: - kj::ArrayPtr array; - bool allocated; -}; - -// ======================================================================================= -// implementation details - -inline const ReaderOptions& MessageReader::getOptions() { - return options; -} - -template -inline typename RootType::Reader MessageReader::getRoot() { - return getRootInternal().getAs(); -} - -template -inline typename RootType::Builder MessageBuilder::initRoot() { - return getRootInternal().initAs(); -} - -template -inline void MessageBuilder::setRoot(Reader&& value) { - getRootInternal().setAs>(value); -} - -template -inline typename RootType::Builder MessageBuilder::getRoot() { - return getRootInternal().getAs(); -} - -template -void MessageBuilder::adoptRoot(Orphan&& orphan) { - return getRootInternal().adopt(kj::mv(orphan)); -} - -template -typename RootType::Reader MessageReader::getRoot(SchemaType schema) { - return getRootInternal().getAs(schema); -} - -template -typename RootType::Builder MessageBuilder::getRoot(SchemaType schema) { - return getRootInternal().getAs(schema); -} - -template -typename RootType::Builder MessageBuilder::initRoot(SchemaType schema) { - return getRootInternal().initAs(schema); -} - -template -typename RootType::Reader readMessageUnchecked(const word* data) { - return AnyPointer::Reader(_::PointerReader::getRootUnchecked(data)).getAs(); -} - -template -void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer) { - FlatMessageBuilder builder(uncheckedBuffer); - builder.setRoot(kj::fwd(reader)); - builder.requireFilled(); -} - -template -typename RootType::Reader readDataStruct(kj::ArrayPtr data) { - return typename RootType::Reader(_::StructReader(data)); -} - -template -typename kj::ArrayPtr writeDataStruct(BuilderType builder) { - auto bytes = _::PointerHelpers>::getInternalBuilder(kj::mv(builder)) - .getDataSectionAsBlob(); - return kj::arrayPtr(reinterpret_cast(bytes.begin()), - reinterpret_cast(bytes.end())); -} - -template -static typename Type::Reader defaultValue() { - return typename Type::Reader(_::StructReader()); -} - -template -kj::Array canonicalize(T&& reader) { - return _::PointerHelpers>::getInternalReader(reader).canonicalize(); -} - -} // namespace capnp - -#endif // CAPNP_MESSAGE_H_ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include +#include "common.h" +#include "layout.h" +#include "any.h" + +#ifndef CAPNP_MESSAGE_H_ +#define CAPNP_MESSAGE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +namespace capnp { + +namespace _ { // private + class ReaderArena; + class BuilderArena; +} + +class StructSchema; +class Orphanage; +template +class Orphan; + +// ======================================================================================= + +struct ReaderOptions { + // Options controlling how data is read. + + uint64_t traversalLimitInWords = 8 * 1024 * 1024; + // Limits how many total words of data are allowed to be traversed. Traversal is counted when + // a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling + // the getter for the same sub-struct multiple times will cause it to be double-counted. Once + // the traversal limit is reached, an error will be reported. + // + // This limit exists for security reasons. It is possible for an attacker to construct a message + // in which multiple pointers point at the same location. This is technically invalid, but hard + // to detect. Using such a message, an attacker could cause a message which is small on the wire + // to appear much larger when actually traversed, possibly exhausting server resources leading to + // denial-of-service. + // + // It makes sense to set a traversal limit that is much larger than the underlying message. + // Together with sensible coding practices (e.g. trying to avoid calling sub-object getters + // multiple times, which is expensive anyway), this should provide adequate protection without + // inconvenience. + // + // The default limit is 64 MiB. This may or may not be a sensible number for any given use case, + // but probably at least prevents easy exploitation while also avoiding causing problems in most + // typical cases. + + int nestingLimit = 64; + // Limits how deeply-nested a message structure can be, e.g. structs containing other structs or + // lists of structs. + // + // Like the traversal limit, this limit exists for security reasons. Since it is common to use + // recursive code to traverse recursive data structures, an attacker could easily cause a stack + // overflow by sending a very-deeply-nested (or even cyclic) message, without the message even + // being very large. The default limit of 64 is probably low enough to prevent any chance of + // stack overflow, yet high enough that it is never a problem in practice. +}; + +class MessageReader { + // Abstract interface for an object used to read a Cap'n Proto message. Subclasses of + // MessageReader are responsible for reading the raw, flat message content. Callers should + // usually call `messageReader.getRoot()` to get a `MyStructType::Reader` + // representing the root of the message, then use that to traverse the message content. + // + // Some common subclasses of `MessageReader` include `SegmentArrayMessageReader`, whose + // constructor accepts pointers to the raw data, and `StreamFdMessageReader` (from + // `serialize.h`), which reads the message from a file descriptor. One might implement other + // subclasses to handle things like reading from shared memory segments, mmap()ed files, etc. + +public: + MessageReader(ReaderOptions options); + // It is suggested that subclasses take ReaderOptions as a constructor parameter, but give it a + // default value of "ReaderOptions()". The base class constructor doesn't have a default value + // in order to remind subclasses that they really need to give the user a way to provide this. + + virtual ~MessageReader() noexcept(false); + + virtual kj::ArrayPtr getSegment(uint id) = 0; + // Gets the segment with the given ID, or returns null if no such segment exists. This method + // will be called at most once for each segment ID. + + inline const ReaderOptions& getOptions(); + // Get the options passed to the constructor. + + template + typename RootType::Reader getRoot(); + // Get the root struct of the message, interpreting it as the given struct type. + + template + typename RootType::Reader getRoot(SchemaType schema); + // Dynamically interpret the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + bool isCanonical(); + // Returns whether the message encoded in the reader is in canonical form. + +private: + ReaderOptions options; + + // Space in which we can construct a ReaderArena. We don't use ReaderArena directly here + // because we don't want clients to have to #include arena.h, which itself includes a bunch of + // big STL headers. We don't use a pointer to a ReaderArena because that would require an + // extra malloc on every message which could be expensive when processing small messages. + void* arenaSpace[15 + sizeof(kj::MutexGuarded) / sizeof(void*)]; + bool allocatedArena; + + _::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); } + AnyPointer::Reader getRootInternal(); +}; + +class MessageBuilder { + // Abstract interface for an object used to allocate and build a message. Subclasses of + // MessageBuilder are responsible for allocating the space in which the message will be written. + // The most common subclass is `MallocMessageBuilder`, but other subclasses may be used to do + // tricky things like allocate messages in shared memory or mmap()ed files. + // + // Creating a new message ususually means allocating a new MessageBuilder (ideally on the stack) + // and then calling `messageBuilder.initRoot()` to get a `MyStructType::Builder`. + // That, in turn, can be used to fill in the message content. When done, you can call + // `messageBuilder.getSegmentsForOutput()` to get a list of flat data arrays containing the + // message. + +public: + MessageBuilder(); + virtual ~MessageBuilder() noexcept(false); + KJ_DISALLOW_COPY(MessageBuilder); + + struct SegmentInit { + kj::ArrayPtr space; + + size_t wordsUsed; + // Number of words in `space` which are used; the rest are free space in which additional + // objects may be allocated. + }; + + explicit MessageBuilder(kj::ArrayPtr segments); + // Create a MessageBuilder backed by existing memory. This is an advanced interface that most + // people should not use. THIS METHOD IS INSECURE; see below. + // + // This allows a MessageBuilder to be constructed to modify an in-memory message without first + // making a copy of the content. This is especially useful in conjunction with mmap(). + // + // The contents of each segment must outlive the MessageBuilder, but the SegmentInit array itself + // only need outlive the constructor. + // + // SECURITY: Do not use this in conjunction with untrusted data. This constructor assumes that + // the input message is valid. This constructor is designed to be used with data you control, + // e.g. an mmap'd file which is owned and accessed by only one program. When reading data you + // do not trust, you *must* load it into a Reader and then copy into a Builder as a means of + // validating the content. + // + // WARNING: It is NOT safe to initialize a MessageBuilder in this way from memory that is + // currently in use by another MessageBuilder or MessageReader. Other readers/builders will + // not observe changes to the segment sizes nor newly-allocated segments caused by allocating + // new objects in this message. + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) = 0; + // Allocates an array of at least the given number of words, throwing an exception or crashing if + // this is not possible. It is expected that this method will usually return more space than + // requested, and the caller should use that extra space as much as possible before allocating + // more. The returned space remains valid at least until the MessageBuilder is destroyed. + // + // Cap'n Proto will only call this once at a time, so the subclass need not worry about + // thread-safety. + + template + typename RootType::Builder initRoot(); + // Initialize the root struct of the message as the given struct type. + + template + void setRoot(Reader&& value); + // Set the root struct to a deep copy of the given struct. + + template + typename RootType::Builder getRoot(); + // Get the root struct of the message, interpreting it as the given struct type. + + template + typename RootType::Builder getRoot(SchemaType schema); + // Dynamically interpret the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + template + typename RootType::Builder initRoot(SchemaType schema); + // Dynamically init the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + template + void adoptRoot(Orphan&& orphan); + // Like setRoot() but adopts the orphan without copying. + + kj::ArrayPtr> getSegmentsForOutput(); + // Get the raw data that makes up the message. + + Orphanage getOrphanage(); + + bool isCanonical(); + // Check whether the message builder is in canonical form + +private: + void* arenaSpace[22]; + // Space in which we can construct a BuilderArena. We don't use BuilderArena directly here + // because we don't want clients to have to #include arena.h, which itself includes a bunch of + // big STL headers. We don't use a pointer to a BuilderArena because that would require an + // extra malloc on every message which could be expensive when processing small messages. + + bool allocatedArena = false; + // We have to initialize the arena lazily because when we do so we want to allocate the root + // pointer immediately, and this will allocate a segment, which requires a virtual function + // call on the MessageBuilder. We can't do such a call in the constructor since the subclass + // isn't constructed yet. This is kind of annoying because it means that getOrphanage() is + // not thread-safe, but that shouldn't be a huge deal... + + _::BuilderArena* arena() { return reinterpret_cast<_::BuilderArena*>(arenaSpace); } + _::SegmentBuilder* getRootSegment(); + AnyPointer::Builder getRootInternal(); +}; + +template +typename RootType::Reader readMessageUnchecked(const word* data); +// IF THE INPUT IS INVALID, THIS MAY CRASH, CORRUPT MEMORY, CREATE A SECURITY HOLE IN YOUR APP, +// MURDER YOUR FIRST-BORN CHILD, AND/OR BRING ABOUT ETERNAL DAMNATION ON ALL OF HUMANITY. DO NOT +// USE UNLESS YOU UNDERSTAND THE CONSEQUENCES. +// +// Given a pointer to a known-valid message located in a single contiguous memory segment, +// returns a reader for that message. No bounds-checking will be done while traversing this +// message. Use this only if you have already verified that all pointers are valid and in-bounds, +// and there are no far pointers in the message. +// +// To create a message that can be passed to this function, build a message using a MallocAllocator +// whose preferred segment size is larger than the message size. This guarantees that the message +// will be allocated as a single segment, meaning getSegmentsForOutput() returns a single word +// array. That word array is your message; you may pass a pointer to its first word into +// readMessageUnchecked() to read the message. +// +// This can be particularly handy for embedding messages in generated code: you can +// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way +// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have +// a message MyMessage, you can read its default value like so: +// MyMessage::Reader reader = Message::readMessageUnchecked(MyMessage::DEFAULT.words); +// +// To sanitize a message from an untrusted source such that it can be safely passed to +// readMessageUnchecked(), use copyToUnchecked(). + +template +void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer); +// Copy the content of the given reader into the given buffer, such that it can safely be passed to +// readMessageUnchecked(). The buffer's size must be exactly reader.totalSizeInWords() + 1, +// otherwise an exception will be thrown. The buffer must be zero'd before calling. + +template +typename RootType::Reader readDataStruct(kj::ArrayPtr data); +// Interprets the given data as a single, data-only struct. Only primitive fields (booleans, +// numbers, and enums) will be readable; all pointers will be null. This is useful if you want +// to use Cap'n Proto as a language/platform-neutral way to pack some bits. +// +// The input is a word array rather than a byte array to enforce alignment. If you have a byte +// array which you know is word-aligned (or if your platform supports unaligned reads and you don't +// mind the performance penalty), then you can use `reinterpret_cast` to convert a byte array into +// a word array: +// +// kj::arrayPtr(reinterpret_cast(bytes.begin()), +// reinterpret_cast(bytes.end())) + +template +typename kj::ArrayPtr writeDataStruct(BuilderType builder); +// Given a struct builder, get the underlying data section as a word array, suitable for passing +// to `readDataStruct()`. +// +// Note that you may call `.toBytes()` on the returned value to convert to `ArrayPtr`. + +template +static typename Type::Reader defaultValue(); +// Get a default instance of the given struct or list type. +// +// TODO(cleanup): Find a better home for this function? + +// ======================================================================================= + +class SegmentArrayMessageReader: public MessageReader { + // A simple MessageReader that reads from an array of word arrays representing all segments. + // In particular you can read directly from the output of MessageBuilder::getSegmentsForOutput() + // (although it would probably make more sense to call builder.getRoot().asReader() in that case). + +public: + SegmentArrayMessageReader(kj::ArrayPtr> segments, + ReaderOptions options = ReaderOptions()); + // Creates a message pointing at the given segment array, without taking ownership of the + // segments. All arrays passed in must remain valid until the MessageReader is destroyed. + + KJ_DISALLOW_COPY(SegmentArrayMessageReader); + ~SegmentArrayMessageReader() noexcept(false); + + virtual kj::ArrayPtr getSegment(uint id) override; + +private: + kj::ArrayPtr> segments; +}; + +enum class AllocationStrategy: uint8_t { + FIXED_SIZE, + // The builder will prefer to allocate the same amount of space for each segment with no + // heuristic growth. It will still allocate larger segments when the preferred size is too small + // for some single object. This mode is generally not recommended, but can be particularly useful + // for testing in order to force a message to allocate a predictable number of segments. Note + // that you can force every single object in the message to be located in a separate segment by + // using this mode with firstSegmentWords = 0. + + GROW_HEURISTICALLY + // The builder will heuristically decide how much space to allocate for each segment. Each + // allocated segment will be progressively larger than the previous segments on the assumption + // that message sizes are exponentially distributed. The total number of segments that will be + // allocated for a message of size n is O(log n). +}; + +constexpr uint SUGGESTED_FIRST_SEGMENT_WORDS = 1024; +constexpr AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy::GROW_HEURISTICALLY; + +class MallocMessageBuilder: public MessageBuilder { + // A simple MessageBuilder that uses malloc() (actually, calloc()) to allocate segments. This + // implementation should be reasonable for any case that doesn't require writing the message to + // a specific location in memory. + +public: + explicit MallocMessageBuilder(uint firstSegmentWords = SUGGESTED_FIRST_SEGMENT_WORDS, + AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); + // Creates a BuilderContext which allocates at least the given number of words for the first + // segment, and then uses the given strategy to decide how much to allocate for subsequent + // segments. When choosing a value for firstSegmentWords, consider that: + // 1) Reading and writing messages gets slower when multiple segments are involved, so it's good + // if most messages fit in a single segment. + // 2) Unused bytes will not be written to the wire, so generally it is not a big deal to allocate + // more space than you need. It only becomes problematic if you are allocating many messages + // in parallel and thus use lots of memory, or if you allocate so much extra space that just + // zeroing it out becomes a bottleneck. + // The defaults have been chosen to be reasonable for most people, so don't change them unless you + // have reason to believe you need to. + + explicit MallocMessageBuilder(kj::ArrayPtr firstSegment, + AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); + // This version always returns the given array for the first segment, and then proceeds with the + // allocation strategy. This is useful for optimization when building lots of small messages in + // a tight loop: you can reuse the space for the first segment. + // + // firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros + // over any space that was used so that it can be reused. + + KJ_DISALLOW_COPY(MallocMessageBuilder); + virtual ~MallocMessageBuilder() noexcept(false); + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; + +private: + uint nextSize; + AllocationStrategy allocationStrategy; + + bool ownFirstSegment; + bool returnedFirstSegment; + + void* firstSegment; + + struct MoreSegments; + kj::Maybe> moreSegments; +}; + +class FlatMessageBuilder: public MessageBuilder { + // THIS IS NOT THE CLASS YOU'RE LOOKING FOR. + // + // If you want to write a message into already-existing scratch space, use `MallocMessageBuilder` + // and pass the scratch space to its constructor. It will then only fall back to malloc() if + // the scratch space is not large enough. + // + // Do NOT use this class unless you really know what you're doing. This class is problematic + // because it requires advance knowledge of the size of your message, which is usually impossible + // to determine without actually building the message. The class was created primarily to + // implement `copyToUnchecked()`, which itself exists only to support other internal parts of + // the Cap'n Proto implementation. + +public: + explicit FlatMessageBuilder(kj::ArrayPtr array); + KJ_DISALLOW_COPY(FlatMessageBuilder); + virtual ~FlatMessageBuilder() noexcept(false); + + void requireFilled(); + // Throws an exception if the flat array is not exactly full. + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; + +private: + kj::ArrayPtr array; + bool allocated; +}; + +// ======================================================================================= +// implementation details + +inline const ReaderOptions& MessageReader::getOptions() { + return options; +} + +template +inline typename RootType::Reader MessageReader::getRoot() { + return getRootInternal().getAs(); +} + +template +inline typename RootType::Builder MessageBuilder::initRoot() { + return getRootInternal().initAs(); +} + +template +inline void MessageBuilder::setRoot(Reader&& value) { + getRootInternal().setAs>(value); +} + +template +inline typename RootType::Builder MessageBuilder::getRoot() { + return getRootInternal().getAs(); +} + +template +void MessageBuilder::adoptRoot(Orphan&& orphan) { + return getRootInternal().adopt(kj::mv(orphan)); +} + +template +typename RootType::Reader MessageReader::getRoot(SchemaType schema) { + return getRootInternal().getAs(schema); +} + +template +typename RootType::Builder MessageBuilder::getRoot(SchemaType schema) { + return getRootInternal().getAs(schema); +} + +template +typename RootType::Builder MessageBuilder::initRoot(SchemaType schema) { + return getRootInternal().initAs(schema); +} + +template +typename RootType::Reader readMessageUnchecked(const word* data) { + return AnyPointer::Reader(_::PointerReader::getRootUnchecked(data)).getAs(); +} + +template +void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer) { + FlatMessageBuilder builder(uncheckedBuffer); + builder.setRoot(kj::fwd(reader)); + builder.requireFilled(); +} + +template +typename RootType::Reader readDataStruct(kj::ArrayPtr data) { + return typename RootType::Reader(_::StructReader(data)); +} + +template +typename kj::ArrayPtr writeDataStruct(BuilderType builder) { + auto bytes = _::PointerHelpers>::getInternalBuilder(kj::mv(builder)) + .getDataSectionAsBlob(); + return kj::arrayPtr(reinterpret_cast(bytes.begin()), + reinterpret_cast(bytes.end())); +} + +template +static typename Type::Reader defaultValue() { + return typename Type::Reader(_::StructReader()); +} + +template +kj::Array canonicalize(T&& reader) { + return _::PointerHelpers>::getInternalReader(reader).canonicalize(); +} + +} // namespace capnp + +#endif // CAPNP_MESSAGE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/orphan.h --- a/osx/include/capnp/orphan.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/orphan.h Mon May 22 10:01:37 2017 +0100 @@ -1,440 +1,440 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_ORPHAN_H_ -#define CAPNP_ORPHAN_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "layout.h" - -namespace capnp { - -class StructSchema; -class ListSchema; -struct DynamicStruct; -struct DynamicList; -namespace _ { struct OrphanageInternal; } - -template -class Orphan { - // Represents an object which is allocated within some message builder but has no pointers - // pointing at it. An Orphan can later be "adopted" by some other object as one of that object's - // fields, without having to copy the orphan. For a field `foo` of pointer type, the generated - // code will define builder methods `void adoptFoo(Orphan)` and `Orphan disownFoo()`. - // Orphans can also be created independently of any parent using an Orphanage. - // - // `Orphan` can be moved but not copied, like `Own`, so that it is impossible for one - // orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its - // contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space - // in a message arena). - -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {} - - inline BuilderFor get(); - // Get the underlying builder. If the orphan is null, this will allocate and return a default - // object rather than crash. This is done for security -- otherwise, you might enable a DoS - // attack any time you disown a field and fail to check if it is null. In the case of structs, - // this means that the orphan is no longer null after get() returns. In the case of lists, - // no actual object is allocated since a simple empty ListBuilder can be returned. - - inline ReaderFor getReader() const; - - inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } - - inline void truncate(uint size); - // Resize an object (which must be a list or a blob) to the given size. - // - // If the new size is less than the original, the remaining elements will be discarded. The - // list is never moved in this case. If the list happens to be located at the end of its segment - // (which is always true if the list was the last thing allocated), the removed memory will be - // reclaimed (reducing the messag size), otherwise it is simply zeroed. The reclaiming behavior - // is particularly useful for allocating buffer space when you aren't sure how much space you - // actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and - // then truncate it back to the amount of space actually used. - // - // If the new size is greater than the original, the list is extended with default values. If - // the list is the last object in its segment *and* there is enough space left in the segment to - // extend it to cover the new values, then the list is extended in-place. Otherwise, it must be - // moved to a new location, leaving a zero'd hole in the previous space that won't be filled. - // This copy is shallow; sub-objects will simply be reparented, not copied. - // - // Any existing readers or builders pointing at the object are invalidated by this call (even if - // it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer. - -private: - _::OrphanBuilder builder; - - template - friend struct _::PointerHelpers; - template - friend struct List; - template - friend class Orphan; - friend class Orphanage; - friend class MessageBuilder; -}; - -class Orphanage: private kj::DisallowConstCopy { - // Use to directly allocate Orphan objects, without having a parent object allocate and then - // disown the object. - -public: - inline Orphanage(): arena(nullptr) {} - - template - static Orphanage getForMessageContaining(BuilderType builder); - // Construct an Orphanage that allocates within the message containing the given Builder. This - // allows the constructed Orphans to be adopted by objects within said message. - // - // This constructor takes the builder rather than having the builder have a getOrphanage() method - // because this is an advanced feature and we don't want to pollute the builder APIs with it. - // - // Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its - // `getOrphanage()` method. - - template - Orphan newOrphan() const; - // Allocate a new orphaned struct. - - template - Orphan newOrphan(uint size) const; - // Allocate a new orphaned list or blob. - - Orphan newOrphan(StructSchema schema) const; - // Dynamically create an orphan struct with the given schema. You must - // #include to use this. - - Orphan newOrphan(ListSchema schema, uint size) const; - // Dynamically create an orphan list with the given schema. You must #include - // to use this. - - template - Orphan> newOrphanCopy(Reader copyFrom) const; - // Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the - // given object. - - template - Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; - template - Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; - // Given an array of List readers, copy and concatenate the lists, creating a new Orphan. - // - // Note that compared to allocating the list yourself and using `setWithCaveats()` to set each - // item, this method avoids the "caveats": the new list will be allocated with the element size - // being the maximum of that from all the input lists. This is particularly important when - // concatenating struct lists: if the lists were created using a newer version of the protocol - // in which some new fields had been added to the struct, using `setWithCaveats()` would - // truncate off those new fields. - - Orphan referenceExternalData(Data::Reader data) const; - // Creates an Orphan that points at an existing region of memory (e.g. from another message) - // without copying it. There are some SEVERE restrictions on how this can be used: - // - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is - // abandoned). - // - Because the data is const, you will not be allowed to obtain a `Data::Builder` - // for this blob. Any call which would return such a builder will throw an exception. You - // can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once - // the orphan is adopted). It is your responsibility to make sure your code can deal with - // these problems when using this optimization; if you can't, allocate a copy instead. - // - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on - // the CPU). Any pointer returned by malloc() as well as any data blob obtained from another - // Cap'n Proto message satisfies this. - // - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte - // boundary will be visible in the raw message when it is written out. Thus, there must be no - // secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe - // as these bytes should be zero (unless the sender had the same problem). - // - // The array will actually become one of the message's segments. The data can thus be adopted - // into the message tree without copying it. This is particularly useful when referencing very - // large blobs, such as whole mmap'd files. - -private: - _::BuilderArena* arena; - _::CapTableBuilder* capTable; - - inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable) - : arena(arena), capTable(capTable) {} - - template - struct GetInnerBuilder; - template - struct GetInnerReader; - template - struct NewOrphanListImpl; - - friend class MessageBuilder; - friend struct _::OrphanageInternal; -}; - -// ======================================================================================= -// Inline implementation details. - -namespace _ { // private - -template -struct OrphanGetImpl; - -template -struct OrphanGetImpl { - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, _::elementSizeForType()); - } -}; - -template -struct OrphanGetImpl { - static inline typename T::Builder apply(_::OrphanBuilder& builder) { - return typename T::Builder(builder.asStruct(_::structSize())); - } - static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) { - return typename T::Reader(builder.asStructReader(_::structSize())); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, _::structSize()); - } -}; - -#if !CAPNP_LITE -template -struct OrphanGetImpl { - static inline typename T::Client apply(_::OrphanBuilder& builder) { - return typename T::Client(builder.asCapability()); - } - static inline typename T::Client applyReader(const _::OrphanBuilder& builder) { - return typename T::Client(builder.asCapability()); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, ElementSize::POINTER); - } -}; -#endif // !CAPNP_LITE - -template -struct OrphanGetImpl, Kind::LIST> { - static inline typename List::Builder apply(_::OrphanBuilder& builder) { - return typename List::Builder(builder.asList(_::ElementSizeForType::value)); - } - static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { - return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, ElementSize::POINTER); - } -}; - -template -struct OrphanGetImpl, Kind::LIST> { - static inline typename List::Builder apply(_::OrphanBuilder& builder) { - return typename List::Builder(builder.asStructList(_::structSize())); - } - static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { - return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, ElementSize::POINTER); - } -}; - -template <> -struct OrphanGetImpl { - static inline Text::Builder apply(_::OrphanBuilder& builder) { - return Text::Builder(builder.asText()); - } - static inline Text::Reader applyReader(const _::OrphanBuilder& builder) { - return Text::Reader(builder.asTextReader()); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, ElementSize::POINTER); - } -}; - -template <> -struct OrphanGetImpl { - static inline Data::Builder apply(_::OrphanBuilder& builder) { - return Data::Builder(builder.asData()); - } - static inline Data::Reader applyReader(const _::OrphanBuilder& builder) { - return Data::Reader(builder.asDataReader()); - } - static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { - builder.truncate(size, ElementSize::POINTER); - } -}; - -struct OrphanageInternal { - static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; } - static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; } -}; - -} // namespace _ (private) - -template -inline BuilderFor Orphan::get() { - return _::OrphanGetImpl::apply(builder); -} - -template -inline ReaderFor Orphan::getReader() const { - return _::OrphanGetImpl::applyReader(builder); -} - -template -inline void Orphan::truncate(uint size) { - _::OrphanGetImpl>::truncateListOf(builder, size * ELEMENTS); -} - -template <> -inline void Orphan::truncate(uint size) { - builder.truncateText(size * ELEMENTS); -} - -template <> -inline void Orphan::truncate(uint size) { - builder.truncate(size * ELEMENTS, ElementSize::BYTE); -} - -template -struct Orphanage::GetInnerBuilder { - static inline _::StructBuilder apply(typename T::Builder& t) { - return t._builder; - } -}; - -template -struct Orphanage::GetInnerBuilder { - static inline _::ListBuilder apply(typename T::Builder& t) { - return t.builder; - } -}; - -template -Orphanage Orphanage::getForMessageContaining(BuilderType builder) { - auto inner = GetInnerBuilder>::apply(builder); - return Orphanage(inner.getArena(), inner.getCapTable()); -} - -template -Orphan Orphanage::newOrphan() const { - return Orphan(_::OrphanBuilder::initStruct(arena, capTable, _::structSize())); -} - -template -struct Orphanage::NewOrphanListImpl> { - static inline _::OrphanBuilder apply( - _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { - return _::OrphanBuilder::initList( - arena, capTable, size * ELEMENTS, _::ElementSizeForType::value); - } -}; - -template -struct Orphanage::NewOrphanListImpl> { - static inline _::OrphanBuilder apply( - _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { - return _::OrphanBuilder::initStructList( - arena, capTable, size * ELEMENTS, _::structSize()); - } -}; - -template <> -struct Orphanage::NewOrphanListImpl { - static inline _::OrphanBuilder apply( - _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { - return _::OrphanBuilder::initText(arena, capTable, size * BYTES); - } -}; - -template <> -struct Orphanage::NewOrphanListImpl { - static inline _::OrphanBuilder apply( - _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { - return _::OrphanBuilder::initData(arena, capTable, size * BYTES); - } -}; - -template -Orphan Orphanage::newOrphan(uint size) const { - return Orphan(NewOrphanListImpl::apply(arena, capTable, size)); -} - -template -struct Orphanage::GetInnerReader { - static inline _::StructReader apply(const typename T::Reader& t) { - return t._reader; - } -}; - -template -struct Orphanage::GetInnerReader { - static inline _::ListReader apply(const typename T::Reader& t) { - return t.reader; - } -}; - -template -struct Orphanage::GetInnerReader { - static inline const typename T::Reader& apply(const typename T::Reader& t) { - return t; - } -}; - -template -inline Orphan> Orphanage::newOrphanCopy(Reader copyFrom) const { - return Orphan>(_::OrphanBuilder::copy( - arena, capTable, GetInnerReader>::apply(copyFrom))); -} - -template -inline Orphan>>> -Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { - return newOrphanConcat(kj::implicitCast>(lists)); -} -template -inline Orphan>>> -Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { - // Optimization / simplification: Rely on List::Reader containing nothing except a - // _::ListReader. - static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?"); - kj::ArrayPtr raw( - reinterpret_cast(lists.begin()), lists.size()); - typedef ListElementType> Element; - return Orphan>( - _::OrphanBuilder::concat(arena, capTable, - _::elementSizeForType(), - _::minStructSizeForElement(), raw)); -} - -inline Orphan Orphanage::referenceExternalData(Data::Reader data) const { - return Orphan(_::OrphanBuilder::referenceExternalData(arena, data)); -} - -} // namespace capnp - -#endif // CAPNP_ORPHAN_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ORPHAN_H_ +#define CAPNP_ORPHAN_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" + +namespace capnp { + +class StructSchema; +class ListSchema; +struct DynamicStruct; +struct DynamicList; +namespace _ { struct OrphanageInternal; } + +template +class Orphan { + // Represents an object which is allocated within some message builder but has no pointers + // pointing at it. An Orphan can later be "adopted" by some other object as one of that object's + // fields, without having to copy the orphan. For a field `foo` of pointer type, the generated + // code will define builder methods `void adoptFoo(Orphan)` and `Orphan disownFoo()`. + // Orphans can also be created independently of any parent using an Orphanage. + // + // `Orphan` can be moved but not copied, like `Own`, so that it is impossible for one + // orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its + // contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space + // in a message arena). + +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {} + + inline BuilderFor get(); + // Get the underlying builder. If the orphan is null, this will allocate and return a default + // object rather than crash. This is done for security -- otherwise, you might enable a DoS + // attack any time you disown a field and fail to check if it is null. In the case of structs, + // this means that the orphan is no longer null after get() returns. In the case of lists, + // no actual object is allocated since a simple empty ListBuilder can be returned. + + inline ReaderFor getReader() const; + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + + inline void truncate(uint size); + // Resize an object (which must be a list or a blob) to the given size. + // + // If the new size is less than the original, the remaining elements will be discarded. The + // list is never moved in this case. If the list happens to be located at the end of its segment + // (which is always true if the list was the last thing allocated), the removed memory will be + // reclaimed (reducing the messag size), otherwise it is simply zeroed. The reclaiming behavior + // is particularly useful for allocating buffer space when you aren't sure how much space you + // actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and + // then truncate it back to the amount of space actually used. + // + // If the new size is greater than the original, the list is extended with default values. If + // the list is the last object in its segment *and* there is enough space left in the segment to + // extend it to cover the new values, then the list is extended in-place. Otherwise, it must be + // moved to a new location, leaving a zero'd hole in the previous space that won't be filled. + // This copy is shallow; sub-objects will simply be reparented, not copied. + // + // Any existing readers or builders pointing at the object are invalidated by this call (even if + // it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer. + +private: + _::OrphanBuilder builder; + + template + friend struct _::PointerHelpers; + template + friend struct List; + template + friend class Orphan; + friend class Orphanage; + friend class MessageBuilder; +}; + +class Orphanage: private kj::DisallowConstCopy { + // Use to directly allocate Orphan objects, without having a parent object allocate and then + // disown the object. + +public: + inline Orphanage(): arena(nullptr) {} + + template + static Orphanage getForMessageContaining(BuilderType builder); + // Construct an Orphanage that allocates within the message containing the given Builder. This + // allows the constructed Orphans to be adopted by objects within said message. + // + // This constructor takes the builder rather than having the builder have a getOrphanage() method + // because this is an advanced feature and we don't want to pollute the builder APIs with it. + // + // Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its + // `getOrphanage()` method. + + template + Orphan newOrphan() const; + // Allocate a new orphaned struct. + + template + Orphan newOrphan(uint size) const; + // Allocate a new orphaned list or blob. + + Orphan newOrphan(StructSchema schema) const; + // Dynamically create an orphan struct with the given schema. You must + // #include to use this. + + Orphan newOrphan(ListSchema schema, uint size) const; + // Dynamically create an orphan list with the given schema. You must #include + // to use this. + + template + Orphan> newOrphanCopy(Reader copyFrom) const; + // Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the + // given object. + + template + Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; + template + Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; + // Given an array of List readers, copy and concatenate the lists, creating a new Orphan. + // + // Note that compared to allocating the list yourself and using `setWithCaveats()` to set each + // item, this method avoids the "caveats": the new list will be allocated with the element size + // being the maximum of that from all the input lists. This is particularly important when + // concatenating struct lists: if the lists were created using a newer version of the protocol + // in which some new fields had been added to the struct, using `setWithCaveats()` would + // truncate off those new fields. + + Orphan referenceExternalData(Data::Reader data) const; + // Creates an Orphan that points at an existing region of memory (e.g. from another message) + // without copying it. There are some SEVERE restrictions on how this can be used: + // - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is + // abandoned). + // - Because the data is const, you will not be allowed to obtain a `Data::Builder` + // for this blob. Any call which would return such a builder will throw an exception. You + // can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once + // the orphan is adopted). It is your responsibility to make sure your code can deal with + // these problems when using this optimization; if you can't, allocate a copy instead. + // - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on + // the CPU). Any pointer returned by malloc() as well as any data blob obtained from another + // Cap'n Proto message satisfies this. + // - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte + // boundary will be visible in the raw message when it is written out. Thus, there must be no + // secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe + // as these bytes should be zero (unless the sender had the same problem). + // + // The array will actually become one of the message's segments. The data can thus be adopted + // into the message tree without copying it. This is particularly useful when referencing very + // large blobs, such as whole mmap'd files. + +private: + _::BuilderArena* arena; + _::CapTableBuilder* capTable; + + inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable) + : arena(arena), capTable(capTable) {} + + template + struct GetInnerBuilder; + template + struct GetInnerReader; + template + struct NewOrphanListImpl; + + friend class MessageBuilder; + friend struct _::OrphanageInternal; +}; + +// ======================================================================================= +// Inline implementation details. + +namespace _ { // private + +template +struct OrphanGetImpl; + +template +struct OrphanGetImpl { + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::elementSizeForType()); + } +}; + +template +struct OrphanGetImpl { + static inline typename T::Builder apply(_::OrphanBuilder& builder) { + return typename T::Builder(builder.asStruct(_::structSize())); + } + static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) { + return typename T::Reader(builder.asStructReader(_::structSize())); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::structSize()); + } +}; + +#if !CAPNP_LITE +template +struct OrphanGetImpl { + static inline typename T::Client apply(_::OrphanBuilder& builder) { + return typename T::Client(builder.asCapability()); + } + static inline typename T::Client applyReader(const _::OrphanBuilder& builder) { + return typename T::Client(builder.asCapability()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; +#endif // !CAPNP_LITE + +template +struct OrphanGetImpl, Kind::LIST> { + static inline typename List::Builder apply(_::OrphanBuilder& builder) { + return typename List::Builder(builder.asList(_::ElementSizeForType::value)); + } + static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { + return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template +struct OrphanGetImpl, Kind::LIST> { + static inline typename List::Builder apply(_::OrphanBuilder& builder) { + return typename List::Builder(builder.asStructList(_::structSize())); + } + static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { + return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template <> +struct OrphanGetImpl { + static inline Text::Builder apply(_::OrphanBuilder& builder) { + return Text::Builder(builder.asText()); + } + static inline Text::Reader applyReader(const _::OrphanBuilder& builder) { + return Text::Reader(builder.asTextReader()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template <> +struct OrphanGetImpl { + static inline Data::Builder apply(_::OrphanBuilder& builder) { + return Data::Builder(builder.asData()); + } + static inline Data::Reader applyReader(const _::OrphanBuilder& builder) { + return Data::Reader(builder.asDataReader()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +struct OrphanageInternal { + static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; } + static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; } +}; + +} // namespace _ (private) + +template +inline BuilderFor Orphan::get() { + return _::OrphanGetImpl::apply(builder); +} + +template +inline ReaderFor Orphan::getReader() const { + return _::OrphanGetImpl::applyReader(builder); +} + +template +inline void Orphan::truncate(uint size) { + _::OrphanGetImpl>::truncateListOf(builder, bounded(size) * ELEMENTS); +} + +template <> +inline void Orphan::truncate(uint size) { + builder.truncateText(bounded(size) * ELEMENTS); +} + +template <> +inline void Orphan::truncate(uint size) { + builder.truncate(bounded(size) * ELEMENTS, ElementSize::BYTE); +} + +template +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(typename T::Builder& t) { + return t._builder; + } +}; + +template +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(typename T::Builder& t) { + return t.builder; + } +}; + +template +Orphanage Orphanage::getForMessageContaining(BuilderType builder) { + auto inner = GetInnerBuilder>::apply(builder); + return Orphanage(inner.getArena(), inner.getCapTable()); +} + +template +Orphan Orphanage::newOrphan() const { + return Orphan(_::OrphanBuilder::initStruct(arena, capTable, _::structSize())); +} + +template +struct Orphanage::NewOrphanListImpl> { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initList( + arena, capTable, bounded(size) * ELEMENTS, _::ElementSizeForType::value); + } +}; + +template +struct Orphanage::NewOrphanListImpl> { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initStructList( + arena, capTable, bounded(size) * ELEMENTS, _::structSize()); + } +}; + +template <> +struct Orphanage::NewOrphanListImpl { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initText(arena, capTable, bounded(size) * BYTES); + } +}; + +template <> +struct Orphanage::NewOrphanListImpl { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initData(arena, capTable, bounded(size) * BYTES); + } +}; + +template +Orphan Orphanage::newOrphan(uint size) const { + return Orphan(NewOrphanListImpl::apply(arena, capTable, size)); +} + +template +struct Orphanage::GetInnerReader { + static inline _::StructReader apply(const typename T::Reader& t) { + return t._reader; + } +}; + +template +struct Orphanage::GetInnerReader { + static inline _::ListReader apply(const typename T::Reader& t) { + return t.reader; + } +}; + +template +struct Orphanage::GetInnerReader { + static inline const typename T::Reader& apply(const typename T::Reader& t) { + return t; + } +}; + +template +inline Orphan> Orphanage::newOrphanCopy(Reader copyFrom) const { + return Orphan>(_::OrphanBuilder::copy( + arena, capTable, GetInnerReader>::apply(copyFrom))); +} + +template +inline Orphan>>> +Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { + return newOrphanConcat(kj::implicitCast>(lists)); +} +template +inline Orphan>>> +Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { + // Optimization / simplification: Rely on List::Reader containing nothing except a + // _::ListReader. + static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?"); + kj::ArrayPtr raw( + reinterpret_cast(lists.begin()), lists.size()); + typedef ListElementType> Element; + return Orphan>( + _::OrphanBuilder::concat(arena, capTable, + _::elementSizeForType(), + _::minStructSizeForElement(), raw)); +} + +inline Orphan Orphanage::referenceExternalData(Data::Reader data) const { + return Orphan(_::OrphanBuilder::referenceExternalData(arena, data)); +} + +} // namespace capnp + +#endif // CAPNP_ORPHAN_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/persistent.capnp --- a/osx/include/capnp/persistent.capnp Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/persistent.capnp Mon May 22 10:01:37 2017 +0100 @@ -1,139 +1,139 @@ -# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xb8630836983feed7; - -$import "/capnp/c++.capnp".namespace("capnp"); - -interface Persistent@0xc8cb212fcd9f5691(SturdyRef, Owner) { - # Interface implemented by capabilities that outlive a single connection. A client may save() - # the capability, producing a SturdyRef. The SturdyRef can be stored to disk, then later used to - # obtain a new reference to the capability on a future connection. - # - # The exact format of SturdyRef depends on the "realm" in which the SturdyRef appears. A "realm" - # is an abstract space in which all SturdyRefs have the same format and refer to the same set of - # resources. Every vat is in exactly one realm. All capability clients within that vat must - # produce SturdyRefs of the format appropriate for the realm. - # - # Similarly, every VatNetwork also resides in a particular realm. Usually, a vat's "realm" - # corresponds to the realm of its main VatNetwork. However, a Vat can in fact communicate over - # a VatNetwork in a different realm -- in this case, all SturdyRefs need to be transformed when - # coming or going through said VatNetwork. The RPC system has hooks for registering - # transformation callbacks for this purpose. - # - # Since the format of SturdyRef is realm-dependent, it is not defined here. An application should - # choose an appropriate realm for itself as part of its design. Note that under Sandstorm, every - # application exists in its own realm and is therefore free to define its own SturdyRef format; - # the Sandstorm platform handles translating between realms. - # - # Note that whether a capability is persistent is often orthogonal to its type. In these cases, - # the capability's interface should NOT inherit `Persistent`; instead, just perform a cast at - # runtime. It's not type-safe, but trying to be type-safe in these cases will likely lead to - # tears. In cases where a particular interface only makes sense on persistent capabilities, it - # still should not explicitly inherit Persistent because the `SturdyRef` and `Owner` types will - # vary between realms (they may even be different at the call site than they are on the - # implementation). Instead, mark persistent interfaces with the $persistent annotation (defined - # below). - # - # Sealing - # ------- - # - # As an added security measure, SturdyRefs may be "sealed" to a particular owner, such that - # if the SturdyRef itself leaks to a third party, that party cannot actually restore it because - # they are not the owner. To restore a sealed capability, you must first prove to its host that - # you are the rightful owner. The precise mechanism for this authentication is defined by the - # realm. - # - # Sealing is a defense-in-depth mechanism meant to mitigate damage in the case of catastrophic - # attacks. For example, say an attacker temporarily gains read access to a database full of - # SturdyRefs: it would be unfortunate if it were then necessary to revoke every single reference - # in the database to prevent the attacker from using them. - # - # In general, an "owner" is a course-grained identity. Because capability-based security is still - # the primary mechanism of security, it is not necessary nor desirable to have a separate "owner" - # identity for every single process or object; that is exactly what capabilities are supposed to - # avoid! Instead, it makes sense for an "owner" to literally identify the owner of the machines - # where the capability is stored. If untrusted third parties are able to run arbitrary code on - # said machines, then the sandbox for that code should be designed using Distributed Confinement - # such that the third-party code never sees the bits of the SturdyRefs and cannot directly - # exercise the owner's power to restore refs. See: - # - # http://www.erights.org/elib/capability/dist-confine.html - # - # Resist the urge to represent an Owner as a simple public key. The whole point of sealing is to - # defend against leaked-storage attacks. Such attacks can easily result in the owner's private - # key being stolen as well. A better solution is for `Owner` to contain a simple globally unique - # identifier for the owner, and for everyone to separately maintain a mapping of owner IDs to - # public keys. If an owner's private key is compromised, then humans will need to communicate - # and agree on a replacement public key, then update the mapping. - # - # As a concrete example, an `Owner` could simply contain a domain name, and restoring a SturdyRef - # would require signing a request using the domain's private key. Authenticating this key could - # be accomplished through certificate authorities or web-of-trust techniques. - - save @0 SaveParams -> SaveResults; - # Save a capability persistently so that it can be restored by a future connection. Not all - # capabilities can be saved -- application interfaces should define which capabilities support - # this and which do not. - - struct SaveParams { - sealFor @0 :Owner; - # Seal the SturdyRef so that it can only be restored by the specified Owner. This is meant - # to mitigate damage when a SturdyRef is leaked. See comments above. - # - # Leaving this value null may or may not be allowed; it is up to the realm to decide. If a - # realm does allow a null owner, this should indicate that anyone is allowed to restore the - # ref. - } - struct SaveResults { - sturdyRef @0 :SturdyRef; - } -} - -interface RealmGateway(InternalRef, ExternalRef, InternalOwner, ExternalOwner) { - # Interface invoked when a SturdyRef is about to cross realms. The RPC system supports providing - # a RealmGateway as a callback hook when setting up RPC over some VatNetwork. - - import @0 (cap :Persistent(ExternalRef, ExternalOwner), - params :Persistent(InternalRef, InternalOwner).SaveParams) - -> Persistent(InternalRef, InternalOwner).SaveResults; - # Given an external capability, save it and return an internal reference. Used when someone - # inside the realm tries to save a capability from outside the realm. - - export @1 (cap :Persistent(InternalRef, InternalOwner), - params :Persistent(ExternalRef, ExternalOwner).SaveParams) - -> Persistent(ExternalRef, ExternalOwner).SaveResults; - # Given an internal capability, save it and return an external reference. Used when someone - # outside the realm tries to save a capability from inside the realm. -} - -annotation persistent(interface, field) :Void; -# Apply this annotation to interfaces for objects that will always be persistent, instead of -# extending the Persistent capability, since the correct type parameters to Persistent depend on -# the realm, which is orthogonal to the interface type and therefore should not be defined -# along-side it. -# -# You may also apply this annotation to a capability-typed field which will always contain a -# persistent capability, but where the capability's interface itself is not already marked -# persistent. -# -# Note that absence of the $persistent annotation doesn't mean a capability of that type isn't -# persistent; it just means not *all* such capabilities are persistent. +# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xb8630836983feed7; + +$import "/capnp/c++.capnp".namespace("capnp"); + +interface Persistent@0xc8cb212fcd9f5691(SturdyRef, Owner) { + # Interface implemented by capabilities that outlive a single connection. A client may save() + # the capability, producing a SturdyRef. The SturdyRef can be stored to disk, then later used to + # obtain a new reference to the capability on a future connection. + # + # The exact format of SturdyRef depends on the "realm" in which the SturdyRef appears. A "realm" + # is an abstract space in which all SturdyRefs have the same format and refer to the same set of + # resources. Every vat is in exactly one realm. All capability clients within that vat must + # produce SturdyRefs of the format appropriate for the realm. + # + # Similarly, every VatNetwork also resides in a particular realm. Usually, a vat's "realm" + # corresponds to the realm of its main VatNetwork. However, a Vat can in fact communicate over + # a VatNetwork in a different realm -- in this case, all SturdyRefs need to be transformed when + # coming or going through said VatNetwork. The RPC system has hooks for registering + # transformation callbacks for this purpose. + # + # Since the format of SturdyRef is realm-dependent, it is not defined here. An application should + # choose an appropriate realm for itself as part of its design. Note that under Sandstorm, every + # application exists in its own realm and is therefore free to define its own SturdyRef format; + # the Sandstorm platform handles translating between realms. + # + # Note that whether a capability is persistent is often orthogonal to its type. In these cases, + # the capability's interface should NOT inherit `Persistent`; instead, just perform a cast at + # runtime. It's not type-safe, but trying to be type-safe in these cases will likely lead to + # tears. In cases where a particular interface only makes sense on persistent capabilities, it + # still should not explicitly inherit Persistent because the `SturdyRef` and `Owner` types will + # vary between realms (they may even be different at the call site than they are on the + # implementation). Instead, mark persistent interfaces with the $persistent annotation (defined + # below). + # + # Sealing + # ------- + # + # As an added security measure, SturdyRefs may be "sealed" to a particular owner, such that + # if the SturdyRef itself leaks to a third party, that party cannot actually restore it because + # they are not the owner. To restore a sealed capability, you must first prove to its host that + # you are the rightful owner. The precise mechanism for this authentication is defined by the + # realm. + # + # Sealing is a defense-in-depth mechanism meant to mitigate damage in the case of catastrophic + # attacks. For example, say an attacker temporarily gains read access to a database full of + # SturdyRefs: it would be unfortunate if it were then necessary to revoke every single reference + # in the database to prevent the attacker from using them. + # + # In general, an "owner" is a course-grained identity. Because capability-based security is still + # the primary mechanism of security, it is not necessary nor desirable to have a separate "owner" + # identity for every single process or object; that is exactly what capabilities are supposed to + # avoid! Instead, it makes sense for an "owner" to literally identify the owner of the machines + # where the capability is stored. If untrusted third parties are able to run arbitrary code on + # said machines, then the sandbox for that code should be designed using Distributed Confinement + # such that the third-party code never sees the bits of the SturdyRefs and cannot directly + # exercise the owner's power to restore refs. See: + # + # http://www.erights.org/elib/capability/dist-confine.html + # + # Resist the urge to represent an Owner as a simple public key. The whole point of sealing is to + # defend against leaked-storage attacks. Such attacks can easily result in the owner's private + # key being stolen as well. A better solution is for `Owner` to contain a simple globally unique + # identifier for the owner, and for everyone to separately maintain a mapping of owner IDs to + # public keys. If an owner's private key is compromised, then humans will need to communicate + # and agree on a replacement public key, then update the mapping. + # + # As a concrete example, an `Owner` could simply contain a domain name, and restoring a SturdyRef + # would require signing a request using the domain's private key. Authenticating this key could + # be accomplished through certificate authorities or web-of-trust techniques. + + save @0 SaveParams -> SaveResults; + # Save a capability persistently so that it can be restored by a future connection. Not all + # capabilities can be saved -- application interfaces should define which capabilities support + # this and which do not. + + struct SaveParams { + sealFor @0 :Owner; + # Seal the SturdyRef so that it can only be restored by the specified Owner. This is meant + # to mitigate damage when a SturdyRef is leaked. See comments above. + # + # Leaving this value null may or may not be allowed; it is up to the realm to decide. If a + # realm does allow a null owner, this should indicate that anyone is allowed to restore the + # ref. + } + struct SaveResults { + sturdyRef @0 :SturdyRef; + } +} + +interface RealmGateway(InternalRef, ExternalRef, InternalOwner, ExternalOwner) { + # Interface invoked when a SturdyRef is about to cross realms. The RPC system supports providing + # a RealmGateway as a callback hook when setting up RPC over some VatNetwork. + + import @0 (cap :Persistent(ExternalRef, ExternalOwner), + params :Persistent(InternalRef, InternalOwner).SaveParams) + -> Persistent(InternalRef, InternalOwner).SaveResults; + # Given an external capability, save it and return an internal reference. Used when someone + # inside the realm tries to save a capability from outside the realm. + + export @1 (cap :Persistent(InternalRef, InternalOwner), + params :Persistent(ExternalRef, ExternalOwner).SaveParams) + -> Persistent(ExternalRef, ExternalOwner).SaveResults; + # Given an internal capability, save it and return an external reference. Used when someone + # outside the realm tries to save a capability from inside the realm. +} + +annotation persistent(interface, field) :Void; +# Apply this annotation to interfaces for objects that will always be persistent, instead of +# extending the Persistent capability, since the correct type parameters to Persistent depend on +# the realm, which is orthogonal to the interface type and therefore should not be defined +# along-side it. +# +# You may also apply this annotation to a capability-typed field which will always contain a +# persistent capability, but where the capability's interface itself is not already marked +# persistent. +# +# Note that absence of the $persistent annotation doesn't mean a capability of that type isn't +# persistent; it just means not *all* such capabilities are persistent. diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/persistent.capnp.h --- a/osx/include/capnp/persistent.capnp.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/persistent.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -1,1328 +1,1328 @@ -// Generated by Cap'n Proto compiler, DO NOT EDIT -// source: persistent.capnp - -#ifndef CAPNP_INCLUDED_b8630836983feed7_ -#define CAPNP_INCLUDED_b8630836983feed7_ - -#include -#if !CAPNP_LITE -#include -#endif // !CAPNP_LITE - -#if CAPNP_VERSION != 6000 -#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." -#endif - - -namespace capnp { -namespace schemas { - -CAPNP_DECLARE_SCHEMA(c8cb212fcd9f5691); -CAPNP_DECLARE_SCHEMA(f76fba59183073a5); -CAPNP_DECLARE_SCHEMA(b76848c18c40efbf); -CAPNP_DECLARE_SCHEMA(84ff286cd00a3ed4); -CAPNP_DECLARE_SCHEMA(f0c2cc1d3909574d); -CAPNP_DECLARE_SCHEMA(ecafa18b482da3aa); -CAPNP_DECLARE_SCHEMA(f622595091cafb67); - -} // namespace schemas -} // namespace capnp - -namespace capnp { - -template -struct Persistent { - Persistent() = delete; - -#if !CAPNP_LITE - class Client; - class Server; -#endif // !CAPNP_LITE - - struct SaveParams; - struct SaveResults; - - #if !CAPNP_LITE - struct _capnpPrivate { - CAPNP_DECLARE_INTERFACE_HEADER(c8cb212fcd9f5691) - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand; - }; - #endif // !CAPNP_LITE -}; - -template -struct Persistent::SaveParams { - SaveParams() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(f76fba59183073a5, 0, 1) - #if !CAPNP_LITE - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand; - #endif // !CAPNP_LITE - }; -}; - -template -struct Persistent::SaveResults { - SaveResults() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b76848c18c40efbf, 0, 1) - #if !CAPNP_LITE - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand; - #endif // !CAPNP_LITE - }; -}; - -template -struct RealmGateway { - RealmGateway() = delete; - -#if !CAPNP_LITE - class Client; - class Server; -#endif // !CAPNP_LITE - - struct ImportParams; - struct ExportParams; - - #if !CAPNP_LITE - struct _capnpPrivate { - CAPNP_DECLARE_INTERFACE_HEADER(84ff286cd00a3ed4) - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand; - }; - #endif // !CAPNP_LITE -}; - -template -struct RealmGateway::ImportParams { - ImportParams() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(f0c2cc1d3909574d, 0, 2) - #if !CAPNP_LITE - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand; - #endif // !CAPNP_LITE - }; -}; - -template -struct RealmGateway::ExportParams { - ExportParams() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ecafa18b482da3aa, 0, 2) - #if !CAPNP_LITE - static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; - static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; - static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; - static const ::capnp::_::RawBrandedSchema specificBrand; - static constexpr ::capnp::_::RawBrandedSchema const* brand = ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand; - #endif // !CAPNP_LITE - }; -}; - -// ======================================================================================= - -#if !CAPNP_LITE -template -class Persistent::Client - : public virtual ::capnp::Capability::Client { -public: - typedef Persistent Calls; - typedef Persistent Reads; - - Client(decltype(nullptr)); - explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); - template ()>> - Client(::kj::Own<_t>&& server); - template ()>> - Client(::kj::Promise<_t>&& promise); - Client(::kj::Exception&& exception); - Client(Client&) = default; - Client(Client&&) = default; - Client& operator=(Client& other); - Client& operator=(Client&& other); - - template - typename Persistent::Client asGeneric() { - return castAs>(); - } - - ::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults> saveRequest( - ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); - -protected: - Client() = default; -}; - -template -class Persistent::Server - : public virtual ::capnp::Capability::Server { -public: - typedef Persistent Serves; - - ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) - override; - -protected: - typedef ::capnp::CallContext::SaveParams, typename ::capnp::Persistent::SaveResults> SaveContext; - virtual ::kj::Promise save(SaveContext context); - - inline typename ::capnp::Persistent::Client thisCap() { - return ::capnp::Capability::Server::thisCap() - .template castAs< ::capnp::Persistent>(); - } - - ::kj::Promise dispatchCallInternal(uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); -}; -#endif // !CAPNP_LITE - -template -class Persistent::SaveParams::Reader { -public: - typedef SaveParams Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - template - typename Persistent::SaveParams::Reader asPersistentGeneric() { - return typename Persistent::SaveParams::Reader(_reader); - } - - inline bool hasSealFor() const; - inline ::capnp::ReaderFor getSealFor() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -template -class Persistent::SaveParams::Builder { -public: - typedef SaveParams Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - template - typename Persistent::SaveParams::Builder asPersistentGeneric() { - return typename Persistent::SaveParams::Builder(_builder); - } - - inline bool hasSealFor(); - inline ::capnp::BuilderFor getSealFor(); - inline void setSealFor( ::capnp::ReaderFor value); - inline ::capnp::BuilderFor initSealFor(); - inline ::capnp::BuilderFor initSealFor(unsigned int size); - inline void adoptSealFor(::capnp::Orphan&& value); - inline ::capnp::Orphan disownSealFor(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -template -class Persistent::SaveParams::Pipeline { -public: - typedef SaveParams Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::PipelineFor getSealFor(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -template -class Persistent::SaveResults::Reader { -public: - typedef SaveResults Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - template - typename Persistent::SaveResults::Reader asPersistentGeneric() { - return typename Persistent::SaveResults::Reader(_reader); - } - - inline bool hasSturdyRef() const; - inline ::capnp::ReaderFor getSturdyRef() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -template -class Persistent::SaveResults::Builder { -public: - typedef SaveResults Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - template - typename Persistent::SaveResults::Builder asPersistentGeneric() { - return typename Persistent::SaveResults::Builder(_builder); - } - - inline bool hasSturdyRef(); - inline ::capnp::BuilderFor getSturdyRef(); - inline void setSturdyRef( ::capnp::ReaderFor value); - inline ::capnp::BuilderFor initSturdyRef(); - inline ::capnp::BuilderFor initSturdyRef(unsigned int size); - inline void adoptSturdyRef(::capnp::Orphan&& value); - inline ::capnp::Orphan disownSturdyRef(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -template -class Persistent::SaveResults::Pipeline { -public: - typedef SaveResults Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::PipelineFor getSturdyRef(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -#if !CAPNP_LITE -template -class RealmGateway::Client - : public virtual ::capnp::Capability::Client { -public: - typedef RealmGateway Calls; - typedef RealmGateway Reads; - - Client(decltype(nullptr)); - explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); - template ()>> - Client(::kj::Own<_t>&& server); - template ()>> - Client(::kj::Promise<_t>&& promise); - Client(::kj::Exception&& exception); - Client(Client&) = default; - Client(Client&&) = default; - Client& operator=(Client& other); - Client& operator=(Client&& other); - - template - typename RealmGateway::Client asGeneric() { - return castAs>(); - } - - ::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults> importRequest( - ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); - ::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults> exportRequest( - ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); - -protected: - Client() = default; -}; - -template -class RealmGateway::Server - : public virtual ::capnp::Capability::Server { -public: - typedef RealmGateway Serves; - - ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) - override; - -protected: - typedef typename ::capnp::RealmGateway::ImportParams ImportParams; - typedef ::capnp::CallContext::SaveResults> ImportContext; - virtual ::kj::Promise import(ImportContext context); - typedef typename ::capnp::RealmGateway::ExportParams ExportParams; - typedef ::capnp::CallContext::SaveResults> ExportContext; - virtual ::kj::Promise export_(ExportContext context); - - inline typename ::capnp::RealmGateway::Client thisCap() { - return ::capnp::Capability::Server::thisCap() - .template castAs< ::capnp::RealmGateway>(); - } - - ::kj::Promise dispatchCallInternal(uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); -}; -#endif // !CAPNP_LITE - -template -class RealmGateway::ImportParams::Reader { -public: - typedef ImportParams Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - template - typename RealmGateway::ImportParams::Reader asRealmGatewayGeneric() { - return typename RealmGateway::ImportParams::Reader(_reader); - } - - inline bool hasCap() const; -#if !CAPNP_LITE - inline typename ::capnp::Persistent::Client getCap() const; -#endif // !CAPNP_LITE - - inline bool hasParams() const; - inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -template -class RealmGateway::ImportParams::Builder { -public: - typedef ImportParams Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - template - typename RealmGateway::ImportParams::Builder asRealmGatewayGeneric() { - return typename RealmGateway::ImportParams::Builder(_builder); - } - - inline bool hasCap(); -#if !CAPNP_LITE - inline typename ::capnp::Persistent::Client getCap(); - inline void setCap(typename ::capnp::Persistent::Client&& value); - inline void setCap(typename ::capnp::Persistent::Client& value); - inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); - inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); -#endif // !CAPNP_LITE - - inline bool hasParams(); - inline typename ::capnp::Persistent::SaveParams::Builder getParams(); - inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); - inline typename ::capnp::Persistent::SaveParams::Builder initParams(); - inline void adoptParams(::capnp::Orphan::SaveParams>&& value); - inline ::capnp::Orphan::SaveParams> disownParams(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -template -class RealmGateway::ImportParams::Pipeline { -public: - typedef ImportParams Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline typename ::capnp::Persistent::Client getCap(); - inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -template -class RealmGateway::ExportParams::Reader { -public: - typedef ExportParams Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - template - typename RealmGateway::ExportParams::Reader asRealmGatewayGeneric() { - return typename RealmGateway::ExportParams::Reader(_reader); - } - - inline bool hasCap() const; -#if !CAPNP_LITE - inline typename ::capnp::Persistent::Client getCap() const; -#endif // !CAPNP_LITE - - inline bool hasParams() const; - inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -template -class RealmGateway::ExportParams::Builder { -public: - typedef ExportParams Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - template - typename RealmGateway::ExportParams::Builder asRealmGatewayGeneric() { - return typename RealmGateway::ExportParams::Builder(_builder); - } - - inline bool hasCap(); -#if !CAPNP_LITE - inline typename ::capnp::Persistent::Client getCap(); - inline void setCap(typename ::capnp::Persistent::Client&& value); - inline void setCap(typename ::capnp::Persistent::Client& value); - inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); - inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); -#endif // !CAPNP_LITE - - inline bool hasParams(); - inline typename ::capnp::Persistent::SaveParams::Builder getParams(); - inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); - inline typename ::capnp::Persistent::SaveParams::Builder initParams(); - inline void adoptParams(::capnp::Orphan::SaveParams>&& value); - inline ::capnp::Orphan::SaveParams> disownParams(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -template -class RealmGateway::ExportParams::Pipeline { -public: - typedef ExportParams Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline typename ::capnp::Persistent::Client getCap(); - inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -// ======================================================================================= - -#if !CAPNP_LITE -template -inline Persistent::Client::Client(decltype(nullptr)) - : ::capnp::Capability::Client(nullptr) {} -template -inline Persistent::Client::Client( - ::kj::Own< ::capnp::ClientHook>&& hook) - : ::capnp::Capability::Client(::kj::mv(hook)) {} -template -template -inline Persistent::Client::Client(::kj::Own<_t>&& server) - : ::capnp::Capability::Client(::kj::mv(server)) {} -template -template -inline Persistent::Client::Client(::kj::Promise<_t>&& promise) - : ::capnp::Capability::Client(::kj::mv(promise)) {} -template -inline Persistent::Client::Client(::kj::Exception&& exception) - : ::capnp::Capability::Client(::kj::mv(exception)) {} -template -inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client& other) { - ::capnp::Capability::Client::operator=(other); - return *this; -} -template -inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client&& other) { - ::capnp::Capability::Client::operator=(kj::mv(other)); - return *this; -} - -#endif // !CAPNP_LITE -template -inline bool Persistent::SaveParams::Reader::hasSealFor() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline bool Persistent::SaveParams::Builder::hasSealFor() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline ::capnp::ReaderFor Persistent::SaveParams::Reader::getSealFor() const { - return ::capnp::_::PointerHelpers::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline ::capnp::BuilderFor Persistent::SaveParams::Builder::getSealFor() { - return ::capnp::_::PointerHelpers::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -template -inline ::capnp::PipelineFor Persistent::SaveParams::Pipeline::getSealFor() { - return ::capnp::PipelineFor(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -template -inline void Persistent::SaveParams::Builder::setSealFor( ::capnp::ReaderFor value) { - ::capnp::_::PointerHelpers::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -template -inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor() { - return ::capnp::_::PointerHelpers::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor(unsigned int size) { - return ::capnp::_::PointerHelpers::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -template -inline void Persistent::SaveParams::Builder::adoptSealFor( - ::capnp::Orphan&& value) { - ::capnp::_::PointerHelpers::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan Persistent::SaveParams::Builder::disownSealFor() { - return ::capnp::_::PointerHelpers::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -// Persistent::SaveParams -template -constexpr uint16_t Persistent::SaveParams::_capnpPrivate::dataWordSize; -template -constexpr uint16_t Persistent::SaveParams::_capnpPrivate::pointerCount; -#if !CAPNP_LITE -template -constexpr ::capnp::Kind Persistent::SaveParams::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* Persistent::SaveParams::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* Persistent::SaveParams::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveParams::_capnpPrivate::brandScopes[] = { - { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveParams::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema Persistent::SaveParams::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_f76fba59183073a5, brandScopes, nullptr, - sizeof(brandScopes) / sizeof(brandScopes[0]), 0, nullptr -}; -#endif // !CAPNP_LITE - -template -inline bool Persistent::SaveResults::Reader::hasSturdyRef() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline bool Persistent::SaveResults::Builder::hasSturdyRef() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline ::capnp::ReaderFor Persistent::SaveResults::Reader::getSturdyRef() const { - return ::capnp::_::PointerHelpers::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline ::capnp::BuilderFor Persistent::SaveResults::Builder::getSturdyRef() { - return ::capnp::_::PointerHelpers::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -template -inline ::capnp::PipelineFor Persistent::SaveResults::Pipeline::getSturdyRef() { - return ::capnp::PipelineFor(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -template -inline void Persistent::SaveResults::Builder::setSturdyRef( ::capnp::ReaderFor value) { - ::capnp::_::PointerHelpers::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -template -inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef() { - return ::capnp::_::PointerHelpers::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef(unsigned int size) { - return ::capnp::_::PointerHelpers::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -template -inline void Persistent::SaveResults::Builder::adoptSturdyRef( - ::capnp::Orphan&& value) { - ::capnp::_::PointerHelpers::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan Persistent::SaveResults::Builder::disownSturdyRef() { - return ::capnp::_::PointerHelpers::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -// Persistent::SaveResults -template -constexpr uint16_t Persistent::SaveResults::_capnpPrivate::dataWordSize; -template -constexpr uint16_t Persistent::SaveResults::_capnpPrivate::pointerCount; -#if !CAPNP_LITE -template -constexpr ::capnp::Kind Persistent::SaveResults::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* Persistent::SaveResults::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* Persistent::SaveResults::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveResults::_capnpPrivate::brandScopes[] = { - { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveResults::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema Persistent::SaveResults::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_b76848c18c40efbf, brandScopes, nullptr, - sizeof(brandScopes) / sizeof(brandScopes[0]), 0, nullptr -}; -#endif // !CAPNP_LITE - -#if !CAPNP_LITE -template -::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults> -Persistent::Client::saveRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { - return newCall::SaveParams, typename ::capnp::Persistent::SaveResults>( - 0xc8cb212fcd9f5691ull, 0, sizeHint); -} -template -::kj::Promise Persistent::Server::save(SaveContext) { - return ::capnp::Capability::Server::internalUnimplemented( - "capnp/persistent.capnp:Persistent", "save", - 0xc8cb212fcd9f5691ull, 0); -} -template -::kj::Promise Persistent::Server::dispatchCall( - uint64_t interfaceId, uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { - switch (interfaceId) { - case 0xc8cb212fcd9f5691ull: - return dispatchCallInternal(methodId, context); - default: - return internalUnimplemented("capnp/persistent.capnp:Persistent", interfaceId); - } -} -template -::kj::Promise Persistent::Server::dispatchCallInternal( - uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { - switch (methodId) { - case 0: - return save(::capnp::Capability::Server::internalGetTypedContext< - typename ::capnp::Persistent::SaveParams, typename ::capnp::Persistent::SaveResults>(context)); - default: - (void)context; - return ::capnp::Capability::Server::internalUnimplemented( - "capnp/persistent.capnp:Persistent", - 0xc8cb212fcd9f5691ull, methodId); - } -} -#endif // !CAPNP_LITE - -// Persistent -#if !CAPNP_LITE -template -constexpr ::capnp::Kind Persistent::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* Persistent::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* Persistent::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope Persistent::_capnpPrivate::brandScopes[] = { - { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding Persistent::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema::Dependency Persistent::_capnpPrivate::brandDependencies[] = { - { 33554432, ::capnp::Persistent::SaveParams::_capnpPrivate::brand }, - { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand }, -}; -template -const ::capnp::_::RawBrandedSchema Persistent::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_c8cb212fcd9f5691, brandScopes, brandDependencies, - sizeof(brandScopes) / sizeof(brandScopes[0]), sizeof(brandDependencies) / sizeof(brandDependencies[0]), nullptr -}; -#endif // !CAPNP_LITE - -#if !CAPNP_LITE -template -inline RealmGateway::Client::Client(decltype(nullptr)) - : ::capnp::Capability::Client(nullptr) {} -template -inline RealmGateway::Client::Client( - ::kj::Own< ::capnp::ClientHook>&& hook) - : ::capnp::Capability::Client(::kj::mv(hook)) {} -template -template -inline RealmGateway::Client::Client(::kj::Own<_t>&& server) - : ::capnp::Capability::Client(::kj::mv(server)) {} -template -template -inline RealmGateway::Client::Client(::kj::Promise<_t>&& promise) - : ::capnp::Capability::Client(::kj::mv(promise)) {} -template -inline RealmGateway::Client::Client(::kj::Exception&& exception) - : ::capnp::Capability::Client(::kj::mv(exception)) {} -template -inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client& other) { - ::capnp::Capability::Client::operator=(other); - return *this; -} -template -inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client&& other) { - ::capnp::Capability::Client::operator=(kj::mv(other)); - return *this; -} - -#endif // !CAPNP_LITE -template -inline bool RealmGateway::ImportParams::Reader::hasCap() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline bool RealmGateway::ImportParams::Builder::hasCap() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -#if !CAPNP_LITE -template -inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Reader::getCap() const { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Builder::getCap() { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Pipeline::getCap() { - return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); -} -template -inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(cap)); -} -template -inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), cap); -} -template -inline void RealmGateway::ImportParams::Builder::adoptCap( - ::capnp::Orphan< ::capnp::Persistent>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ImportParams::Builder::disownCap() { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#endif // !CAPNP_LITE - -template -inline bool RealmGateway::ImportParams::Reader::hasParams() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -template -inline bool RealmGateway::ImportParams::Builder::hasParams() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -template -inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ImportParams::Reader::getParams() const { - return ::capnp::_::PointerHelpers::SaveParams>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::getParams() { - return ::capnp::_::PointerHelpers::SaveParams>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -template -inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ImportParams::Pipeline::getParams() { - return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); -} -#endif // !CAPNP_LITE -template -inline void RealmGateway::ImportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { - ::capnp::_::PointerHelpers::SaveParams>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -template -inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::initParams() { - return ::capnp::_::PointerHelpers::SaveParams>::init( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -template -inline void RealmGateway::ImportParams::Builder::adoptParams( - ::capnp::Orphan::SaveParams>&& value) { - ::capnp::_::PointerHelpers::SaveParams>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan::SaveParams> RealmGateway::ImportParams::Builder::disownParams() { - return ::capnp::_::PointerHelpers::SaveParams>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -// RealmGateway::ImportParams -template -constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::dataWordSize; -template -constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::pointerCount; -#if !CAPNP_LITE -template -constexpr ::capnp::Kind RealmGateway::ImportParams::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* RealmGateway::ImportParams::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* RealmGateway::ImportParams::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ImportParams::_capnpPrivate::brandScopes[] = { - { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ImportParams::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ImportParams::_capnpPrivate::brandDependencies[] = { - { 16777216, ::capnp::Persistent::_capnpPrivate::brand }, - { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand }, -}; -template -const ::capnp::_::RawBrandedSchema RealmGateway::ImportParams::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_f0c2cc1d3909574d, brandScopes, brandDependencies, - sizeof(brandScopes) / sizeof(brandScopes[0]), sizeof(brandDependencies) / sizeof(brandDependencies[0]), nullptr -}; -#endif // !CAPNP_LITE - -template -inline bool RealmGateway::ExportParams::Reader::hasCap() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -template -inline bool RealmGateway::ExportParams::Builder::hasCap() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -#if !CAPNP_LITE -template -inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Reader::getCap() const { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Builder::getCap() { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Pipeline::getCap() { - return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); -} -template -inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(cap)); -} -template -inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), cap); -} -template -inline void RealmGateway::ExportParams::Builder::adoptCap( - ::capnp::Orphan< ::capnp::Persistent>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ExportParams::Builder::disownCap() { - return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#endif // !CAPNP_LITE - -template -inline bool RealmGateway::ExportParams::Reader::hasParams() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -template -inline bool RealmGateway::ExportParams::Builder::hasParams() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -template -inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ExportParams::Reader::getParams() const { - return ::capnp::_::PointerHelpers::SaveParams>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -template -inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::getParams() { - return ::capnp::_::PointerHelpers::SaveParams>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -template -inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ExportParams::Pipeline::getParams() { - return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); -} -#endif // !CAPNP_LITE -template -inline void RealmGateway::ExportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { - ::capnp::_::PointerHelpers::SaveParams>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -template -inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::initParams() { - return ::capnp::_::PointerHelpers::SaveParams>::init( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -template -inline void RealmGateway::ExportParams::Builder::adoptParams( - ::capnp::Orphan::SaveParams>&& value) { - ::capnp::_::PointerHelpers::SaveParams>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -template -inline ::capnp::Orphan::SaveParams> RealmGateway::ExportParams::Builder::disownParams() { - return ::capnp::_::PointerHelpers::SaveParams>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -// RealmGateway::ExportParams -template -constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::dataWordSize; -template -constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::pointerCount; -#if !CAPNP_LITE -template -constexpr ::capnp::Kind RealmGateway::ExportParams::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* RealmGateway::ExportParams::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* RealmGateway::ExportParams::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ExportParams::_capnpPrivate::brandScopes[] = { - { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ExportParams::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ExportParams::_capnpPrivate::brandDependencies[] = { - { 16777216, ::capnp::Persistent::_capnpPrivate::brand }, - { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand }, -}; -template -const ::capnp::_::RawBrandedSchema RealmGateway::ExportParams::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_ecafa18b482da3aa, brandScopes, brandDependencies, - sizeof(brandScopes) / sizeof(brandScopes[0]), sizeof(brandDependencies) / sizeof(brandDependencies[0]), nullptr -}; -#endif // !CAPNP_LITE - -#if !CAPNP_LITE -template -::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults> -RealmGateway::Client::importRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { - return newCall::ImportParams, typename ::capnp::Persistent::SaveResults>( - 0x84ff286cd00a3ed4ull, 0, sizeHint); -} -template -::kj::Promise RealmGateway::Server::import(ImportContext) { - return ::capnp::Capability::Server::internalUnimplemented( - "capnp/persistent.capnp:RealmGateway", "import", - 0x84ff286cd00a3ed4ull, 0); -} -template -::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults> -RealmGateway::Client::exportRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { - return newCall::ExportParams, typename ::capnp::Persistent::SaveResults>( - 0x84ff286cd00a3ed4ull, 1, sizeHint); -} -template -::kj::Promise RealmGateway::Server::export_(ExportContext) { - return ::capnp::Capability::Server::internalUnimplemented( - "capnp/persistent.capnp:RealmGateway", "export", - 0x84ff286cd00a3ed4ull, 1); -} -template -::kj::Promise RealmGateway::Server::dispatchCall( - uint64_t interfaceId, uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { - switch (interfaceId) { - case 0x84ff286cd00a3ed4ull: - return dispatchCallInternal(methodId, context); - default: - return internalUnimplemented("capnp/persistent.capnp:RealmGateway", interfaceId); - } -} -template -::kj::Promise RealmGateway::Server::dispatchCallInternal( - uint16_t methodId, - ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { - switch (methodId) { - case 0: - return import(::capnp::Capability::Server::internalGetTypedContext< - typename ::capnp::RealmGateway::ImportParams, typename ::capnp::Persistent::SaveResults>(context)); - case 1: - return export_(::capnp::Capability::Server::internalGetTypedContext< - typename ::capnp::RealmGateway::ExportParams, typename ::capnp::Persistent::SaveResults>(context)); - default: - (void)context; - return ::capnp::Capability::Server::internalUnimplemented( - "capnp/persistent.capnp:RealmGateway", - 0x84ff286cd00a3ed4ull, methodId); - } -} -#endif // !CAPNP_LITE - -// RealmGateway -#if !CAPNP_LITE -template -constexpr ::capnp::Kind RealmGateway::_capnpPrivate::kind; -template -constexpr ::capnp::_::RawSchema const* RealmGateway::_capnpPrivate::schema; -template -constexpr ::capnp::_::RawBrandedSchema const* RealmGateway::_capnpPrivate::brand; -template -const ::capnp::_::RawBrandedSchema::Scope RealmGateway::_capnpPrivate::brandScopes[] = { - { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, -}; -template -const ::capnp::_::RawBrandedSchema::Binding RealmGateway::_capnpPrivate::brandBindings[] = { - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), - ::capnp::_::brandBindingFor(), -}; -template -const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::_capnpPrivate::brandDependencies[] = { - { 33554432, ::capnp::RealmGateway::ImportParams::_capnpPrivate::brand }, - { 33554433, ::capnp::RealmGateway::ExportParams::_capnpPrivate::brand }, - { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand }, - { 50331649, ::capnp::Persistent::SaveResults::_capnpPrivate::brand }, -}; -template -const ::capnp::_::RawBrandedSchema RealmGateway::_capnpPrivate::specificBrand = { - &::capnp::schemas::s_84ff286cd00a3ed4, brandScopes, brandDependencies, - sizeof(brandScopes) / sizeof(brandScopes[0]), sizeof(brandDependencies) / sizeof(brandDependencies[0]), nullptr -}; -#endif // !CAPNP_LITE - -} // namespace - -#endif // CAPNP_INCLUDED_b8630836983feed7_ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: persistent.capnp + +#ifndef CAPNP_INCLUDED_b8630836983feed7_ +#define CAPNP_INCLUDED_b8630836983feed7_ + +#include +#if !CAPNP_LITE +#include +#endif // !CAPNP_LITE + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(c8cb212fcd9f5691); +CAPNP_DECLARE_SCHEMA(f76fba59183073a5); +CAPNP_DECLARE_SCHEMA(b76848c18c40efbf); +CAPNP_DECLARE_SCHEMA(84ff286cd00a3ed4); +CAPNP_DECLARE_SCHEMA(f0c2cc1d3909574d); +CAPNP_DECLARE_SCHEMA(ecafa18b482da3aa); +CAPNP_DECLARE_SCHEMA(f622595091cafb67); + +} // namespace schemas +} // namespace capnp + +namespace capnp { + +template +struct Persistent { + Persistent() = delete; + +#if !CAPNP_LITE + class Client; + class Server; +#endif // !CAPNP_LITE + + struct SaveParams; + struct SaveResults; + + #if !CAPNP_LITE + struct _capnpPrivate { + CAPNP_DECLARE_INTERFACE_HEADER(c8cb212fcd9f5691) + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + }; + #endif // !CAPNP_LITE +}; + +template +struct Persistent::SaveParams { + SaveParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f76fba59183073a5, 0, 1) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct Persistent::SaveResults { + SaveResults() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b76848c18c40efbf, 0, 1) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct RealmGateway { + RealmGateway() = delete; + +#if !CAPNP_LITE + class Client; + class Server; +#endif // !CAPNP_LITE + + struct ImportParams; + struct ExportParams; + + #if !CAPNP_LITE + struct _capnpPrivate { + CAPNP_DECLARE_INTERFACE_HEADER(84ff286cd00a3ed4) + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + }; + #endif // !CAPNP_LITE +}; + +template +struct RealmGateway::ImportParams { + ImportParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f0c2cc1d3909574d, 0, 2) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct RealmGateway::ExportParams { + ExportParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ecafa18b482da3aa, 0, 2) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +#if !CAPNP_LITE +template +class Persistent::Client + : public virtual ::capnp::Capability::Client { +public: + typedef Persistent Calls; + typedef Persistent Reads; + + Client(decltype(nullptr)); + explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); + template ()>> + Client(::kj::Own<_t>&& server); + template ()>> + Client(::kj::Promise<_t>&& promise); + Client(::kj::Exception&& exception); + Client(Client&) = default; + Client(Client&&) = default; + Client& operator=(Client& other); + Client& operator=(Client&& other); + + template + typename Persistent::Client asGeneric() { + return castAs>(); + } + + CAPNP_AUTO_IF_MSVC(::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults>) saveRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + +protected: + Client() = default; +}; + +template +class Persistent::Server + : public virtual ::capnp::Capability::Server { +public: + typedef Persistent Serves; + + ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) + override; + +protected: + typedef ::capnp::CallContext::SaveParams, typename ::capnp::Persistent::SaveResults> SaveContext; + virtual ::kj::Promise save(SaveContext context); + + inline typename ::capnp::Persistent::Client thisCap() { + return ::capnp::Capability::Server::thisCap() + .template castAs< ::capnp::Persistent>(); + } + + ::kj::Promise dispatchCallInternal(uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); +}; +#endif // !CAPNP_LITE + +template +class Persistent::SaveParams::Reader { +public: + typedef SaveParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveParams::Reader asPersistentGeneric() { + return typename Persistent::SaveParams::Reader(_reader); + } + + inline bool hasSealFor() const; + inline ::capnp::ReaderFor getSealFor() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class Persistent::SaveParams::Builder { +public: + typedef SaveParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveParams::Builder asPersistentGeneric() { + return typename Persistent::SaveParams::Builder(_builder); + } + + inline bool hasSealFor(); + inline ::capnp::BuilderFor getSealFor(); + inline void setSealFor( ::capnp::ReaderFor value); + inline ::capnp::BuilderFor initSealFor(); + inline ::capnp::BuilderFor initSealFor(unsigned int size); + inline void adoptSealFor(::capnp::Orphan&& value); + inline ::capnp::Orphan disownSealFor(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class Persistent::SaveParams::Pipeline { +public: + typedef SaveParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::PipelineFor getSealFor(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +template +class Persistent::SaveResults::Reader { +public: + typedef SaveResults Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveResults::Reader asPersistentGeneric() { + return typename Persistent::SaveResults::Reader(_reader); + } + + inline bool hasSturdyRef() const; + inline ::capnp::ReaderFor getSturdyRef() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class Persistent::SaveResults::Builder { +public: + typedef SaveResults Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveResults::Builder asPersistentGeneric() { + return typename Persistent::SaveResults::Builder(_builder); + } + + inline bool hasSturdyRef(); + inline ::capnp::BuilderFor getSturdyRef(); + inline void setSturdyRef( ::capnp::ReaderFor value); + inline ::capnp::BuilderFor initSturdyRef(); + inline ::capnp::BuilderFor initSturdyRef(unsigned int size); + inline void adoptSturdyRef(::capnp::Orphan&& value); + inline ::capnp::Orphan disownSturdyRef(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class Persistent::SaveResults::Pipeline { +public: + typedef SaveResults Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::PipelineFor getSturdyRef(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +class RealmGateway::Client + : public virtual ::capnp::Capability::Client { +public: + typedef RealmGateway Calls; + typedef RealmGateway Reads; + + Client(decltype(nullptr)); + explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); + template ()>> + Client(::kj::Own<_t>&& server); + template ()>> + Client(::kj::Promise<_t>&& promise); + Client(::kj::Exception&& exception); + Client(Client&) = default; + Client(Client&&) = default; + Client& operator=(Client& other); + Client& operator=(Client&& other); + + template + typename RealmGateway::Client asGeneric() { + return castAs>(); + } + + CAPNP_AUTO_IF_MSVC(::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults>) importRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + CAPNP_AUTO_IF_MSVC(::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults>) exportRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + +protected: + Client() = default; +}; + +template +class RealmGateway::Server + : public virtual ::capnp::Capability::Server { +public: + typedef RealmGateway Serves; + + ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) + override; + +protected: + typedef typename ::capnp::RealmGateway::ImportParams ImportParams; + typedef ::capnp::CallContext::SaveResults> ImportContext; + virtual ::kj::Promise import(ImportContext context); + typedef typename ::capnp::RealmGateway::ExportParams ExportParams; + typedef ::capnp::CallContext::SaveResults> ExportContext; + virtual ::kj::Promise export_(ExportContext context); + + inline typename ::capnp::RealmGateway::Client thisCap() { + return ::capnp::Capability::Server::thisCap() + .template castAs< ::capnp::RealmGateway>(); + } + + ::kj::Promise dispatchCallInternal(uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); +}; +#endif // !CAPNP_LITE + +template +class RealmGateway::ImportParams::Reader { +public: + typedef ImportParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ImportParams::Reader asRealmGatewayGeneric() { + return typename RealmGateway::ImportParams::Reader(_reader); + } + + inline bool hasCap() const; +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap() const; +#endif // !CAPNP_LITE + + inline bool hasParams() const; + inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class RealmGateway::ImportParams::Builder { +public: + typedef ImportParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ImportParams::Builder asRealmGatewayGeneric() { + return typename RealmGateway::ImportParams::Builder(_builder); + } + + inline bool hasCap(); +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap(); + inline void setCap(typename ::capnp::Persistent::Client&& value); + inline void setCap(typename ::capnp::Persistent::Client& value); + inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); + inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); +#endif // !CAPNP_LITE + + inline bool hasParams(); + inline typename ::capnp::Persistent::SaveParams::Builder getParams(); + inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); + inline typename ::capnp::Persistent::SaveParams::Builder initParams(); + inline void adoptParams(::capnp::Orphan::SaveParams>&& value); + inline ::capnp::Orphan::SaveParams> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class RealmGateway::ImportParams::Pipeline { +public: + typedef ImportParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename ::capnp::Persistent::Client getCap(); + inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +template +class RealmGateway::ExportParams::Reader { +public: + typedef ExportParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ExportParams::Reader asRealmGatewayGeneric() { + return typename RealmGateway::ExportParams::Reader(_reader); + } + + inline bool hasCap() const; +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap() const; +#endif // !CAPNP_LITE + + inline bool hasParams() const; + inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class RealmGateway::ExportParams::Builder { +public: + typedef ExportParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ExportParams::Builder asRealmGatewayGeneric() { + return typename RealmGateway::ExportParams::Builder(_builder); + } + + inline bool hasCap(); +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap(); + inline void setCap(typename ::capnp::Persistent::Client&& value); + inline void setCap(typename ::capnp::Persistent::Client& value); + inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); + inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); +#endif // !CAPNP_LITE + + inline bool hasParams(); + inline typename ::capnp::Persistent::SaveParams::Builder getParams(); + inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); + inline typename ::capnp::Persistent::SaveParams::Builder initParams(); + inline void adoptParams(::capnp::Orphan::SaveParams>&& value); + inline ::capnp::Orphan::SaveParams> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class RealmGateway::ExportParams::Pipeline { +public: + typedef ExportParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename ::capnp::Persistent::Client getCap(); + inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +#if !CAPNP_LITE +template +inline Persistent::Client::Client(decltype(nullptr)) + : ::capnp::Capability::Client(nullptr) {} +template +inline Persistent::Client::Client( + ::kj::Own< ::capnp::ClientHook>&& hook) + : ::capnp::Capability::Client(::kj::mv(hook)) {} +template +template +inline Persistent::Client::Client(::kj::Own<_t>&& server) + : ::capnp::Capability::Client(::kj::mv(server)) {} +template +template +inline Persistent::Client::Client(::kj::Promise<_t>&& promise) + : ::capnp::Capability::Client(::kj::mv(promise)) {} +template +inline Persistent::Client::Client(::kj::Exception&& exception) + : ::capnp::Capability::Client(::kj::mv(exception)) {} +template +inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client& other) { + ::capnp::Capability::Client::operator=(other); + return *this; +} +template +inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client&& other) { + ::capnp::Capability::Client::operator=(kj::mv(other)); + return *this; +} + +#endif // !CAPNP_LITE +template +inline bool Persistent::SaveParams::Reader::hasSealFor() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool Persistent::SaveParams::Builder::hasSealFor() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline ::capnp::ReaderFor Persistent::SaveParams::Reader::getSealFor() const { + return ::capnp::_::PointerHelpers::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::getSealFor() { + return ::capnp::_::PointerHelpers::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline ::capnp::PipelineFor Persistent::SaveParams::Pipeline::getSealFor() { + return ::capnp::PipelineFor(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +template +inline void Persistent::SaveParams::Builder::setSealFor( ::capnp::ReaderFor value) { + ::capnp::_::PointerHelpers::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor() { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor(unsigned int size) { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +template +inline void Persistent::SaveParams::Builder::adoptSealFor( + ::capnp::Orphan&& value) { + ::capnp::_::PointerHelpers::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan Persistent::SaveParams::Builder::disownSealFor() { + return ::capnp::_::PointerHelpers::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +// Persistent::SaveParams +template +constexpr uint16_t Persistent::SaveParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t Persistent::SaveParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::SaveParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::SaveParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveParams::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema Persistent::SaveParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_f76fba59183073a5, brandScopes, nullptr, + 1, 0, nullptr +}; +#endif // !CAPNP_LITE + +template +inline bool Persistent::SaveResults::Reader::hasSturdyRef() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool Persistent::SaveResults::Builder::hasSturdyRef() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline ::capnp::ReaderFor Persistent::SaveResults::Reader::getSturdyRef() const { + return ::capnp::_::PointerHelpers::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::getSturdyRef() { + return ::capnp::_::PointerHelpers::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline ::capnp::PipelineFor Persistent::SaveResults::Pipeline::getSturdyRef() { + return ::capnp::PipelineFor(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +template +inline void Persistent::SaveResults::Builder::setSturdyRef( ::capnp::ReaderFor value) { + ::capnp::_::PointerHelpers::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef() { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef(unsigned int size) { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +template +inline void Persistent::SaveResults::Builder::adoptSturdyRef( + ::capnp::Orphan&& value) { + ::capnp::_::PointerHelpers::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan Persistent::SaveResults::Builder::disownSturdyRef() { + return ::capnp::_::PointerHelpers::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +// Persistent::SaveResults +template +constexpr uint16_t Persistent::SaveResults::_capnpPrivate::dataWordSize; +template +constexpr uint16_t Persistent::SaveResults::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::SaveResults::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::SaveResults::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveResults::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveResults::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema Persistent::SaveResults::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_b76848c18c40efbf, brandScopes, nullptr, + 1, 0, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults>) +Persistent::Client::saveRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::SaveParams, typename ::capnp::Persistent::SaveResults>( + 0xc8cb212fcd9f5691ull, 0, sizeHint); +} +template +::kj::Promise Persistent::Server::save(SaveContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:Persistent", "save", + 0xc8cb212fcd9f5691ull, 0); +} +template +::kj::Promise Persistent::Server::dispatchCall( + uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (interfaceId) { + case 0xc8cb212fcd9f5691ull: + return dispatchCallInternal(methodId, context); + default: + return internalUnimplemented("capnp/persistent.capnp:Persistent", interfaceId); + } +} +template +::kj::Promise Persistent::Server::dispatchCallInternal( + uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (methodId) { + case 0: + return save(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::Persistent::SaveParams, typename ::capnp::Persistent::SaveResults>(context)); + default: + (void)context; + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:Persistent", + 0xc8cb212fcd9f5691ull, methodId); + } +} +#endif // !CAPNP_LITE + +// Persistent +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency Persistent::_capnpPrivate::brandDependencies[] = { + { 33554432, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema Persistent::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_c8cb212fcd9f5691, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +inline RealmGateway::Client::Client(decltype(nullptr)) + : ::capnp::Capability::Client(nullptr) {} +template +inline RealmGateway::Client::Client( + ::kj::Own< ::capnp::ClientHook>&& hook) + : ::capnp::Capability::Client(::kj::mv(hook)) {} +template +template +inline RealmGateway::Client::Client(::kj::Own<_t>&& server) + : ::capnp::Capability::Client(::kj::mv(server)) {} +template +template +inline RealmGateway::Client::Client(::kj::Promise<_t>&& promise) + : ::capnp::Capability::Client(::kj::mv(promise)) {} +template +inline RealmGateway::Client::Client(::kj::Exception&& exception) + : ::capnp::Capability::Client(::kj::mv(exception)) {} +template +inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client& other) { + ::capnp::Capability::Client::operator=(other); + return *this; +} +template +inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client&& other) { + ::capnp::Capability::Client::operator=(kj::mv(other)); + return *this; +} + +#endif // !CAPNP_LITE +template +inline bool RealmGateway::ImportParams::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ImportParams::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Reader::getCap() const { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Builder::getCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Pipeline::getCap() { + return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); +} +template +inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(cap)); +} +template +inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), cap); +} +template +inline void RealmGateway::ImportParams::Builder::adoptCap( + ::capnp::Orphan< ::capnp::Persistent>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ImportParams::Builder::disownCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ImportParams::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ImportParams::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ImportParams::Reader::getParams() const { + return ::capnp::_::PointerHelpers::SaveParams>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::getParams() { + return ::capnp::_::PointerHelpers::SaveParams>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ImportParams::Pipeline::getParams() { + return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +template +inline void RealmGateway::ImportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { + ::capnp::_::PointerHelpers::SaveParams>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::initParams() { + return ::capnp::_::PointerHelpers::SaveParams>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline void RealmGateway::ImportParams::Builder::adoptParams( + ::capnp::Orphan::SaveParams>&& value) { + ::capnp::_::PointerHelpers::SaveParams>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan::SaveParams> RealmGateway::ImportParams::Builder::disownParams() { + return ::capnp::_::PointerHelpers::SaveParams>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +// RealmGateway::ImportParams +template +constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::ImportParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::ImportParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ImportParams::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ImportParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ImportParams::_capnpPrivate::brandDependencies[] = { + { 16777216, ::capnp::Persistent::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::ImportParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_f0c2cc1d3909574d, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ExportParams::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ExportParams::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Reader::getCap() const { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Builder::getCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Pipeline::getCap() { + return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); +} +template +inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(cap)); +} +template +inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), cap); +} +template +inline void RealmGateway::ExportParams::Builder::adoptCap( + ::capnp::Orphan< ::capnp::Persistent>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ExportParams::Builder::disownCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ExportParams::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ExportParams::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ExportParams::Reader::getParams() const { + return ::capnp::_::PointerHelpers::SaveParams>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::getParams() { + return ::capnp::_::PointerHelpers::SaveParams>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ExportParams::Pipeline::getParams() { + return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +template +inline void RealmGateway::ExportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { + ::capnp::_::PointerHelpers::SaveParams>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::initParams() { + return ::capnp::_::PointerHelpers::SaveParams>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline void RealmGateway::ExportParams::Builder::adoptParams( + ::capnp::Orphan::SaveParams>&& value) { + ::capnp::_::PointerHelpers::SaveParams>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan::SaveParams> RealmGateway::ExportParams::Builder::disownParams() { + return ::capnp::_::PointerHelpers::SaveParams>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +// RealmGateway::ExportParams +template +constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::ExportParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::ExportParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ExportParams::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ExportParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ExportParams::_capnpPrivate::brandDependencies[] = { + { 16777216, ::capnp::Persistent::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::ExportParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_ecafa18b482da3aa, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults>) +RealmGateway::Client::importRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::ImportParams, typename ::capnp::Persistent::SaveResults>( + 0x84ff286cd00a3ed4ull, 0, sizeHint); +} +template +::kj::Promise RealmGateway::Server::import(ImportContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", "import", + 0x84ff286cd00a3ed4ull, 0); +} +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults>) +RealmGateway::Client::exportRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::ExportParams, typename ::capnp::Persistent::SaveResults>( + 0x84ff286cd00a3ed4ull, 1, sizeHint); +} +template +::kj::Promise RealmGateway::Server::export_(ExportContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", "export", + 0x84ff286cd00a3ed4ull, 1); +} +template +::kj::Promise RealmGateway::Server::dispatchCall( + uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (interfaceId) { + case 0x84ff286cd00a3ed4ull: + return dispatchCallInternal(methodId, context); + default: + return internalUnimplemented("capnp/persistent.capnp:RealmGateway", interfaceId); + } +} +template +::kj::Promise RealmGateway::Server::dispatchCallInternal( + uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (methodId) { + case 0: + return import(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::RealmGateway::ImportParams, typename ::capnp::Persistent::SaveResults>(context)); + case 1: + return export_(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::RealmGateway::ExportParams, typename ::capnp::Persistent::SaveResults>(context)); + default: + (void)context; + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", + 0x84ff286cd00a3ed4ull, methodId); + } +} +#endif // !CAPNP_LITE + +// RealmGateway +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::_capnpPrivate::brandDependencies[] = { + { 33554432, ::capnp::RealmGateway::ImportParams::_capnpPrivate::brand() }, + { 33554433, ::capnp::RealmGateway::ExportParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, + { 50331649, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_84ff286cd00a3ed4, brandScopes, brandDependencies, + 1, 4, nullptr +}; +#endif // !CAPNP_LITE + +} // namespace + +#endif // CAPNP_INCLUDED_b8630836983feed7_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/pointer-helpers.h --- a/osx/include/capnp/pointer-helpers.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/pointer-helpers.h Mon May 22 10:01:37 2017 +0100 @@ -1,160 +1,160 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_POINTER_HELPERS_H_ -#define CAPNP_POINTER_HELPERS_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "layout.h" -#include "list.h" - -namespace capnp { -namespace _ { // private - -// PointerHelpers is a template class that assists in wrapping/unwrapping the low-level types in -// layout.h with the high-level public API and generated types. This way, the code generator -// and other templates do not have to specialize on each kind of pointer. - -template -struct PointerHelpers { - static inline typename T::Reader get(PointerReader reader, const word* defaultValue = nullptr) { - return typename T::Reader(reader.getStruct(defaultValue)); - } - static inline typename T::Builder get(PointerBuilder builder, - const word* defaultValue = nullptr) { - return typename T::Builder(builder.getStruct(structSize(), defaultValue)); - } - static inline void set(PointerBuilder builder, typename T::Reader value) { - builder.setStruct(value._reader); - } - static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { - builder.setStruct(value._reader, true); - } - static inline typename T::Builder init(PointerBuilder builder) { - return typename T::Builder(builder.initStruct(structSize())); - } - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder) { - return Orphan(builder.disown()); - } - static inline _::StructReader getInternalReader(const typename T::Reader& reader) { - return reader._reader; - } - static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) { - return builder._builder; - } -}; - -template -struct PointerHelpers, Kind::LIST> { - static inline typename List::Reader get(PointerReader reader, - const word* defaultValue = nullptr) { - return typename List::Reader(List::getFromPointer(reader, defaultValue)); - } - static inline typename List::Builder get(PointerBuilder builder, - const word* defaultValue = nullptr) { - return typename List::Builder(List::getFromPointer(builder, defaultValue)); - } - static inline void set(PointerBuilder builder, typename List::Reader value) { - builder.setList(value.reader); - } - static inline void setCanonical(PointerBuilder builder, typename List::Reader value) { - builder.setList(value.reader, true); - } - static void set(PointerBuilder builder, kj::ArrayPtr> value) { - auto l = init(builder, value.size()); - uint i = 0; - for (auto& element: value) { - l.set(i++, element); - } - } - static inline typename List::Builder init(PointerBuilder builder, uint size) { - return typename List::Builder(List::initPointer(builder, size)); - } - static inline void adopt(PointerBuilder builder, Orphan>&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan> disown(PointerBuilder builder) { - return Orphan>(builder.disown()); - } - static inline _::ListReader getInternalReader(const typename List::Reader& reader) { - return reader.reader; - } - static inline _::ListBuilder getInternalBuilder(typename List::Builder&& builder) { - return builder.builder; - } -}; - -template -struct PointerHelpers { - static inline typename T::Reader get(PointerReader reader, - const void* defaultValue = nullptr, - uint defaultBytes = 0) { - return reader.getBlob(defaultValue, defaultBytes * BYTES); - } - static inline typename T::Builder get(PointerBuilder builder, - const void* defaultValue = nullptr, - uint defaultBytes = 0) { - return builder.getBlob(defaultValue, defaultBytes * BYTES); - } - static inline void set(PointerBuilder builder, typename T::Reader value) { - builder.setBlob(value); - } - static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { - builder.setBlob(value); - } - static inline typename T::Builder init(PointerBuilder builder, uint size) { - return builder.initBlob(size * BYTES); - } - static inline void adopt(PointerBuilder builder, Orphan&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan disown(PointerBuilder builder) { - return Orphan(builder.disown()); - } -}; - -struct UncheckedMessage { - typedef const word* Reader; -}; - -template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; - -template <> -struct PointerHelpers { - // Reads an AnyPointer 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(PointerReader reader) { - return reader.getUnchecked(); - } -}; - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_POINTER_HELPERS_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_POINTER_HELPERS_H_ +#define CAPNP_POINTER_HELPERS_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "list.h" + +namespace capnp { +namespace _ { // private + +// PointerHelpers is a template class that assists in wrapping/unwrapping the low-level types in +// layout.h with the high-level public API and generated types. This way, the code generator +// and other templates do not have to specialize on each kind of pointer. + +template +struct PointerHelpers { + static inline typename T::Reader get(PointerReader reader, const word* defaultValue = nullptr) { + return typename T::Reader(reader.getStruct(defaultValue)); + } + static inline typename T::Builder get(PointerBuilder builder, + const word* defaultValue = nullptr) { + return typename T::Builder(builder.getStruct(structSize(), defaultValue)); + } + static inline void set(PointerBuilder builder, typename T::Reader value) { + builder.setStruct(value._reader); + } + static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { + builder.setStruct(value._reader, true); + } + static inline typename T::Builder init(PointerBuilder builder) { + return typename T::Builder(builder.initStruct(structSize())); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } + static inline _::StructReader getInternalReader(const typename T::Reader& reader) { + return reader._reader; + } + static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) { + return builder._builder; + } +}; + +template +struct PointerHelpers, Kind::LIST> { + static inline typename List::Reader get(PointerReader reader, + const word* defaultValue = nullptr) { + return typename List::Reader(List::getFromPointer(reader, defaultValue)); + } + static inline typename List::Builder get(PointerBuilder builder, + const word* defaultValue = nullptr) { + return typename List::Builder(List::getFromPointer(builder, defaultValue)); + } + static inline void set(PointerBuilder builder, typename List::Reader value) { + builder.setList(value.reader); + } + static inline void setCanonical(PointerBuilder builder, typename List::Reader value) { + builder.setList(value.reader, true); + } + static void set(PointerBuilder builder, kj::ArrayPtr> value) { + auto l = init(builder, value.size()); + uint i = 0; + for (auto& element: value) { + l.set(i++, element); + } + } + static inline typename List::Builder init(PointerBuilder builder, uint size) { + return typename List::Builder(List::initPointer(builder, size)); + } + static inline void adopt(PointerBuilder builder, Orphan>&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan> disown(PointerBuilder builder) { + return Orphan>(builder.disown()); + } + static inline _::ListReader getInternalReader(const typename List::Reader& reader) { + return reader.reader; + } + static inline _::ListBuilder getInternalBuilder(typename List::Builder&& builder) { + return builder.builder; + } +}; + +template +struct PointerHelpers { + static inline typename T::Reader get(PointerReader reader, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return reader.getBlob(defaultValue, bounded(defaultBytes) * BYTES); + } + static inline typename T::Builder get(PointerBuilder builder, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return builder.getBlob(defaultValue, bounded(defaultBytes) * BYTES); + } + static inline void set(PointerBuilder builder, typename T::Reader value) { + builder.setBlob(value); + } + static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { + builder.setBlob(value); + } + static inline typename T::Builder init(PointerBuilder builder, uint size) { + return builder.initBlob(bounded(size) * BYTES); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +struct UncheckedMessage { + typedef const word* Reader; +}; + +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; + +template <> +struct PointerHelpers { + // Reads an AnyPointer 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(PointerReader reader) { + return reader.getUnchecked(); + } +}; + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_POINTER_HELPERS_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/pretty-print.h --- a/osx/include/capnp/pretty-print.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/pretty-print.h Mon May 22 10:01:37 2017 +0100 @@ -1,47 +1,47 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_PRETTY_PRINT_H_ -#define CAPNP_PRETTY_PRINT_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "dynamic.h" -#include - -namespace capnp { - -kj::StringTree prettyPrint(DynamicStruct::Reader value); -kj::StringTree prettyPrint(DynamicStruct::Builder value); -kj::StringTree prettyPrint(DynamicList::Reader value); -kj::StringTree prettyPrint(DynamicList::Builder value); -// Print the given Cap'n Proto struct or list with nice indentation. Note that you can pass any -// struct or list reader or builder type to this method, since they can be implicitly converted -// to one of the dynamic types. -// -// If you don't want indentation, just use the value's KJ stringifier (e.g. pass it to kj::str(), -// any of the KJ debug macros, etc.). - -} // namespace capnp - -#endif // PRETTY_PRINT_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_PRETTY_PRINT_H_ +#define CAPNP_PRETTY_PRINT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "dynamic.h" +#include + +namespace capnp { + +kj::StringTree prettyPrint(DynamicStruct::Reader value); +kj::StringTree prettyPrint(DynamicStruct::Builder value); +kj::StringTree prettyPrint(DynamicList::Reader value); +kj::StringTree prettyPrint(DynamicList::Builder value); +// Print the given Cap'n Proto struct or list with nice indentation. Note that you can pass any +// struct or list reader or builder type to this method, since they can be implicitly converted +// to one of the dynamic types. +// +// If you don't want indentation, just use the value's KJ stringifier (e.g. pass it to kj::str(), +// any of the KJ debug macros, etc.). + +} // namespace capnp + +#endif // PRETTY_PRINT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/raw-schema.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/capnp/raw-schema.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,242 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RAW_SCHEMA_H_ +#define CAPNP_RAW_SCHEMA_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" // for uint and friends + +#if _MSC_VER +#include +#endif + +namespace capnp { +namespace _ { // private + +struct RawSchema; + +struct RawBrandedSchema { + // Represents a combination of a schema and bindings for its generic parameters. + // + // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for + // every _instance_ of a generic type -- or, at least, every instance that is actually used. For + // generated-code types, we use template magic to initialize these. + + const RawSchema* generic; + // Generic type which we're branding. + + struct Binding { + uint8_t which; // Numeric value of one of schema::Type::Which. + + bool isImplicitParameter; + // For AnyPointer, true if it's an implicit method parameter. + + uint16_t listDepth; // Number of times to wrap the base type in List(). + + uint16_t paramIndex; + // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter + // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric + // value of one of schema::Type::AnyPointer::Unconstrained::Which. + + union { + const RawBrandedSchema* schema; // for struct, enum, interface + uint64_t scopeId; // for AnyPointer, if it's a type parameter + }; + + Binding() = default; + inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) + : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0), + schema(schema) {} + inline constexpr Binding(uint8_t which, uint16_t listDepth, + uint64_t scopeId, uint16_t paramIndex) + : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex), + scopeId(scopeId) {} + inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex) + : which(which), isImplicitParameter(true), listDepth(listDepth), + paramIndex(implicitParamIndex), scopeId(0) {} + }; + + struct Scope { + uint64_t typeId; + // Type ID whose parameters are being bound. + + const Binding* bindings; + uint bindingCount; + // Bindings for those parameters. + + bool isUnbound; + // This scope is unbound, in the sense of SchemaLoader::getUnbound(). + }; + + const Scope* scopes; + // Array of enclosing scopes for which generic variables have been bound, sorted by type ID. + + struct Dependency { + uint location; + const RawBrandedSchema* schema; + }; + + const Dependency* dependencies; + // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that + // are branded are included in this map; if a dependency is missing, use its `defaultBrand`. + + uint32_t scopeCount; + uint32_t dependencyCount; + + enum class DepKind { + // Component of a Dependency::location. Specifies what sort of dependency this is. + + INVALID, + // Mostly defined to ensure that zero is not a valid location. + + FIELD, + // Binding needed for a field's type. The index is the field index (NOT ordinal!). + + METHOD_PARAMS, + // Bindings needed for a method's params type. The index is the method number. + + METHOD_RESULTS, + // Bindings needed for a method's results type. The index is the method ordinal. + + SUPERCLASS, + // Bindings needed for a superclass type. The index is the superclass's index in the + // "extends" list. + + CONST_TYPE + // Bindings needed for the type of a constant. The index is zero. + }; + + static inline uint makeDepLocation(DepKind kind, uint index) { + // Make a number representing the location of a particular dependency within its parent + // schema. + + return (static_cast(kind) << 24) | index; + } + + class Initializer { + public: + virtual void init(const RawBrandedSchema* generic) 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. + +#if __GNUC__ + const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); +#elif _MSC_VER + const Initializer* i = *static_cast(&lazyInitializer); + std::atomic_thread_fence(std::memory_order_acquire); +#else +#error "Platform not supported" +#endif + if (i != nullptr) i->init(this); + } + + inline bool isUnbound() const; + // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case + // binding lookups need to be handled specially. +}; + +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(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. + + const uint16_t* 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 uint16_t* membersByDiscriminant; + // List of all member indexes ordered by discriminant value. Those which don't have a + // discriminant value are listed at the end, in order by ordinal. + + 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. + +#if __GNUC__ + const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); +#elif _MSC_VER + const Initializer* i = *static_cast(&lazyInitializer); + std::atomic_thread_fence(std::memory_order_acquire); +#else +#error "Platform not supported" +#endif + if (i != nullptr) i->init(this); + } + + RawBrandedSchema defaultBrand; + // Specifies the brand to use for this schema if no generic parameters have been bound to + // anything. Generally, in the default brand, all generic parameters are treated as if they were + // bound to `AnyPointer`. +}; + +inline bool RawBrandedSchema::isUnbound() const { + // The unbound schema is the only one that has no scopes but is not the default schema. + return scopeCount == 0 && this != &generic->defaultBrand; +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_RAW_SCHEMA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc-prelude.h --- a/osx/include/capnp/rpc-prelude.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc-prelude.h Mon May 22 10:01:37 2017 +0100 @@ -1,130 +1,130 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file contains a bunch of internal declarations that must appear before rpc.h can start. -// We don't define these directly in rpc.h because it makes the file hard to read. - -#ifndef CAPNP_RPC_PRELUDE_H_ -#define CAPNP_RPC_PRELUDE_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "capability.h" -#include "persistent.capnp.h" - -namespace capnp { - -class OutgoingRpcMessage; -class IncomingRpcMessage; - -template -class RpcSystem; - -namespace _ { // private - -class VatNetworkBase { - // Non-template version of VatNetwork. Ignore this class; see VatNetwork in rpc.h. - -public: - class Connection; - - struct ConnectionAndProvisionId { - kj::Own connection; - kj::Own firstMessage; - Orphan provisionId; - }; - - class Connection { - public: - virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) = 0; - virtual kj::Promise>> receiveIncomingMessage() = 0; - virtual kj::Promise shutdown() = 0; - virtual AnyStruct::Reader baseGetPeerVatId() = 0; - }; - virtual kj::Maybe> baseConnect(AnyStruct::Reader vatId) = 0; - virtual kj::Promise> baseAccept() = 0; -}; - -class SturdyRefRestorerBase { -public: - virtual Capability::Client baseRestore(AnyPointer::Reader ref) = 0; -}; - -class BootstrapFactoryBase { - // Non-template version of BootstrapFactory. Ignore this class; see BootstrapFactory in rpc.h. -public: - virtual Capability::Client baseCreateFor(AnyStruct::Reader clientId) = 0; -}; - -class RpcSystemBase { - // Non-template version of RpcSystem. Ignore this class; see RpcSystem in rpc.h. - -public: - RpcSystemBase(VatNetworkBase& network, kj::Maybe bootstrapInterface, - kj::Maybe::Client> gateway); - RpcSystemBase(VatNetworkBase& network, BootstrapFactoryBase& bootstrapFactory, - kj::Maybe::Client> gateway); - RpcSystemBase(VatNetworkBase& network, SturdyRefRestorerBase& restorer); - RpcSystemBase(RpcSystemBase&& other) noexcept; - ~RpcSystemBase() noexcept(false); - -private: - class Impl; - kj::Own impl; - - Capability::Client baseBootstrap(AnyStruct::Reader vatId); - Capability::Client baseRestore(AnyStruct::Reader vatId, AnyPointer::Reader objectId); - void baseSetFlowLimit(size_t words); - - template - friend class capnp::RpcSystem; -}; - -template struct InternalRefFromRealmGateway_; -template -struct InternalRefFromRealmGateway_> { - typedef InternalRef Type; -}; -template -using InternalRefFromRealmGateway = typename InternalRefFromRealmGateway_::Type; -template -using InternalRefFromRealmGatewayClient = InternalRefFromRealmGateway; - -template struct ExternalRefFromRealmGateway_; -template -struct ExternalRefFromRealmGateway_> { - typedef ExternalRef Type; -}; -template -using ExternalRefFromRealmGateway = typename ExternalRefFromRealmGateway_::Type; -template -using ExternalRefFromRealmGatewayClient = ExternalRefFromRealmGateway; - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_RPC_PRELUDE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains a bunch of internal declarations that must appear before rpc.h can start. +// We don't define these directly in rpc.h because it makes the file hard to read. + +#ifndef CAPNP_RPC_PRELUDE_H_ +#define CAPNP_RPC_PRELUDE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "capability.h" +#include "persistent.capnp.h" + +namespace capnp { + +class OutgoingRpcMessage; +class IncomingRpcMessage; + +template +class RpcSystem; + +namespace _ { // private + +class VatNetworkBase { + // Non-template version of VatNetwork. Ignore this class; see VatNetwork in rpc.h. + +public: + class Connection; + + struct ConnectionAndProvisionId { + kj::Own connection; + kj::Own firstMessage; + Orphan provisionId; + }; + + class Connection { + public: + virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) = 0; + virtual kj::Promise>> receiveIncomingMessage() = 0; + virtual kj::Promise shutdown() = 0; + virtual AnyStruct::Reader baseGetPeerVatId() = 0; + }; + virtual kj::Maybe> baseConnect(AnyStruct::Reader vatId) = 0; + virtual kj::Promise> baseAccept() = 0; +}; + +class SturdyRefRestorerBase { +public: + virtual Capability::Client baseRestore(AnyPointer::Reader ref) = 0; +}; + +class BootstrapFactoryBase { + // Non-template version of BootstrapFactory. Ignore this class; see BootstrapFactory in rpc.h. +public: + virtual Capability::Client baseCreateFor(AnyStruct::Reader clientId) = 0; +}; + +class RpcSystemBase { + // Non-template version of RpcSystem. Ignore this class; see RpcSystem in rpc.h. + +public: + RpcSystemBase(VatNetworkBase& network, kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway); + RpcSystemBase(VatNetworkBase& network, BootstrapFactoryBase& bootstrapFactory, + kj::Maybe::Client> gateway); + RpcSystemBase(VatNetworkBase& network, SturdyRefRestorerBase& restorer); + RpcSystemBase(RpcSystemBase&& other) noexcept; + ~RpcSystemBase() noexcept(false); + +private: + class Impl; + kj::Own impl; + + Capability::Client baseBootstrap(AnyStruct::Reader vatId); + Capability::Client baseRestore(AnyStruct::Reader vatId, AnyPointer::Reader objectId); + void baseSetFlowLimit(size_t words); + + template + friend class capnp::RpcSystem; +}; + +template struct InternalRefFromRealmGateway_; +template +struct InternalRefFromRealmGateway_> { + typedef InternalRef Type; +}; +template +using InternalRefFromRealmGateway = typename InternalRefFromRealmGateway_::Type; +template +using InternalRefFromRealmGatewayClient = InternalRefFromRealmGateway; + +template struct ExternalRefFromRealmGateway_; +template +struct ExternalRefFromRealmGateway_> { + typedef ExternalRef Type; +}; +template +using ExternalRefFromRealmGateway = typename ExternalRefFromRealmGateway_::Type; +template +using ExternalRefFromRealmGatewayClient = ExternalRefFromRealmGateway; + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_RPC_PRELUDE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc-twoparty.capnp --- a/osx/include/capnp/rpc-twoparty.capnp Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc-twoparty.capnp Mon May 22 10:01:37 2017 +0100 @@ -1,169 +1,169 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xa184c7885cdaf2a1; -# This file defines the "network-specific parameters" in rpc.capnp to support a network consisting -# of two vats. Each of these vats may in fact be in communication with other vats, but any -# capabilities they forward must be proxied. Thus, to each end of the connection, all capabilities -# received from the other end appear to live in a single vat. -# -# Two notable use cases for this model include: -# - Regular client-server communications, where a remote client machine (perhaps living on an end -# user's personal device) connects to a server. The server may be part of a cluster, and may -# call on other servers in the cluster to help service the user's request. It may even obtain -# capabilities from these other servers which it passes on to the user. To simplify network -# common traversal problems (e.g. if the user is behind a firewall), it is probably desirable to -# multiplex all communications between the server cluster and the client over the original -# connection rather than form new ones. This connection should use the two-party protocol, as -# the client has no interest in knowing about additional servers. -# - Applications running in a sandbox. A supervisor process may execute a confined application -# such that all of the confined app's communications with the outside world must pass through -# the supervisor. In this case, the connection between the confined app and the supervisor might -# as well use the two-party protocol, because the confined app is intentionally prevented from -# talking to any other vat anyway. Any external resources will be proxied through the supervisor, -# and so to the contained app will appear as if they were hosted by the supervisor itself. -# -# Since there are only two vats in this network, there is never a need for three-way introductions, -# so level 3 is free. Moreover, because it is never necessary to form new connections, the -# two-party protocol can be used easily anywhere where a two-way byte stream exists, without regard -# to where that byte stream goes or how it was initiated. This makes the two-party runtime library -# highly reusable. -# -# Joins (level 4) _could_ be needed in cases where one or both vats are participating in other -# networks that use joins. For instance, if Alice and Bob are speaking through the two-party -# protocol, and Bob is also participating on another network, Bob may send Alice two or more -# proxied capabilities which, unbeknownst to Bob at the time, are in fact pointing at the same -# remote object. Alice may then request to join these capabilities, at which point Bob will have -# to forward the join to the other network. Note, however, that if Alice is _not_ participating on -# any other network, then Alice will never need to _receive_ a Join, because Alice would always -# know when two locally-hosted capabilities are the same and would never export a redundant alias -# to Bob. So, Alice can respond to all incoming joins with an error, and only needs to implement -# outgoing joins if she herself desires to use this feature. Also, outgoing joins are relatively -# easy to implement in this scenario. -# -# What all this means is that a level 4 implementation of the confined network is barely more -# complicated than a level 2 implementation. However, such an implementation allows the "client" -# or "confined" app to access the server's/supervisor's network with equal functionality to any -# native participant. In other words, an application which implements only the two-party protocol -# can be paired with a proxy app in order to participate in any network. -# -# So, when implementing Cap'n Proto in a new language, it makes sense to implement only the -# two-party protocol initially, and then pair applications with an appropriate proxy written in -# C++, rather than implement other parameterizations of the RPC protocol directly. - -using Cxx = import "/capnp/c++.capnp"; -$Cxx.namespace("capnp::rpc::twoparty"); - -# Note: SturdyRef is not specified here. It is up to the application to define semantics of -# SturdyRefs if desired. - -enum Side { - server @0; - # The object lives on the "server" or "supervisor" end of the connection. Only the - # server/supervisor knows how to interpret the ref; to the client, it is opaque. - # - # Note that containers intending to implement strong confinement should rewrite SturdyRefs - # received from the external network before passing them on to the confined app. The confined - # app thus does not ever receive the raw bits of the SturdyRef (which it could perhaps - # maliciously leak), but instead receives only a thing that it can pass back to the container - # later to restore the ref. See: - # http://www.erights.org/elib/capability/dist-confine.html - - client @1; - # The object lives on the "client" or "confined app" end of the connection. Only the client - # knows how to interpret the ref; to the server/supervisor, it is opaque. Most clients do not - # actually know how to persist capabilities at all, so use of this is unusual. -} - -struct VatId { - side @0 :Side; -} - -struct ProvisionId { - # Only used for joins, since three-way introductions never happen on a two-party network. - - joinId @0 :UInt32; - # The ID from `JoinKeyPart`. -} - -struct RecipientId {} -# Never used, because there are only two parties. - -struct ThirdPartyCapId {} -# Never used, because there is no third party. - -struct JoinKeyPart { - # Joins in the two-party case are simplified by a few observations. - # - # First, on a two-party network, a Join only ever makes sense if the receiving end is also - # connected to other networks. A vat which is not connected to any other network can safely - # reject all joins. - # - # Second, since a two-party connection bisects the network -- there can be no other connections - # between the networks at either end of the connection -- if one part of a join crosses the - # connection, then _all_ parts must cross it. Therefore, a vat which is receiving a Join request - # off some other network which needs to be forwarded across the two-party connection can - # collect all the parts on its end and only forward them across the two-party connection when all - # have been received. - # - # For example, imagine that Alice and Bob are vats connected over a two-party connection, and - # each is also connected to other networks. At some point, Alice receives one part of a Join - # request off her network. The request is addressed to a capability that Alice received from - # Bob and is proxying to her other network. Alice goes ahead and responds to the Join part as - # if she hosted the capability locally (this is important so that if not all the Join parts end - # up at Alice, the original sender can detect the failed Join without hanging). As other parts - # trickle in, Alice verifies that each part is addressed to a capability from Bob and continues - # to respond to each one. Once the complete set of join parts is received, Alice checks if they - # were all for the exact same capability. If so, she doesn't need to send anything to Bob at - # all. Otherwise, she collects the set of capabilities (from Bob) to which the join parts were - # addressed and essentially initiates a _new_ Join request on those capabilities to Bob. Alice - # does not forward the Join parts she received herself, but essentially forwards the Join as a - # whole. - # - # On Bob's end, since he knows that Alice will always send all parts of a Join together, he - # simply waits until he's received them all, then performs a join on the respective capabilities - # as if it had been requested locally. - - joinId @0 :UInt32; - # A number identifying this join, chosen by the sender. May be reused once `Finish` messages are - # sent corresponding to all of the `Join` messages. - - partCount @1 :UInt16; - # The number of capabilities to be joined. - - partNum @2 :UInt16; - # Which part this request targets -- a number in the range [0, partCount). -} - -struct JoinResult { - joinId @0 :UInt32; - # Matches `JoinKeyPart`. - - succeeded @1 :Bool; - # All JoinResults in the set will have the same value for `succeeded`. The receiver actually - # implements the join by waiting for all the `JoinKeyParts` and then performing its own join on - # them, then going back and answering all the join requests afterwards. - - cap @2 :AnyPointer; - # One of the JoinResults will have a non-null `cap` which is the joined capability. - # - # TODO(cleanup): Change `AnyPointer` to `Capability` when that is supported. -} +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xa184c7885cdaf2a1; +# This file defines the "network-specific parameters" in rpc.capnp to support a network consisting +# of two vats. Each of these vats may in fact be in communication with other vats, but any +# capabilities they forward must be proxied. Thus, to each end of the connection, all capabilities +# received from the other end appear to live in a single vat. +# +# Two notable use cases for this model include: +# - Regular client-server communications, where a remote client machine (perhaps living on an end +# user's personal device) connects to a server. The server may be part of a cluster, and may +# call on other servers in the cluster to help service the user's request. It may even obtain +# capabilities from these other servers which it passes on to the user. To simplify network +# common traversal problems (e.g. if the user is behind a firewall), it is probably desirable to +# multiplex all communications between the server cluster and the client over the original +# connection rather than form new ones. This connection should use the two-party protocol, as +# the client has no interest in knowing about additional servers. +# - Applications running in a sandbox. A supervisor process may execute a confined application +# such that all of the confined app's communications with the outside world must pass through +# the supervisor. In this case, the connection between the confined app and the supervisor might +# as well use the two-party protocol, because the confined app is intentionally prevented from +# talking to any other vat anyway. Any external resources will be proxied through the supervisor, +# and so to the contained app will appear as if they were hosted by the supervisor itself. +# +# Since there are only two vats in this network, there is never a need for three-way introductions, +# so level 3 is free. Moreover, because it is never necessary to form new connections, the +# two-party protocol can be used easily anywhere where a two-way byte stream exists, without regard +# to where that byte stream goes or how it was initiated. This makes the two-party runtime library +# highly reusable. +# +# Joins (level 4) _could_ be needed in cases where one or both vats are participating in other +# networks that use joins. For instance, if Alice and Bob are speaking through the two-party +# protocol, and Bob is also participating on another network, Bob may send Alice two or more +# proxied capabilities which, unbeknownst to Bob at the time, are in fact pointing at the same +# remote object. Alice may then request to join these capabilities, at which point Bob will have +# to forward the join to the other network. Note, however, that if Alice is _not_ participating on +# any other network, then Alice will never need to _receive_ a Join, because Alice would always +# know when two locally-hosted capabilities are the same and would never export a redundant alias +# to Bob. So, Alice can respond to all incoming joins with an error, and only needs to implement +# outgoing joins if she herself desires to use this feature. Also, outgoing joins are relatively +# easy to implement in this scenario. +# +# What all this means is that a level 4 implementation of the confined network is barely more +# complicated than a level 2 implementation. However, such an implementation allows the "client" +# or "confined" app to access the server's/supervisor's network with equal functionality to any +# native participant. In other words, an application which implements only the two-party protocol +# can be paired with a proxy app in order to participate in any network. +# +# So, when implementing Cap'n Proto in a new language, it makes sense to implement only the +# two-party protocol initially, and then pair applications with an appropriate proxy written in +# C++, rather than implement other parameterizations of the RPC protocol directly. + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("capnp::rpc::twoparty"); + +# Note: SturdyRef is not specified here. It is up to the application to define semantics of +# SturdyRefs if desired. + +enum Side { + server @0; + # The object lives on the "server" or "supervisor" end of the connection. Only the + # server/supervisor knows how to interpret the ref; to the client, it is opaque. + # + # Note that containers intending to implement strong confinement should rewrite SturdyRefs + # received from the external network before passing them on to the confined app. The confined + # app thus does not ever receive the raw bits of the SturdyRef (which it could perhaps + # maliciously leak), but instead receives only a thing that it can pass back to the container + # later to restore the ref. See: + # http://www.erights.org/elib/capability/dist-confine.html + + client @1; + # The object lives on the "client" or "confined app" end of the connection. Only the client + # knows how to interpret the ref; to the server/supervisor, it is opaque. Most clients do not + # actually know how to persist capabilities at all, so use of this is unusual. +} + +struct VatId { + side @0 :Side; +} + +struct ProvisionId { + # Only used for joins, since three-way introductions never happen on a two-party network. + + joinId @0 :UInt32; + # The ID from `JoinKeyPart`. +} + +struct RecipientId {} +# Never used, because there are only two parties. + +struct ThirdPartyCapId {} +# Never used, because there is no third party. + +struct JoinKeyPart { + # Joins in the two-party case are simplified by a few observations. + # + # First, on a two-party network, a Join only ever makes sense if the receiving end is also + # connected to other networks. A vat which is not connected to any other network can safely + # reject all joins. + # + # Second, since a two-party connection bisects the network -- there can be no other connections + # between the networks at either end of the connection -- if one part of a join crosses the + # connection, then _all_ parts must cross it. Therefore, a vat which is receiving a Join request + # off some other network which needs to be forwarded across the two-party connection can + # collect all the parts on its end and only forward them across the two-party connection when all + # have been received. + # + # For example, imagine that Alice and Bob are vats connected over a two-party connection, and + # each is also connected to other networks. At some point, Alice receives one part of a Join + # request off her network. The request is addressed to a capability that Alice received from + # Bob and is proxying to her other network. Alice goes ahead and responds to the Join part as + # if she hosted the capability locally (this is important so that if not all the Join parts end + # up at Alice, the original sender can detect the failed Join without hanging). As other parts + # trickle in, Alice verifies that each part is addressed to a capability from Bob and continues + # to respond to each one. Once the complete set of join parts is received, Alice checks if they + # were all for the exact same capability. If so, she doesn't need to send anything to Bob at + # all. Otherwise, she collects the set of capabilities (from Bob) to which the join parts were + # addressed and essentially initiates a _new_ Join request on those capabilities to Bob. Alice + # does not forward the Join parts she received herself, but essentially forwards the Join as a + # whole. + # + # On Bob's end, since he knows that Alice will always send all parts of a Join together, he + # simply waits until he's received them all, then performs a join on the respective capabilities + # as if it had been requested locally. + + joinId @0 :UInt32; + # A number identifying this join, chosen by the sender. May be reused once `Finish` messages are + # sent corresponding to all of the `Join` messages. + + partCount @1 :UInt16; + # The number of capabilities to be joined. + + partNum @2 :UInt16; + # Which part this request targets -- a number in the range [0, partCount). +} + +struct JoinResult { + joinId @0 :UInt32; + # Matches `JoinKeyPart`. + + succeeded @1 :Bool; + # All JoinResults in the set will have the same value for `succeeded`. The receiver actually + # implements the join by waiting for all the `JoinKeyParts` and then performing its own join on + # them, then going back and answering all the join requests afterwards. + + cap @2 :AnyPointer; + # One of the JoinResults will have a non-null `cap` which is the joined capability. + # + # TODO(cleanup): Change `AnyPointer` to `Capability` when that is supported. +} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc-twoparty.capnp.h --- a/osx/include/capnp/rpc-twoparty.capnp.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc-twoparty.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -1,724 +1,726 @@ -// Generated by Cap'n Proto compiler, DO NOT EDIT -// source: rpc-twoparty.capnp - -#ifndef CAPNP_INCLUDED_a184c7885cdaf2a1_ -#define CAPNP_INCLUDED_a184c7885cdaf2a1_ - -#include - -#if CAPNP_VERSION != 6000 -#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." -#endif - - -namespace capnp { -namespace schemas { - -CAPNP_DECLARE_SCHEMA(9fd69ebc87b9719c); -enum class Side_9fd69ebc87b9719c: uint16_t { - SERVER, - CLIENT, -}; -CAPNP_DECLARE_ENUM(Side, 9fd69ebc87b9719c); -CAPNP_DECLARE_SCHEMA(d20b909fee733a8e); -CAPNP_DECLARE_SCHEMA(b88d09a9c5f39817); -CAPNP_DECLARE_SCHEMA(89f389b6fd4082c1); -CAPNP_DECLARE_SCHEMA(b47f4979672cb59d); -CAPNP_DECLARE_SCHEMA(95b29059097fca83); -CAPNP_DECLARE_SCHEMA(9d263a3630b7ebee); - -} // namespace schemas -} // namespace capnp - -namespace capnp { -namespace rpc { -namespace twoparty { - -typedef ::capnp::schemas::Side_9fd69ebc87b9719c Side; - -struct VatId { - VatId() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d20b909fee733a8e, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct ProvisionId { - ProvisionId() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b88d09a9c5f39817, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct RecipientId { - RecipientId() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(89f389b6fd4082c1, 0, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct ThirdPartyCapId { - ThirdPartyCapId() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b47f4979672cb59d, 0, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct JoinKeyPart { - JoinKeyPart() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(95b29059097fca83, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct JoinResult { - JoinResult() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9d263a3630b7ebee, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -// ======================================================================================= - -class VatId::Reader { -public: - typedef VatId Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::capnp::rpc::twoparty::Side getSide() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class VatId::Builder { -public: - typedef VatId Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::capnp::rpc::twoparty::Side getSide(); - inline void setSide( ::capnp::rpc::twoparty::Side value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class VatId::Pipeline { -public: - typedef VatId Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class ProvisionId::Reader { -public: - typedef ProvisionId Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class ProvisionId::Builder { -public: - typedef ProvisionId Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId(); - inline void setJoinId( ::uint32_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class ProvisionId::Pipeline { -public: - typedef ProvisionId Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class RecipientId::Reader { -public: - typedef RecipientId Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class RecipientId::Builder { -public: - typedef RecipientId Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class RecipientId::Pipeline { -public: - typedef RecipientId Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class ThirdPartyCapId::Reader { -public: - typedef ThirdPartyCapId Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class ThirdPartyCapId::Builder { -public: - typedef ThirdPartyCapId Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class ThirdPartyCapId::Pipeline { -public: - typedef ThirdPartyCapId Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class JoinKeyPart::Reader { -public: - typedef JoinKeyPart Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId() const; - - inline ::uint16_t getPartCount() const; - - inline ::uint16_t getPartNum() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class JoinKeyPart::Builder { -public: - typedef JoinKeyPart Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId(); - inline void setJoinId( ::uint32_t value); - - inline ::uint16_t getPartCount(); - inline void setPartCount( ::uint16_t value); - - inline ::uint16_t getPartNum(); - inline void setPartNum( ::uint16_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class JoinKeyPart::Pipeline { -public: - typedef JoinKeyPart Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class JoinResult::Reader { -public: - typedef JoinResult Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId() const; - - inline bool getSucceeded() const; - - inline bool hasCap() const; - inline ::capnp::AnyPointer::Reader getCap() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class JoinResult::Builder { -public: - typedef JoinResult Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getJoinId(); - inline void setJoinId( ::uint32_t value); - - inline bool getSucceeded(); - inline void setSucceeded(bool value); - - inline bool hasCap(); - inline ::capnp::AnyPointer::Builder getCap(); - inline ::capnp::AnyPointer::Builder initCap(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class JoinResult::Pipeline { -public: - typedef JoinResult Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -// ======================================================================================= - -inline ::capnp::rpc::twoparty::Side VatId::Reader::getSide() const { - return _reader.getDataField< ::capnp::rpc::twoparty::Side>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::rpc::twoparty::Side VatId::Builder::getSide() { - return _builder.getDataField< ::capnp::rpc::twoparty::Side>( - 0 * ::capnp::ELEMENTS); -} -inline void VatId::Builder::setSide( ::capnp::rpc::twoparty::Side value) { - _builder.setDataField< ::capnp::rpc::twoparty::Side>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t ProvisionId::Reader::getJoinId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t ProvisionId::Builder::getJoinId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void ProvisionId::Builder::setJoinId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t JoinKeyPart::Reader::getJoinId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t JoinKeyPart::Builder::getJoinId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void JoinKeyPart::Builder::setJoinId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t JoinKeyPart::Reader::getPartCount() const { - return _reader.getDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint16_t JoinKeyPart::Builder::getPartCount() { - return _builder.getDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS); -} -inline void JoinKeyPart::Builder::setPartCount( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t JoinKeyPart::Reader::getPartNum() const { - return _reader.getDataField< ::uint16_t>( - 3 * ::capnp::ELEMENTS); -} - -inline ::uint16_t JoinKeyPart::Builder::getPartNum() { - return _builder.getDataField< ::uint16_t>( - 3 * ::capnp::ELEMENTS); -} -inline void JoinKeyPart::Builder::setPartNum( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 3 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t JoinResult::Reader::getJoinId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t JoinResult::Builder::getJoinId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void JoinResult::Builder::setJoinId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool JoinResult::Reader::getSucceeded() const { - return _reader.getDataField( - 32 * ::capnp::ELEMENTS); -} - -inline bool JoinResult::Builder::getSucceeded() { - return _builder.getDataField( - 32 * ::capnp::ELEMENTS); -} -inline void JoinResult::Builder::setSucceeded(bool value) { - _builder.setDataField( - 32 * ::capnp::ELEMENTS, value); -} - -inline bool JoinResult::Reader::hasCap() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool JoinResult::Builder::hasCap() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader JoinResult::Reader::getCap() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder JoinResult::Builder::getCap() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder JoinResult::Builder::initCap() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -} // namespace -} // namespace -} // namespace - -#endif // CAPNP_INCLUDED_a184c7885cdaf2a1_ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc-twoparty.capnp + +#ifndef CAPNP_INCLUDED_a184c7885cdaf2a1_ +#define CAPNP_INCLUDED_a184c7885cdaf2a1_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(9fd69ebc87b9719c); +enum class Side_9fd69ebc87b9719c: uint16_t { + SERVER, + CLIENT, +}; +CAPNP_DECLARE_ENUM(Side, 9fd69ebc87b9719c); +CAPNP_DECLARE_SCHEMA(d20b909fee733a8e); +CAPNP_DECLARE_SCHEMA(b88d09a9c5f39817); +CAPNP_DECLARE_SCHEMA(89f389b6fd4082c1); +CAPNP_DECLARE_SCHEMA(b47f4979672cb59d); +CAPNP_DECLARE_SCHEMA(95b29059097fca83); +CAPNP_DECLARE_SCHEMA(9d263a3630b7ebee); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace rpc { +namespace twoparty { + +typedef ::capnp::schemas::Side_9fd69ebc87b9719c Side; + +struct VatId { + VatId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d20b909fee733a8e, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ProvisionId { + ProvisionId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b88d09a9c5f39817, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct RecipientId { + RecipientId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(89f389b6fd4082c1, 0, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ThirdPartyCapId { + ThirdPartyCapId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b47f4979672cb59d, 0, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JoinKeyPart { + JoinKeyPart() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(95b29059097fca83, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JoinResult { + JoinResult() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9d263a3630b7ebee, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class VatId::Reader { +public: + typedef VatId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::capnp::rpc::twoparty::Side getSide() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class VatId::Builder { +public: + typedef VatId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::capnp::rpc::twoparty::Side getSide(); + inline void setSide( ::capnp::rpc::twoparty::Side value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class VatId::Pipeline { +public: + typedef VatId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ProvisionId::Reader { +public: + typedef ProvisionId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ProvisionId::Builder { +public: + typedef ProvisionId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ProvisionId::Pipeline { +public: + typedef ProvisionId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class RecipientId::Reader { +public: + typedef RecipientId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class RecipientId::Builder { +public: + typedef RecipientId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class RecipientId::Pipeline { +public: + typedef RecipientId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ThirdPartyCapId::Reader { +public: + typedef ThirdPartyCapId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ThirdPartyCapId::Builder { +public: + typedef ThirdPartyCapId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ThirdPartyCapId::Pipeline { +public: + typedef ThirdPartyCapId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JoinKeyPart::Reader { +public: + typedef JoinKeyPart Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + + inline ::uint16_t getPartCount() const; + + inline ::uint16_t getPartNum() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JoinKeyPart::Builder { +public: + typedef JoinKeyPart Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + + inline ::uint16_t getPartCount(); + inline void setPartCount( ::uint16_t value); + + inline ::uint16_t getPartNum(); + inline void setPartNum( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JoinKeyPart::Pipeline { +public: + typedef JoinKeyPart Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JoinResult::Reader { +public: + typedef JoinResult Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + + inline bool getSucceeded() const; + + inline bool hasCap() const; + inline ::capnp::AnyPointer::Reader getCap() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JoinResult::Builder { +public: + typedef JoinResult Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + + inline bool getSucceeded(); + inline void setSucceeded(bool value); + + inline bool hasCap(); + inline ::capnp::AnyPointer::Builder getCap(); + inline ::capnp::AnyPointer::Builder initCap(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JoinResult::Pipeline { +public: + typedef JoinResult Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::rpc::twoparty::Side VatId::Reader::getSide() const { + return _reader.getDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::rpc::twoparty::Side VatId::Builder::getSide() { + return _builder.getDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void VatId::Builder::setSide( ::capnp::rpc::twoparty::Side value) { + _builder.setDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t ProvisionId::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t ProvisionId::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void ProvisionId::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t JoinKeyPart::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t JoinKeyPart::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t JoinKeyPart::Reader::getPartCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t JoinKeyPart::Builder::getPartCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setPartCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t JoinKeyPart::Reader::getPartNum() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t JoinKeyPart::Builder::getPartNum() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setPartNum( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t JoinResult::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t JoinResult::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JoinResult::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool JoinResult::Reader::getSucceeded() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} + +inline bool JoinResult::Builder::getSucceeded() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} +inline void JoinResult::Builder::setSucceeded(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value); +} + +inline bool JoinResult::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JoinResult::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader JoinResult::Reader::getCap() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder JoinResult::Builder::getCap() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder JoinResult::Builder::initCap() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +} // namespace +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_a184c7885cdaf2a1_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc-twoparty.h --- a/osx/include/capnp/rpc-twoparty.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc-twoparty.h Mon May 22 10:01:37 2017 +0100 @@ -1,160 +1,160 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_RPC_TWOPARTY_H_ -#define CAPNP_RPC_TWOPARTY_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "rpc.h" -#include "message.h" -#include -#include - -namespace capnp { - -namespace rpc { - namespace twoparty { - typedef VatId SturdyRefHostId; // For backwards-compatibility with version 0.4. - } -} - -typedef VatNetwork - TwoPartyVatNetworkBase; - -class TwoPartyVatNetwork: public TwoPartyVatNetworkBase, - private TwoPartyVatNetworkBase::Connection { - // A `VatNetwork` that consists of exactly two parties communicating over an arbitrary byte - // stream. This is used to implement the common case of a client/server network. - // - // See `ez-rpc.h` for a simple interface for setting up two-party clients and servers. - // Use `TwoPartyVatNetwork` only if you need the advanced features. - -public: - TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side, - ReaderOptions receiveOptions = ReaderOptions()); - KJ_DISALLOW_COPY(TwoPartyVatNetwork); - - kj::Promise onDisconnect() { return disconnectPromise.addBranch(); } - // Returns a promise that resolves when the peer disconnects. - - rpc::twoparty::Side getSide() { return side; } - - // implements VatNetwork ----------------------------------------------------- - - kj::Maybe> connect( - rpc::twoparty::VatId::Reader ref) override; - kj::Promise> accept() override; - -private: - class OutgoingMessageImpl; - class IncomingMessageImpl; - - kj::AsyncIoStream& stream; - rpc::twoparty::Side side; - MallocMessageBuilder peerVatId; - ReaderOptions receiveOptions; - bool accepted = false; - - kj::Maybe> previousWrite; - // Resolves when the previous write completes. This effectively serves as the write queue. - // Becomes null when shutdown() is called. - - kj::Own>> acceptFulfiller; - // Fulfiller for the promise returned by acceptConnectionAsRefHost() on the client side, or the - // second call on the server side. Never fulfilled, because there is only one connection. - - kj::ForkedPromise disconnectPromise = nullptr; - - class FulfillerDisposer: public kj::Disposer { - // Hack: TwoPartyVatNetwork is both a VatNetwork and a VatNetwork::Connection. When the RPC - // system detects (or initiates) a disconnection, it drops its reference to the Connection. - // When all references have been dropped, then we want disconnectPromise to be fulfilled. - // So we hand out Owns with this disposer attached, so that we can detect when - // they are dropped. - - public: - mutable kj::Own> fulfiller; - mutable uint refcount = 0; - - void disposeImpl(void* pointer) const override; - }; - FulfillerDisposer disconnectFulfiller; - - kj::Own asConnection(); - // Returns a pointer to this with the disposer set to disconnectFulfiller. - - // implements Connection ----------------------------------------------------- - - rpc::twoparty::VatId::Reader getPeerVatId() override; - kj::Own newOutgoingMessage(uint firstSegmentWordSize) override; - kj::Promise>> receiveIncomingMessage() override; - kj::Promise shutdown() override; -}; - -class TwoPartyServer: private kj::TaskSet::ErrorHandler { - // Convenience class which implements a simple server which accepts connections on a listener - // socket and serices them as two-party connections. - -public: - explicit TwoPartyServer(Capability::Client bootstrapInterface); - - void accept(kj::Own&& connection); - // Accepts the connection for servicing. - - kj::Promise listen(kj::ConnectionReceiver& listener); - // Listens for connections on the given listener. The returned promise never resolves unless an - // exception is thrown while trying to accept. You may discard the returned promise to cancel - // listening. - -private: - Capability::Client bootstrapInterface; - kj::TaskSet tasks; - - struct AcceptedConnection; - - void taskFailed(kj::Exception&& exception) override; -}; - -class TwoPartyClient { - // Convenience class which implements a simple client. - -public: - explicit TwoPartyClient(kj::AsyncIoStream& connection); - TwoPartyClient(kj::AsyncIoStream& connection, Capability::Client bootstrapInterface, - rpc::twoparty::Side side = rpc::twoparty::Side::CLIENT); - - Capability::Client bootstrap(); - // Get the server's bootstrap interface. - - inline kj::Promise onDisconnect() { return network.onDisconnect(); } - -private: - TwoPartyVatNetwork network; - RpcSystem rpcSystem; -}; - -} // namespace capnp - -#endif // CAPNP_RPC_TWOPARTY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RPC_TWOPARTY_H_ +#define CAPNP_RPC_TWOPARTY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "rpc.h" +#include "message.h" +#include +#include + +namespace capnp { + +namespace rpc { + namespace twoparty { + typedef VatId SturdyRefHostId; // For backwards-compatibility with version 0.4. + } +} + +typedef VatNetwork + TwoPartyVatNetworkBase; + +class TwoPartyVatNetwork: public TwoPartyVatNetworkBase, + private TwoPartyVatNetworkBase::Connection { + // A `VatNetwork` that consists of exactly two parties communicating over an arbitrary byte + // stream. This is used to implement the common case of a client/server network. + // + // See `ez-rpc.h` for a simple interface for setting up two-party clients and servers. + // Use `TwoPartyVatNetwork` only if you need the advanced features. + +public: + TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side, + ReaderOptions receiveOptions = ReaderOptions()); + KJ_DISALLOW_COPY(TwoPartyVatNetwork); + + kj::Promise onDisconnect() { return disconnectPromise.addBranch(); } + // Returns a promise that resolves when the peer disconnects. + + rpc::twoparty::Side getSide() { return side; } + + // implements VatNetwork ----------------------------------------------------- + + kj::Maybe> connect( + rpc::twoparty::VatId::Reader ref) override; + kj::Promise> accept() override; + +private: + class OutgoingMessageImpl; + class IncomingMessageImpl; + + kj::AsyncIoStream& stream; + rpc::twoparty::Side side; + MallocMessageBuilder peerVatId; + ReaderOptions receiveOptions; + bool accepted = false; + + kj::Maybe> previousWrite; + // Resolves when the previous write completes. This effectively serves as the write queue. + // Becomes null when shutdown() is called. + + kj::Own>> acceptFulfiller; + // Fulfiller for the promise returned by acceptConnectionAsRefHost() on the client side, or the + // second call on the server side. Never fulfilled, because there is only one connection. + + kj::ForkedPromise disconnectPromise = nullptr; + + class FulfillerDisposer: public kj::Disposer { + // Hack: TwoPartyVatNetwork is both a VatNetwork and a VatNetwork::Connection. When the RPC + // system detects (or initiates) a disconnection, it drops its reference to the Connection. + // When all references have been dropped, then we want disconnectPromise to be fulfilled. + // So we hand out Owns with this disposer attached, so that we can detect when + // they are dropped. + + public: + mutable kj::Own> fulfiller; + mutable uint refcount = 0; + + void disposeImpl(void* pointer) const override; + }; + FulfillerDisposer disconnectFulfiller; + + kj::Own asConnection(); + // Returns a pointer to this with the disposer set to disconnectFulfiller. + + // implements Connection ----------------------------------------------------- + + rpc::twoparty::VatId::Reader getPeerVatId() override; + kj::Own newOutgoingMessage(uint firstSegmentWordSize) override; + kj::Promise>> receiveIncomingMessage() override; + kj::Promise shutdown() override; +}; + +class TwoPartyServer: private kj::TaskSet::ErrorHandler { + // Convenience class which implements a simple server which accepts connections on a listener + // socket and serices them as two-party connections. + +public: + explicit TwoPartyServer(Capability::Client bootstrapInterface); + + void accept(kj::Own&& connection); + // Accepts the connection for servicing. + + kj::Promise listen(kj::ConnectionReceiver& listener); + // Listens for connections on the given listener. The returned promise never resolves unless an + // exception is thrown while trying to accept. You may discard the returned promise to cancel + // listening. + +private: + Capability::Client bootstrapInterface; + kj::TaskSet tasks; + + struct AcceptedConnection; + + void taskFailed(kj::Exception&& exception) override; +}; + +class TwoPartyClient { + // Convenience class which implements a simple client. + +public: + explicit TwoPartyClient(kj::AsyncIoStream& connection); + TwoPartyClient(kj::AsyncIoStream& connection, Capability::Client bootstrapInterface, + rpc::twoparty::Side side = rpc::twoparty::Side::CLIENT); + + Capability::Client bootstrap(); + // Get the server's bootstrap interface. + + inline kj::Promise onDisconnect() { return network.onDisconnect(); } + +private: + TwoPartyVatNetwork network; + RpcSystem rpcSystem; +}; + +} // namespace capnp + +#endif // CAPNP_RPC_TWOPARTY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc.capnp --- a/osx/include/capnp/rpc.capnp Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc.capnp Mon May 22 10:01:37 2017 +0100 @@ -1,1399 +1,1399 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xb312981b2552a250; -# Recall that Cap'n Proto RPC allows messages to contain references to remote objects that -# implement interfaces. These references are called "capabilities", because they both designate -# the remote object to use and confer permission to use it. -# -# Recall also that Cap'n Proto RPC has the feature that when a method call itself returns a -# capability, the caller can begin calling methods on that capability _before the first call has -# returned_. The caller essentially sends a message saying "Hey server, as soon as you finish -# that previous call, do this with the result!". Cap'n Proto's RPC protocol makes this possible. -# -# The protocol is significantly more complicated than most RPC protocols. However, this is -# implementation complexity that underlies an easy-to-grasp higher-level model of object oriented -# programming. That is, just like TCP is a surprisingly complicated protocol that implements a -# conceptually-simple byte stream abstraction, Cap'n Proto is a surprisingly complicated protocol -# that implements a conceptually-simple object abstraction. -# -# Cap'n Proto RPC is based heavily on CapTP, the object-capability protocol used by the E -# programming language: -# http://www.erights.org/elib/distrib/captp/index.html -# -# Cap'n Proto RPC takes place between "vats". A vat hosts some set of objects and talks to other -# vats through direct bilateral connections. Typically, there is a 1:1 correspondence between vats -# and processes (in the unix sense of the word), although this is not strictly always true (one -# process could run multiple vats, or a distributed virtual vat might live across many processes). -# -# Cap'n Proto does not distinguish between "clients" and "servers" -- this is up to the application. -# Either end of any connection can potentially hold capabilities pointing to the other end, and -# can call methods on those capabilities. In the doc comments below, we use the words "sender" -# and "receiver". These refer to the sender and receiver of an instance of the struct or field -# being documented. Sometimes we refer to a "third-party" that is neither the sender nor the -# receiver. Documentation is generally written from the point of view of the sender. -# -# It is generally up to the vat network implementation to securely verify that connections are made -# to the intended vat as well as to encrypt transmitted data for privacy and integrity. See the -# `VatNetwork` example interface near the end of this file. -# -# When a new connection is formed, the only interesting things that can be done are to send a -# `Bootstrap` (level 0) or `Accept` (level 3) message. -# -# Unless otherwise specified, messages must be delivered to the receiving application in the same -# order in which they were initiated by the sending application. The goal is to support "E-Order", -# which states that two calls made on the same reference must be delivered in the order which they -# were made: -# http://erights.org/elib/concurrency/partial-order.html -# -# Since the full protocol is complicated, we define multiple levels of support that an -# implementation may target. For many applications, level 1 support will be sufficient. -# Comments in this file indicate which level requires the corresponding feature to be -# implemented. -# -# * **Level 0:** The implementation does not support object references. Only the bootstrap interface -# can be called. At this level, the implementation does not support object-oriented protocols and -# is similar in complexity to JSON-RPC or Protobuf services. This level should be considered only -# a temporary stepping-stone toward level 1 as the lack of object references drastically changes -# how protocols are designed. Applications _should not_ attempt to design their protocols around -# the limitations of level 0 implementations. -# -# * **Level 1:** The implementation supports simple bilateral interaction with object references -# and promise pipelining, but interactions between three or more parties are supported only via -# proxying of objects. E.g. if Alice (in Vat A) wants to send Bob (in Vat B) a capability -# pointing to Carol (in Vat C), Alice must create a proxy of Carol within Vat A and send Bob a -# reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do -# not support checking if two capabilities received from different vats actually point to the -# same object ("join"), although they should be able to do this check on capabilities received -# from the same vat. -# -# * **Level 2:** The implementation supports saving persistent capabilities -- i.e. capabilities -# that remain valid even after disconnect, and can be restored on a future connection. When a -# capability is saved, the requester receives a `SturdyRef`, which is a token that can be used -# to restore the capability later. -# -# * **Level 3:** The implementation supports three-way interactions. That is, if Alice (in Vat A) -# sends Bob (in Vat B) a capability pointing to Carol (in Vat C), then Vat B will automatically -# form a direct connection to Vat C rather than have requests be proxied through Vat A. -# -# * **Level 4:** The entire protocol is implemented, including joins (checking if two capabilities -# are equivalent). -# -# Note that an implementation must also support specific networks (transports), as described in -# the "Network-specific Parameters" section below. An implementation might have different levels -# depending on the network used. -# -# New implementations of Cap'n Proto should start out targeting the simplistic two-party network -# type as defined in `rpc-twoparty.capnp`. With this network type, level 3 is irrelevant and -# levels 2 and 4 are much easier than usual to implement. When such an implementation is paired -# with a container proxy, the contained app effectively gets to make full use of the proxy's -# network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to -# bother implementing any other vat network protocol -- just use the correct container type and get -# it for free. - -using Cxx = import "/capnp/c++.capnp"; -$Cxx.namespace("capnp::rpc"); - -# ======================================================================================== -# The Four Tables -# -# Cap'n Proto RPC connections are stateful (although an application built on Cap'n Proto could -# export a stateless interface). As in CapTP, for each open connection, a vat maintains four state -# tables: questions, answers, imports, and exports. See the diagram at: -# http://www.erights.org/elib/distrib/captp/4tables.html -# -# The question table corresponds to the other end's answer table, and the imports table corresponds -# to the other end's exports table. -# -# The entries in each table are identified by ID numbers (defined below as 32-bit integers). These -# numbers are always specific to the connection; a newly-established connection starts with no -# valid IDs. Since low-numbered IDs will pack better, it is suggested that IDs be assigned like -# Unix file descriptors -- prefer the lowest-number ID that is currently available. -# -# IDs in the questions/answers tables are chosen by the questioner and generally represent method -# calls that are in progress. -# -# IDs in the imports/exports tables are chosen by the exporter and generally represent objects on -# which methods may be called. Exports may be "settled", meaning the exported object is an actual -# object living in the exporter's vat, or they may be "promises", meaning the exported object is -# the as-yet-unknown result of an ongoing operation and will eventually be resolved to some other -# object once that operation completes. Calls made to a promise will be forwarded to the eventual -# target once it is known. The eventual replacement object does *not* get the same ID as the -# promise, as it may turn out to be an object that is already exported (so already has an ID) or -# may even live in a completely different vat (and so won't get an ID on the same export table -# at all). -# -# IDs can be reused over time. To make this safe, we carefully define the lifetime of IDs. Since -# messages using the ID could be traveling in both directions simultaneously, we must define the -# end of life of each ID _in each direction_. The ID is only safe to reuse once it has been -# released by both sides. -# -# When a Cap'n Proto connection is lost, everything on the four tables is lost. All questions are -# canceled and throw exceptions. All imports become broken (all future calls to them throw -# exceptions). All exports and answers are implicitly released. The only things not lost are -# persistent capabilities (`SturdyRef`s). The application must plan for this and should respond by -# establishing a new connection and restoring from these persistent capabilities. - -using QuestionId = UInt32; -# **(level 0)** -# -# Identifies a question in the sender's question table (which corresponds to the receiver's answer -# table). The questioner (caller) chooses an ID when making a call. The ID remains valid in -# caller -> callee messages until a Finish message is sent, and remains valid in callee -> caller -# messages until a Return message is sent. - -using AnswerId = QuestionId; -# **(level 0)** -# -# Identifies an answer in the sender's answer table (which corresponds to the receiver's question -# table). -# -# AnswerId is physically equivalent to QuestionId, since the question and answer tables correspond, -# but we define a separate type for documentation purposes: we always use the type representing -# the sender's point of view. - -using ExportId = UInt32; -# **(level 1)** -# -# Identifies an exported capability or promise in the sender's export table (which corresponds -# to the receiver's import table). The exporter chooses an ID before sending a capability over the -# wire. If the capability is already in the table, the exporter should reuse the same ID. If the -# ID is a promise (as opposed to a settled capability), this must be indicated at the time the ID -# is introduced (e.g. by using `senderPromise` instead of `senderHosted` in `CapDescriptor`); in -# this case, the importer shall expect a later `Resolve` message that replaces the promise. -# -# ExportId/ImportIds are subject to reference counting. Whenever an `ExportId` is sent over the -# wire (from the exporter to the importer), the export's reference count is incremented (unless -# otherwise specified). The reference count is later decremented by a `Release` message. Since -# the `Release` message can specify an arbitrary number by which to reduce the reference count, the -# importer should usually batch reference decrements and only send a `Release` when it believes the -# reference count has hit zero. Of course, it is possible that a new reference to the export is -# in-flight at the time that the `Release` message is sent, so it is necessary for the exporter to -# keep track of the reference count on its end as well to avoid race conditions. -# -# When a connection is lost, all exports are implicitly released. It is not possible to restore -# a connection state after disconnect (although a transport layer could implement a concept of -# persistent connections if it is transparent to the RPC layer). - -using ImportId = ExportId; -# **(level 1)** -# -# Identifies an imported capability or promise in the sender's import table (which corresponds to -# the receiver's export table). -# -# ImportId is physically equivalent to ExportId, since the export and import tables correspond, -# but we define a separate type for documentation purposes: we always use the type representing -# the sender's point of view. -# -# An `ImportId` remains valid in importer -> exporter messages until the importer has sent -# `Release` messages that (it believes) have reduced the reference count to zero. - -# ======================================================================================== -# Messages - -struct Message { - # An RPC connection is a bi-directional stream of Messages. - - union { - unimplemented @0 :Message; - # The sender previously received this message from the peer but didn't understand it or doesn't - # yet implement the functionality that was requested. So, the sender is echoing the message - # back. In some cases, the receiver may be able to recover from this by pretending the sender - # had taken some appropriate "null" action. - # - # For example, say `resolve` is received by a level 0 implementation (because a previous call - # or return happened to contain a promise). The level 0 implementation will echo it back as - # `unimplemented`. The original sender can then simply release the cap to which the promise - # had resolved, thus avoiding a leak. - # - # For any message type that introduces a question, if the message comes back unimplemented, - # the original sender may simply treat it as if the question failed with an exception. - # - # In cases where there is no sensible way to react to an `unimplemented` message (without - # resource leaks or other serious problems), the connection may need to be aborted. This is - # a gray area; different implementations may take different approaches. - - abort @1 :Exception; - # Sent when a connection is being aborted due to an unrecoverable error. This could be e.g. - # because the sender received an invalid or nonsensical message (`isCallersFault` is true) or - # because the sender had an internal error (`isCallersFault` is false). The sender will shut - # down the outgoing half of the connection after `abort` and will completely close the - # connection shortly thereafter (it's up to the sender how much of a time buffer they want to - # offer for the client to receive the `abort` before the connection is reset). - - # Level 0 features ----------------------------------------------- - - bootstrap @8 :Bootstrap; # Request the peer's bootstrap interface. - call @2 :Call; # Begin a method call. - return @3 :Return; # Complete a method call. - finish @4 :Finish; # Release a returned answer / cancel a call. - - # Level 1 features ----------------------------------------------- - - resolve @5 :Resolve; # Resolve a previously-sent promise. - release @6 :Release; # Release a capability so that the remote object can be deallocated. - disembargo @13 :Disembargo; # Lift an embargo used to enforce E-order over promise resolution. - - # Level 2 features ----------------------------------------------- - - obsoleteSave @7 :AnyPointer; - # Obsolete request to save a capability, resulting in a SturdyRef. This has been replaced - # by the `Persistent` interface defined in `persistent.capnp`. This operation was never - # implemented. - - obsoleteDelete @9 :AnyPointer; - # Obsolete way to delete a SturdyRef. This operation was never implemented. - - # Level 3 features ----------------------------------------------- - - provide @10 :Provide; # Provide a capability to a third party. - accept @11 :Accept; # Accept a capability provided by a third party. - - # Level 4 features ----------------------------------------------- - - join @12 :Join; # Directly connect to the common root of two or more proxied caps. - } -} - -# Level 0 message types ---------------------------------------------- - -struct Bootstrap { - # **(level 0)** - # - # Get the "bootstrap" interface exported by the remote vat. - # - # For level 0, 1, and 2 implementations, the "bootstrap" interface is simply the main interface - # exported by a vat. If the vat acts as a server fielding connections from clients, then the - # bootstrap interface defines the basic functionality available to a client when it connects. - # The exact interface definition obviously depends on the application. - # - # We call this a "bootstrap" because in an ideal Cap'n Proto world, bootstrap interfaces would - # never be used. In such a world, any time you connect to a new vat, you do so because you - # received an introduction from some other vat (see `ThirdPartyCapId`). Thus, the first message - # you send is `Accept`, and further communications derive from there. `Bootstrap` is not used. - # - # In such an ideal world, DNS itself would support Cap'n Proto -- performing a DNS lookup would - # actually return a new Cap'n Proto capability, thus introducing you to the target system via - # level 3 RPC. Applications would receive the capability to talk to DNS in the first place as - # an initial endowment or part of a Powerbox interaction. Therefore, an app can form arbitrary - # connections without ever using `Bootstrap`. - # - # Of course, in the real world, DNS is not Cap'n-Proto-based, and we don't want Cap'n Proto to - # require a whole new internet infrastructure to be useful. Therefore, we offer bootstrap - # interfaces as a way to get up and running without a level 3 introduction. Thus, bootstrap - # interfaces are used to "bootstrap" from other, non-Cap'n-Proto-based means of service discovery, - # such as legacy DNS. - # - # Note that a vat need not provide a bootstrap interface, and in fact many vats (especially those - # acting as clients) do not. In this case, the vat should either reply to `Bootstrap` with a - # `Return` indicating an exception, or should return a dummy capability with no methods. - - questionId @0 :QuestionId; - # A new question ID identifying this request, which will eventually receive a Return message - # containing the restored capability. - - deprecatedObjectId @1 :AnyPointer; - # ** DEPRECATED ** - # - # A Vat may export multiple bootstrap interfaces. In this case, `deprecatedObjectId` specifies - # which one to return. If this pointer is null, then the default bootstrap interface is returned. - # - # As of verison 0.5, use of this field is deprecated. If a service wants to export multiple - # bootstrap interfaces, it should instead define a single bootstarp interface that has methods - # that return each of the other interfaces. - # - # **History** - # - # In the first version of Cap'n Proto RPC (0.4.x) the `Bootstrap` message was called `Restore`. - # At the time, it was thought that this would eventually serve as the way to restore SturdyRefs - # (level 2). Meanwhile, an application could offer its "main" interface on a well-known - # (non-secret) SturdyRef. - # - # Since level 2 RPC was not implemented at the time, the `Restore` message was in practice only - # used to obtain the main interface. Since most applications had only one main interface that - # they wanted to restore, they tended to designate this with a null `objectId`. - # - # Unfortunately, the earliest version of the EZ RPC interfaces set a precedent of exporting - # multiple main interfaces by allowing them to be exported under string names. In this case, - # `objectId` was a Text value specifying the name. - # - # All of this proved problematic for several reasons: - # - # - The arrangement assumed that a client wishing to restore a SturdyRef would know exactly what - # machine to connect to and would be able to immediately restore a SturdyRef on connection. - # However, in practice, the ability to restore SturdyRefs is itself a capability that may - # require going through an authentication process to obtain. Thus, it makes more sense to - # define a "restorer service" as a full Cap'n Proto interface. If this restorer interface is - # offered as the vat's bootstrap interface, then this is equivalent to the old arrangement. - # - # - Overloading "Restore" for the purpose of obtaining well-known capabilities encouraged the - # practice of exporting singleton services with string names. If singleton services are desired, - # it is better to have one main interface that has methods that can be used to obtain each - # service, in order to get all the usual benefits of schemas and type checking. - # - # - Overloading "Restore" also had a security problem: Often, "main" or "well-known" - # capabilities exported by a vat are in fact not public: they are intended to be accessed only - # by clients who are capable of forming a connection to the vat. This can lead to trouble if - # the client itself has other clients and wishes to foward some `Restore` requests from those - # external clients -- it has to be very careful not to allow through `Restore` requests - # addressing the default capability. - # - # For example, consider the case of a sandboxed Sandstorm application and its supervisor. The - # application exports a default capability to its supervisor that provides access to - # functionality that only the supervisor is supposed to access. Meanwhile, though, applications - # may publish other capabilities that may be persistent, in which case the application needs - # to field `Restore` requests that could come from anywhere. These requests of course have to - # pass through the supervisor, as all communications with the outside world must. But, the - # supervisor has to be careful not to honor an external request addressing the application's - # default capability, since this capability is privileged. Unfortunately, the default - # capability cannot be given an unguessable name, because then the supervisor itself would not - # be able to address it! - # - # As of Cap'n Proto 0.5, `Restore` has been renamed to `Bootstrap` and is no longer planned for - # use in restoring SturdyRefs. - # - # Note that 0.4 also defined a message type called `Delete` that, like `Restore`, addressed a - # SturdyRef, but indicated that the client would not restore the ref again in the future. This - # operation was never implemented, so it was removed entirely. If a "delete" operation is desired, - # it should exist as a method on the same interface that handles restoring SturdyRefs. However, - # the utility of such an operation is questionable. You wouldn't be able to rely on it for - # garbage collection since a client could always disappear permanently without remembering to - # delete all its SturdyRefs, thus leaving them dangling forever. Therefore, it is advisable to - # design systems such that SturdyRefs never represent "owned" pointers. - # - # For example, say a SturdyRef points to an image file hosted on some server. That image file - # should also live inside a collection (a gallery, perhaps) hosted on the same server, owned by - # a user who can delete the image at any time. If the user deletes the image, the SturdyRef - # stops working. On the other hand, if the SturdyRef is discarded, this has no effect on the - # existence of the image in its collection. -} - -struct Call { - # **(level 0)** - # - # Message type initiating a method call on a capability. - - questionId @0 :QuestionId; - # A number, chosen by the caller, that identifies this call in future messages. This number - # must be different from all other calls originating from the same end of the connection (but - # may overlap with question IDs originating from the opposite end). A fine strategy is to use - # sequential question IDs, but the recipient should not assume this. - # - # A question ID can be reused once both: - # - A matching Return has been received from the callee. - # - A matching Finish has been sent from the caller. - - target @1 :MessageTarget; - # The object that should receive this call. - - interfaceId @2 :UInt64; - # The type ID of the interface being called. Each capability may implement multiple interfaces. - - methodId @3 :UInt16; - # The ordinal number of the method to call within the requested interface. - - allowThirdPartyTailCall @8 :Bool = false; - # Indicates whether or not the receiver is allowed to send a `Return` containing - # `acceptFromThirdParty`. Level 3 implementations should set this true. Otherwise, the callee - # will have to proxy the return in the case of a tail call to a third-party vat. - - params @4 :Payload; - # The call parameters. `params.content` is a struct whose fields correspond to the parameters of - # the method. - - sendResultsTo :union { - # Where should the return message be sent? - - caller @5 :Void; - # Send the return message back to the caller (the usual). - - yourself @6 :Void; - # **(level 1)** - # - # Don't actually return the results to the sender. Instead, hold on to them and await - # instructions from the sender regarding what to do with them. In particular, the sender - # may subsequently send a `Return` for some other call (which the receiver had previously made - # to the sender) with `takeFromOtherQuestion` set. The results from this call are then used - # as the results of the other call. - # - # When `yourself` is used, the receiver must still send a `Return` for the call, but sets the - # field `resultsSentElsewhere` in that `Return` rather than including the results. - # - # This feature can be used to implement tail calls in which a call from Vat A to Vat B ends up - # returning the result of a call from Vat B back to Vat A. - # - # In particular, the most common use case for this feature is when Vat A makes a call to a - # promise in Vat B, and then that promise ends up resolving to a capability back in Vat A. - # Vat B must forward all the queued calls on that promise back to Vat A, but can set `yourself` - # in the calls so that the results need not pass back through Vat B. - # - # For example: - # - Alice, in Vat A, call foo() on Bob in Vat B. - # - Alice makes a pipelined call bar() on the promise returned by foo(). - # - Later on, Bob resolves the promise from foo() to point at Carol, who lives in Vat A (next - # to Alice). - # - Vat B dutifully forwards the bar() call to Carol. Let us call this forwarded call bar'(). - # Notice that bar() and bar'() are travelling in opposite directions on the same network - # link. - # - The `Call` for bar'() has `sendResultsTo` set to `yourself`, with the value being the - # question ID originally assigned to the bar() call. - # - Vat A receives bar'() and delivers it to Carol. - # - When bar'() returns, Vat A immediately takes the results and returns them from bar(). - # - Meanwhile, Vat A sends a `Return` for bar'() to Vat B, with `resultsSentElsewhere` set in - # place of results. - # - Vat A sends a `Finish` for that call to Vat B. - # - Vat B receives the `Return` for bar'() and sends a `Return` for bar(), with - # `receivedFromYourself` set in place of the results. - # - Vat B receives the `Finish` for bar() and sends a `Finish` to bar'(). - - thirdParty @7 :RecipientId; - # **(level 3)** - # - # The call's result should be returned to a different vat. The receiver (the callee) expects - # to receive an `Accept` message from the indicated vat, and should return the call's result - # to it, rather than to the sender of the `Call`. - # - # This operates much like `yourself`, above, except that Carol is in a separate Vat C. `Call` - # messages are sent from Vat A -> Vat B and Vat B -> Vat C. A `Return` message is sent from - # Vat B -> Vat A that contains `acceptFromThirdParty` in place of results. When Vat A sends - # an `Accept` to Vat C, it receives back a `Return` containing the call's actual result. Vat C - # also sends a `Return` to Vat B with `resultsSentElsewhere`. - } -} - -struct Return { - # **(level 0)** - # - # Message type sent from callee to caller indicating that the call has completed. - - answerId @0 :AnswerId; - # Equal to the QuestionId of the corresponding `Call` message. - - releaseParamCaps @1 :Bool = true; - # If true, all capabilities that were in the params should be considered released. The sender - # must not send separate `Release` messages for them. Level 0 implementations in particular - # should always set this true. This defaults true because if level 0 implementations forget to - # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget - # to set it to false they'll quickly get errors. - - union { - results @2 :Payload; - # The result. - # - # For regular method calls, `results.content` points to the result struct. - # - # For a `Return` in response to an `Accept`, `results` contains a single capability (rather - # than a struct), and `results.content` is just a capability pointer with index 0. A `Finish` - # is still required in this case. - - exception @3 :Exception; - # Indicates that the call failed and explains why. - - canceled @4 :Void; - # Indicates that the call was canceled due to the caller sending a Finish message - # before the call had completed. - - resultsSentElsewhere @5 :Void; - # This is set when returning from a `Call` that had `sendResultsTo` set to something other - # than `caller`. - - takeFromOtherQuestion @6 :QuestionId; - # The sender has also sent (before this message) a `Call` with the given question ID and with - # `sendResultsTo.yourself` set, and the results of that other call should be used as the - # results here. - - acceptFromThirdParty @7 :ThirdPartyCapId; - # **(level 3)** - # - # The caller should contact a third-party vat to pick up the results. An `Accept` message - # sent to the vat will return the result. This pairs with `Call.sendResultsTo.thirdParty`. - # It should only be used if the corresponding `Call` had `allowThirdPartyTailCall` set. - } -} - -struct Finish { - # **(level 0)** - # - # Message type sent from the caller to the callee to indicate: - # 1) The questionId will no longer be used in any messages sent by the callee (no further - # pipelined requests). - # 2) If the call has not returned yet, the caller no longer cares about the result. If nothing - # else cares about the result either (e.g. there are no other outstanding calls pipelined on - # the result of this one) then the callee may wish to immediately cancel the operation and - # send back a Return message with "canceled" set. However, implementations are not required - # to support premature cancellation -- instead, the implementation may wait until the call - # actually completes and send a normal `Return` message. - # - # TODO(someday): Should we separate (1) and implicitly releasing result capabilities? It would be - # possible and useful to notify the server that it doesn't need to keep around the response to - # service pipeline requests even though the caller still wants to receive it / hasn't yet - # finished processing it. It could also be useful to notify the server that it need not marshal - # the results because the caller doesn't want them anyway, even if the caller is still sending - # pipelined calls, although this seems less useful (just saving some bytes on the wire). - - questionId @0 :QuestionId; - # ID of the call whose result is to be released. - - releaseResultCaps @1 :Bool = true; - # If true, all capabilities that were in the results should be considered released. The sender - # must not send separate `Release` messages for them. Level 0 implementations in particular - # should always set this true. This defaults true because if level 0 implementations forget to - # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget - # set it false they'll quickly get errors. -} - -# Level 1 message types ---------------------------------------------- - -struct Resolve { - # **(level 1)** - # - # Message type sent to indicate that a previously-sent promise has now been resolved to some other - # object (possibly another promise) -- or broken, or canceled. - # - # Keep in mind that it's possible for a `Resolve` to be sent to a level 0 implementation that - # doesn't implement it. For example, a method call or return might contain a capability in the - # payload. Normally this is fine even if the receiver is level 0, because they will implicitly - # release all such capabilities on return / finish. But if the cap happens to be a promise, then - # a follow-up `Resolve` may be sent regardless of this release. The level 0 receiver will reply - # with an `unimplemented` message, and the sender (of the `Resolve`) can respond to this as if the - # receiver had immediately released any capability to which the promise resolved. - # - # When implementing promise resolution, it's important to understand how embargos work and the - # tricky case of the Tribble 4-way race condition. See the comments for the Disembargo message, - # below. - - promiseId @0 :ExportId; - # The ID of the promise to be resolved. - # - # Unlike all other instances of `ExportId` sent from the exporter, the `Resolve` message does - # _not_ increase the reference count of `promiseId`. In fact, it is expected that the receiver - # will release the export soon after receiving `Resolve`, and the sender will not send this - # `ExportId` again until it has been released and recycled. - # - # When an export ID sent over the wire (e.g. in a `CapDescriptor`) is indicated to be a promise, - # this indicates that the sender will follow up at some point with a `Resolve` message. If the - # same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the - # same ID is sent again later _after_ a `Resolve`, it can only be because the export's - # reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore - # this later promise does _not_ correspond to the earlier `Resolve`. - # - # If a promise ID's reference count reaches zero before a `Resolve` is sent, the `Resolve` - # message may or may not still be sent (the `Resolve` may have already been in-flight when - # `Release` was sent, but if the `Release` is received before `Resolve` then there is no longer - # any reason to send a `Resolve`). Thus a `Resolve` may be received for a promise of which - # the receiver has no knowledge, because it already released it earlier. In this case, the - # receiver should simply release the capability to which the promise resolved. - - union { - cap @1 :CapDescriptor; - # The object to which the promise resolved. - # - # The sender promises that from this point forth, until `promiseId` is released, it shall - # simply forward all messages to the capability designated by `cap`. This is true even if - # `cap` itself happens to desigate another promise, and that other promise later resolves -- - # messages sent to `promiseId` shall still go to that other promise, not to its resolution. - # This is important in the case that the receiver of the `Resolve` ends up sending a - # `Disembargo` message towards `promiseId` in order to control message ordering -- that - # `Disembargo` really needs to reflect back to exactly the object designated by `cap` even - # if that object is itself a promise. - - exception @2 :Exception; - # Indicates that the promise was broken. - } -} - -struct Release { - # **(level 1)** - # - # Message type sent to indicate that the sender is done with the given capability and the receiver - # can free resources allocated to it. - - id @0 :ImportId; - # What to release. - - referenceCount @1 :UInt32; - # The amount by which to decrement the reference count. The export is only actually released - # when the reference count reaches zero. -} - -struct Disembargo { - # **(level 1)** - # - # Message sent to indicate that an embargo on a recently-resolved promise may now be lifted. - # - # Embargos are used to enforce E-order in the presence of promise resolution. That is, if an - # application makes two calls foo() and bar() on the same capability reference, in that order, - # the calls should be delivered in the order in which they were made. But if foo() is called - # on a promise, and that promise happens to resolve before bar() is called, then the two calls - # may travel different paths over the network, and thus could arrive in the wrong order. In - # this case, the call to `bar()` must be embargoed, and a `Disembargo` message must be sent along - # the same path as `foo()` to ensure that the `Disembargo` arrives after `foo()`. Once the - # `Disembargo` arrives, `bar()` can then be delivered. - # - # There are two particular cases where embargos are important. Consider object Alice, in Vat A, - # who holds a promise P, pointing towards Vat B, that eventually resolves to Carol. The two - # cases are: - # - Carol lives in Vat A, i.e. next to Alice. In this case, Vat A needs to send a `Disembargo` - # message that echos through Vat B and back, to ensure that all pipelined calls on the promise - # have been delivered. - # - Carol lives in a different Vat C. When the promise resolves, a three-party handoff occurs - # (see `Provide` and `Accept`, which constitute level 3 of the protocol). In this case, we - # piggyback on the state that has already been set up to handle the handoff: the `Accept` - # message (from Vat A to Vat C) is embargoed, as are all pipelined messages sent to it, while - # a `Disembargo` message is sent from Vat A through Vat B to Vat C. See `Accept.embargo` for - # an example. - # - # Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise - # already pointed at), no embargo is needed, because the pipelined calls are delivered over the - # same path as the later direct calls. - # - # Keep in mind that promise resolution happens both in the form of Resolve messages as well as - # Return messages (which resolve PromisedAnswers). Embargos apply in both cases. - # - # An alternative strategy for enforcing E-order over promise resolution could be for Vat A to - # implement the embargo internally. When Vat A is notified of promise resolution, it could - # send a dummy no-op call to promise P and wait for it to complete. Until that call completes, - # all calls to the capability are queued locally. This strategy works, but is pessimistic: - # in the three-party case, it requires an A -> B -> C -> B -> A round trip before calls can start - # being delivered directly to from Vat A to Vat C. The `Disembargo` message allows latency to be - # reduced. (In the two-party loopback case, the `Disembargo` message is just a more explicit way - # of accomplishing the same thing as a no-op call, but isn't any faster.) - # - # *The Tribble 4-way Race Condition* - # - # Any implementation of promise resolution and embargos must be aware of what we call the - # "Tribble 4-way race condition", after Dean Tribble, who explained the problem in a lively - # Friam meeting. - # - # Embargos are designed to work in the case where a two-hop path is being shortened to one hop. - # But sometimes there are more hops. Imagine that Alice has a reference to a remote promise P1 - # that eventually resolves to _another_ remote promise P2 (in a third vat), which _at the same - # time_ happens to resolve to Bob (in a fourth vat). In this case, we're shortening from a 3-hop - # path (with four parties) to a 1-hop path (Alice -> Bob). - # - # Extending the embargo/disembargo protocol to be able to shorted multiple hops at once seems - # difficult. Instead, we make a rule that prevents this case from coming up: - # - # One a promise P has been resolved to a remove object reference R, then all further messages - # received addressed to P will be forwarded strictly to R. Even if it turns out later that R is - # itself a promise, and has resolved to some other object Q, messages sent to P will still be - # forwarded to R, not directly to Q (R will of course further forward the messages to Q). - # - # This rule does not cause a significant performance burden because once P has resolved to R, it - # is expected that people sending messages to P will shortly start sending them to R instead and - # drop P. P is at end-of-life anyway, so it doesn't matter if it ignores chances to further - # optimize its path. - - target @0 :MessageTarget; - # What is to be disembargoed. - - using EmbargoId = UInt32; - # Used in `senderLoopback` and `receiverLoopback`, below. - - context :union { - senderLoopback @1 :EmbargoId; - # The sender is requesting a disembargo on a promise that is known to resolve back to a - # capability hosted by the sender. As soon as the receiver has echoed back all pipelined calls - # on this promise, it will deliver the Disembargo back to the sender with `receiverLoopback` - # set to the same value as `senderLoopback`. This value is chosen by the sender, and since - # it is also consumed be the sender, the sender can use whatever strategy it wants to make sure - # the value is unambiguous. - # - # The receiver must verify that the target capability actually resolves back to the sender's - # vat. Otherwise, the sender has committed a protocol error and should be disconnected. - - receiverLoopback @2 :EmbargoId; - # The receiver previously sent a `senderLoopback` Disembargo towards a promise resolving to - # this capability, and that Disembargo is now being echoed back. - - accept @3 :Void; - # **(level 3)** - # - # The sender is requesting a disembargo on a promise that is known to resolve to a third-party - # capability that the sender is currently in the process of accepting (using `Accept`). - # The receiver of this `Disembargo` has an outstanding `Provide` on said capability. The - # receiver should now send a `Disembargo` with `provide` set to the question ID of that - # `Provide` message. - # - # See `Accept.embargo` for an example. - - provide @4 :QuestionId; - # **(level 3)** - # - # The sender is requesting a disembargo on a capability currently being provided to a third - # party. The question ID identifies the `Provide` message previously sent by the sender to - # this capability. On receipt, the receiver (the capability host) shall release the embargo - # on the `Accept` message that it has received from the third party. See `Accept.embargo` for - # an example. - } -} - -# Level 2 message types ---------------------------------------------- - -# See persistent.capnp. - -# Level 3 message types ---------------------------------------------- - -struct Provide { - # **(level 3)** - # - # Message type sent to indicate that the sender wishes to make a particular capability implemented - # by the receiver available to a third party for direct access (without the need for the third - # party to proxy through the sender). - # - # (In CapTP, `Provide` and `Accept` are methods of the global `NonceLocator` object exported by - # every vat. In Cap'n Proto, we bake this into the core protocol.) - - questionId @0 :QuestionId; - # Question ID to be held open until the recipient has received the capability. A result will be - # returned once the third party has successfully received the capability. The sender must at some - # point send a `Finish` message as with any other call, and that message can be used to cancel the - # whole operation. - - target @1 :MessageTarget; - # What is to be provided to the third party. - - recipient @2 :RecipientId; - # Identity of the third party that is expected to pick up the capability. -} - -struct Accept { - # **(level 3)** - # - # Message type sent to pick up a capability hosted by the receiving vat and provided by a third - # party. The third party previously designated the capability using `Provide`. - # - # This message is also used to pick up a redirected return -- see `Return.redirect`. - - questionId @0 :QuestionId; - # A new question ID identifying this accept message, which will eventually receive a Return - # message containing the provided capability (or the call result in the case of a redirected - # return). - - provision @1 :ProvisionId; - # Identifies the provided object to be picked up. - - embargo @2 :Bool; - # If true, this accept shall be temporarily embargoed. The resulting `Return` will not be sent, - # and any pipelined calls will not be delivered, until the embargo is released. The receiver - # (the capability host) will expect the provider (the vat that sent the `Provide` message) to - # eventually send a `Disembargo` message with the field `context.provide` set to the question ID - # of the original `Provide` message. At that point, the embargo is released and the queued - # messages are delivered. - # - # For example: - # - Alice, in Vat A, holds a promise P, which currently points toward Vat B. - # - Alice calls foo() on P. The `Call` message is sent to Vat B. - # - The promise P in Vat B ends up resolving to Carol, in Vat C. - # - Vat B sends a `Provide` message to Vat C, identifying Vat A as the recipient. - # - Vat B sends a `Resolve` message to Vat A, indicating that the promise has resolved to a - # `ThirdPartyCapId` identifying Carol in Vat C. - # - Vat A sends an `Accept` message to Vat C to pick up the capability. Since Vat A knows that - # it has an outstanding call to the promise, it sets `embargo` to `true` in the `Accept` - # message. - # - Vat A sends a `Disembargo` message to Vat B on promise P, with `context.accept` set. - # - Alice makes a call bar() to promise P, which is now pointing towards Vat C. Alice doesn't - # know anything about the mechanics of promise resolution happening under the hood, but she - # expects that bar() will be delivered after foo() because that is the order in which she - # initiated the calls. - # - Vat A sends the bar() call to Vat C, as a pipelined call on the result of the `Accept` (which - # hasn't returned yet, due to the embargo). Since calls to the newly-accepted capability - # are embargoed, Vat C does not deliver the call yet. - # - At some point, Vat B forwards the foo() call from the beginning of this example on to Vat C. - # - Vat B forwards the `Disembargo` from Vat A on to vat C. It sets `context.provide` to the - # question ID of the `Provide` message it had sent previously. - # - Vat C receives foo() before `Disembargo`, thus allowing it to correctly deliver foo() - # before delivering bar(). - # - Vat C receives `Disembargo` from Vat B. It can now send a `Return` for the `Accept` from - # Vat A, as well as deliver bar(). -} - -# Level 4 message types ---------------------------------------------- - -struct Join { - # **(level 4)** - # - # Message type sent to implement E.join(), which, given a number of capabilities that are - # expected to be equivalent, finds the underlying object upon which they all agree and forms a - # direct connection to it, skipping any proxies that may have been constructed by other vats - # while transmitting the capability. See: - # http://erights.org/elib/equality/index.html - # - # Note that this should only serve to bypass fully-transparent proxies -- proxies that were - # created merely for convenience, without any intention of hiding the underlying object. - # - # For example, say Bob holds two capabilities hosted by Alice and Carol, but he expects that both - # are simply proxies for a capability hosted elsewhere. He then issues a join request, which - # operates as follows: - # - Bob issues Join requests on both Alice and Carol. Each request contains a different piece - # of the JoinKey. - # - Alice is proxying a capability hosted by Dana, so forwards the request to Dana's cap. - # - Dana receives the first request and sees that the JoinKeyPart is one of two. She notes that - # she doesn't have the other part yet, so she records the request and responds with a - # JoinResult. - # - Alice relays the JoinAswer back to Bob. - # - Carol is also proxying a capability from Dana, and so forwards her Join request to Dana as - # well. - # - Dana receives Carol's request and notes that she now has both parts of a JoinKey. She - # combines them in order to form information needed to form a secure connection to Bob. She - # also responds with another JoinResult. - # - Bob receives the responses from Alice and Carol. He uses the returned JoinResults to - # determine how to connect to Dana and attempts to form the connection. Since Bob and Dana now - # agree on a secret key that neither Alice nor Carol ever saw, this connection can be made - # securely even if Alice or Carol is conspiring against the other. (If Alice and Carol are - # conspiring _together_, they can obviously reproduce the key, but this doesn't matter because - # the whole point of the join is to verify that Alice and Carol agree on what capability they - # are proxying.) - # - # If the two capabilities aren't actually proxies of the same object, then the join requests - # will come back with conflicting `hostId`s and the join will fail before attempting to form any - # connection. - - questionId @0 :QuestionId; - # Question ID used to respond to this Join. (Note that this ID only identifies one part of the - # request for one hop; each part has a different ID and relayed copies of the request have - # (probably) different IDs still.) - # - # The receiver will reply with a `Return` whose `results` is a JoinResult. This `JoinResult` - # is relayed from the joined object's host, possibly with transformation applied as needed - # by the network. - # - # Like any return, the result must be released using a `Finish`. However, this release - # should not occur until the joiner has either successfully connected to the joined object. - # Vats relaying a `Join` message similarly must not release the result they receive until the - # return they relayed back towards the joiner has itself been released. This allows the - # joined object's host to detect when the Join operation is canceled before completing -- if - # it receives a `Finish` for one of the join results before the joiner successfully - # connects. It can then free any resources it had allocated as part of the join. - - target @1 :MessageTarget; - # The capability to join. - - keyPart @2 :JoinKeyPart; - # A part of the join key. These combine to form the complete join key, which is used to establish - # a direct connection. - - # TODO(before implementing): Change this so that multiple parts can be sent in a single Join - # message, so that if multiple join parts are going to cross the same connection they can be sent - # together, so that the receive can potentially optimize its handling of them. In the case where - # all parts are bundled together, should the recipient be expected to simply return a cap, so - # that the caller can immediately start pipelining to it? -} - -# ======================================================================================== -# Common structures used in messages - -struct MessageTarget { - # The target of a `Call` or other messages that target a capability. - - union { - importedCap @0 :ImportId; - # This message is to a capability or promise previously imported by the caller (exported by - # the receiver). - - promisedAnswer @1 :PromisedAnswer; - # This message is to a capability that is expected to be returned by another call that has not - # yet been completed. - # - # At level 0, this is supported only for addressing the result of a previous `Bootstrap`, so - # that initial startup doesn't require a round trip. - } -} - -struct Payload { - # Represents some data structure that might contain capabilities. - - content @0 :AnyPointer; - # Some Cap'n Proto data structure. Capability pointers embedded in this structure index into - # `capTable`. - - capTable @1 :List(CapDescriptor); - # Descriptors corresponding to the cap pointers in `content`. -} - -struct CapDescriptor { - # **(level 1)** - # - # When an application-defined type contains an interface pointer, that pointer contains an index - # into the message's capability table -- i.e. the `capTable` part of the `Payload`. Each - # capability in the table is represented as a `CapDescriptor`. The runtime API should not reveal - # the CapDescriptor directly to the application, but should instead wrap it in some kind of - # callable object with methods corresponding to the interface that the capability implements. - # - # Keep in mind that `ExportIds` in a `CapDescriptor` are subject to reference counting. See the - # description of `ExportId`. - - union { - none @0 :Void; - # There is no capability here. This `CapDescriptor` should not appear in the payload content. - # A `none` CapDescriptor can be generated when an application inserts a capability into a - # message and then later changes its mind and removes it -- rewriting all of the other - # capability pointers may be hard, so instead a tombstone is left, similar to the way a removed - # struct or list instance is zeroed out of the message but the space is not reclaimed. - # Hopefully this is unusual. - - senderHosted @1 :ExportId; - # A capability newly exported by the sender. This is the ID of the new capability in the - # sender's export table (receiver's import table). - - senderPromise @2 :ExportId; - # A promise that the sender will resolve later. The sender will send exactly one Resolve - # message at a future point in time to replace this promise. Note that even if the same - # `senderPromise` is received multiple times, only one `Resolve` is sent to cover all of - # them. If `senderPromise` is released before the `Resolve` is sent, the sender (of this - # `CapDescriptor`) may choose not to send the `Resolve` at all. - - receiverHosted @3 :ImportId; - # A capability (or promise) previously exported by the receiver (imported by the sender). - - receiverAnswer @4 :PromisedAnswer; - # A capability expected to be returned in the results of a currently-outstanding call posed - # by the sender. - - thirdPartyHosted @5 :ThirdPartyCapDescriptor; - # **(level 3)** - # - # A capability that lives in neither the sender's nor the receiver's vat. The sender needs - # to form a direct connection to a third party to pick up the capability. - # - # Level 1 and 2 implementations that receive a `thirdPartyHosted` may simply send calls to its - # `vine` instead. - } -} - -struct PromisedAnswer { - # **(mostly level 1)** - # - # Specifies how to derive a promise from an unanswered question, by specifying the path of fields - # to follow from the root of the eventual result struct to get to the desired capability. Used - # to address method calls to a not-yet-returned capability or to pass such a capability as an - # input to some other method call. - # - # Level 0 implementations must support `PromisedAnswer` only for the case where the answer is - # to a `Bootstrap` message. In this case, `path` is always empty since `Bootstrap` always returns - # a raw capability. - - questionId @0 :QuestionId; - # ID of the question (in the sender's question table / receiver's answer table) whose answer is - # expected to contain the capability. - - transform @1 :List(Op); - # Operations / transformations to apply to the result in order to get the capability actually - # being addressed. E.g. if the result is a struct and you want to call a method on a capability - # pointed to by a field of the struct, you need a `getPointerField` op. - - struct Op { - union { - noop @0 :Void; - # Does nothing. This member is mostly defined so that we can make `Op` a union even - # though (as of this writing) only one real operation is defined. - - getPointerField @1 :UInt16; - # Get a pointer field within a struct. The number is an index into the pointer section, NOT - # a field ordinal, so that the receiver does not need to understand the schema. - - # TODO(someday): We could add: - # - For lists, the ability to address every member of the list, or a slice of the list, the - # result of which would be another list. This is useful for implementing the equivalent of - # a SQL table join (not to be confused with the `Join` message type). - # - Maybe some ability to test a union. - # - Probably not a good idea: the ability to specify an arbitrary script to run on the - # result. We could define a little stack-based language where `Op` specifies one - # "instruction" or transformation to apply. Although this is not a good idea - # (over-engineered), any narrower additions to `Op` should be designed as if this - # were the eventual goal. - } - } -} - -struct ThirdPartyCapDescriptor { - # **(level 3)** - # - # Identifies a capability in a third-party vat that the sender wants the receiver to pick up. - - id @0 :ThirdPartyCapId; - # Identifies the third-party host and the specific capability to accept from it. - - vineId @1 :ExportId; - # A proxy for the third-party object exported by the sender. In CapTP terminology this is called - # a "vine", because it is an indirect reference to the third-party object that snakes through the - # sender vat. This serves two purposes: - # - # * Level 1 and 2 implementations that don't understand how to connect to a third party may - # simply send calls to the vine. Such calls will be forwarded to the third-party by the - # sender. - # - # * Level 3 implementations must release the vine once they have successfully picked up the - # object from the third party. This ensures that the capability is not released by the sender - # prematurely. - # - # The sender will close the `Provide` request that it has sent to the third party as soon as - # it receives either a `Call` or a `Release` message directed at the vine. -} - -struct Exception { - # **(level 0)** - # - # Describes an arbitrary error that prevented an operation (e.g. a call) from completing. - # - # Cap'n Proto exceptions always indicate that something went wrong. In other words, in a fantasy - # world where everything always works as expected, no exceptions would ever be thrown. Clients - # should only ever catch exceptions as a means to implement fault-tolerance, where "fault" can - # mean: - # - Bugs. - # - Invalid input. - # - Configuration errors. - # - Network problems. - # - Insufficient resources. - # - Version skew (unimplemented functionality). - # - Other logistical problems. - # - # Exceptions should NOT be used to flag application-specific conditions that a client is expected - # to handle in an application-specific way. Put another way, in the Cap'n Proto world, - # "checked exceptions" (where an interface explicitly defines the exceptions it throws and - # clients are forced by the type system to handle those exceptions) do NOT make sense. - - reason @0 :Text; - # Human-readable failure description. - - type @3 :Type; - # The type of the error. The purpose of this enum is not to describe the error itself, but - # rather to describe how the client might want to respond to the error. - - enum Type { - failed @0; - # A generic problem occurred, and it is believed that if the operation were repeated without - # any change in the state of the world, the problem would occur again. - # - # A client might respond to this error by logging it for investigation by the developer and/or - # displaying it to the user. - - overloaded @1; - # The request was rejected due to a temporary lack of resources. - # - # Examples include: - # - There's not enough CPU time to keep up with incoming requests, so some are rejected. - # - The server ran out of RAM or disk space during the request. - # - The operation timed out (took significantly longer than it should have). - # - # A client might respond to this error by scheduling to retry the operation much later. The - # client should NOT retry again immediately since this would likely exacerbate the problem. - - disconnected @2; - # The method failed because a connection to some necessary capability was lost. - # - # Examples include: - # - The client introduced the server to a third-party capability, the connection to that third - # party was subsequently lost, and then the client requested that the server use the dead - # capability for something. - # - The client previously requested that the server obtain a capability from some third party. - # The server returned a capability to an object wrapping the third-party capability. Later, - # the server's connection to the third party was lost. - # - The capability has been revoked. Revocation does not necessarily mean that the client is - # no longer authorized to use the capability; it is often used simply as a way to force the - # client to repeat the setup process, perhaps to efficiently move them to a new back-end or - # get them to recognize some other change that has occurred. - # - # A client should normally respond to this error by releasing all capabilities it is currently - # holding related to the one it called and then re-creating them by restoring SturdyRefs and/or - # repeating the method calls used to create them originally. In other words, disconnect and - # start over. This should in turn cause the server to obtain a new copy of the capability that - # it lost, thus making everything work. - # - # If the client receives another `disconnencted` error in the process of rebuilding the - # capability and retrying the call, it should treat this as an `overloaded` error: the network - # is currently unreliable, possibly due to load or other temporary issues. - - unimplemented @3; - # The server doesn't implement the requested method. If there is some other method that the - # client could call (perhaps an older and/or slower interface), it should try that instead. - # Otherwise, this should be treated like `failed`. - } - - obsoleteIsCallersFault @1 :Bool; - # OBSOLETE. Ignore. - - obsoleteDurability @2 :UInt16; - # OBSOLETE. See `type` instead. -} - -# ======================================================================================== -# Network-specific Parameters -# -# Some parts of the Cap'n Proto RPC protocol are not specified here because different vat networks -# may wish to use different approaches to solving them. For example, on the public internet, you -# may want to authenticate vats using public-key cryptography, but on a local intranet with trusted -# infrastructure, you may be happy to authenticate based on network address only, or some other -# lightweight mechanism. -# -# To accommodate this, we specify several "parameter" types. Each type is defined here as an -# alias for `AnyPointer`, but a specific network will want to define a specific set of types to use. -# All vats in a vat network must agree on these parameters in order to be able to communicate. -# Inter-network communication can be accomplished through "gateways" that perform translation -# between the primitives used on each network; these gateways may need to be deeply stateful, -# depending on the translations they perform. -# -# For interaction over the global internet between parties with no other prior arrangement, a -# particular set of bindings for these types is defined elsewhere. (TODO(someday): Specify where -# these common definitions live.) -# -# Another common network type is the two-party network, in which one of the parties typically -# interacts with the outside world entirely through the other party. In such a connection between -# Alice and Bob, all objects that exist on Bob's other networks appear to Alice as if they were -# hosted by Bob himself, and similarly all objects on Alice's network (if she even has one) appear -# to Bob as if they were hosted by Alice. This network type is interesting because from the point -# of view of a simple application that communicates with only one other party via the two-party -# protocol, there are no three-party interactions at all, and joins are unusually simple to -# implement, so implementing at level 4 is barely more complicated than implementing at level 1. -# Moreover, if you pair an app implementing the two-party network with a container that implements -# some other network, the app can then participate on the container's network just as if it -# implemented that network directly. The types used by the two-party network are defined in -# `rpc-twoparty.capnp`. -# -# The things that we need to parameterize are: -# - How to store capabilities long-term without holding a connection open (mostly level 2). -# - How to authenticate vats in three-party introductions (level 3). -# - How to implement `Join` (level 4). -# -# Persistent references -# --------------------- -# -# **(mostly level 2)** -# -# We want to allow some capabilities to be stored long-term, even if a connection is lost and later -# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't -# help here. We need a way to specify long-term identifiers, as well as a strategy for -# reconnecting to a referenced capability later. -# -# Three-party interactions -# ------------------------ -# -# **(level 3)** -# -# In cases where more than two vats are interacting, we have situations where VatA holds a -# capability hosted by VatB and wants to send that capability to VatC. This can be accomplished -# by VatA proxying requests on the new capability, but doing so has two big problems: -# - It's inefficient, requiring an extra network hop. -# - If VatC receives another capability to the same object from VatD, it is difficult for VatC to -# detect that the two capabilities are really the same and to implement the E "join" operation, -# which is necessary for certain four-or-more-party interactions, such as the escrow pattern. -# See: http://www.erights.org/elib/equality/grant-matcher/index.html -# -# Instead, we want a way for VatC to form a direct, authenticated connection to VatB. -# -# Join -# ---- -# -# **(level 4)** -# -# The `Join` message type and corresponding operation arranges for a direct connection to be formed -# between the joiner and the host of the joined object, and this connection must be authenticated. -# Thus, the details are network-dependent. - -using SturdyRef = AnyPointer; -# **(level 2)** -# -# Identifies a persisted capability that can be restored in the future. How exactly a SturdyRef -# is restored to a live object is specified along with the SturdyRef definition (i.e. not by -# rpc.capnp). -# -# Generally a SturdyRef needs to specify three things: -# - How to reach the vat that can restore the ref (e.g. a hostname or IP address). -# - How to authenticate the vat after connecting (e.g. a public key fingerprint). -# - The identity of a specific object hosted by the vat. Generally, this is an opaque pointer whose -# format is defined by the specific vat -- the client has no need to inspect the object ID. -# It is important that the objec ID be unguessable if the object is not public (and objects -# should almost never be public). -# -# The above are only suggestions. Some networks might work differently. For example, a private -# network might employ a special restorer service whose sole purpose is to restore SturdyRefs. -# In this case, the entire contents of SturdyRef might be opaque, because they are intended only -# to be forwarded to the restorer service. - -using ProvisionId = AnyPointer; -# **(level 3)** -# -# The information that must be sent in an `Accept` message to identify the object being accepted. -# -# In a network where each vat has a public/private key pair, this could simply be the public key -# fingerprint of the provider vat along with the question ID used in the `Provide` message sent from -# that provider. - -using RecipientId = AnyPointer; -# **(level 3)** -# -# The information that must be sent in a `Provide` message to identify the recipient of the -# capability. -# -# In a network where each vat has a public/private key pair, this could simply be the public key -# fingerprint of the recipient. (CapTP also calls for a nonce to identify the object. In our -# case, the `Provide` message's `questionId` can serve as the nonce.) - -using ThirdPartyCapId = AnyPointer; -# **(level 3)** -# -# The information needed to connect to a third party and accept a capability from it. -# -# In a network where each vat has a public/private key pair, this could be a combination of the -# third party's public key fingerprint, hints on how to connect to the third party (e.g. an IP -# address), and the question ID used in the corresponding `Provide` message sent to that third party -# (used to identify which capability to pick up). - -using JoinKeyPart = AnyPointer; -# **(level 4)** -# -# A piece of a secret key. One piece is sent along each path that is expected to lead to the same -# place. Once the pieces are combined, a direct connection may be formed between the sender and -# the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type. -# -# The motivation for Joins is discussed under "Supporting Equality" in the "Unibus" protocol -# sketch: http://www.erights.org/elib/distrib/captp/unibus.html -# -# In a network where each vat has a public/private key pair and each vat forms no more than one -# connection to each other vat, Joins will rarely -- perhaps never -- be needed, as objects never -# need to be transparently proxied and references to the same object sent over the same connection -# have the same export ID. Thus, a successful join requires only checking that the two objects -# come from the same connection and have the same ID, and then completes immediately. -# -# However, in networks where two vats may form more than one connection between each other, or -# where proxying of objects occurs, joins are necessary. -# -# Typically, each JoinKeyPart would include a fixed-length data value such that all value parts -# XOR'd together forms a shared secret that can be used to form an encrypted connection between -# the joiner and the joined object's host. Each JoinKeyPart should also include an indication of -# how many parts to expect and a hash of the shared secret (used to match up parts). - -using JoinResult = AnyPointer; -# **(level 4)** -# -# Information returned as the result to a `Join` message, needed by the joiner in order to form a -# direct connection to a joined object. This might simply be the address of the joined object's -# host vat, since the `JoinKey` has already been communicated so the two vats already have a shared -# secret to use to authenticate each other. -# -# The `JoinResult` should also contain information that can be used to detect when the Join -# requests ended up reaching different objects, so that this situation can be detected easily. -# This could be a simple matter of including a sequence number -- if the joiner receives two -# `JoinResult`s with sequence number 0, then they must have come from different objects and the -# whole join is a failure. - -# ======================================================================================== -# Network interface sketch -# -# The interfaces below are meant to be pseudo-code to illustrate how the details of a particular -# vat network might be abstracted away. They are written like Cap'n Proto interfaces, but in -# practice you'd probably define these interfaces manually in the target programming language. A -# Cap'n Proto RPC implementation should be able to use these interfaces without knowing the -# definitions of the various network-specific parameters defined above. - -# interface VatNetwork { -# # Represents a vat network, with the ability to connect to particular vats and receive -# # connections from vats. -# # -# # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the -# # caller is expected to find and share state with existing users of the connection. -# -# # Level 0 features ----------------------------------------------- -# -# connect(vatId :VatId) :Connection; -# # Connect to the given vat. The transport should return a promise that does not -# # resolve until authentication has completed, but allows messages to be pipelined in before -# # that; the transport either queues these messages until authenticated, or sends them encrypted -# # such that only the authentic vat would be able to decrypt them. The latter approach avoids a -# # round trip for authentication. -# -# accept() :Connection; -# # Wait for the next incoming connection and return it. Only connections formed by -# # connect() are returned by this method. -# -# # Level 4 features ----------------------------------------------- -# -# newJoiner(count :UInt32) :NewJoinerResponse; -# # Prepare a new Join operation, which will eventually lead to forming a new direct connection -# # to the host of the joined capability. `count` is the number of capabilities to join. -# -# struct NewJoinerResponse { -# joinKeyParts :List(JoinKeyPart); -# # Key parts to send in Join messages to each capability. -# -# joiner :Joiner; -# # Used to establish the final connection. -# } -# -# interface Joiner { -# addJoinResult(result :JoinResult) :Void; -# # Add a JoinResult received in response to one of the `Join` messages. All `JoinResult`s -# # returned from all paths must be added before trying to connect. -# -# connect() :ConnectionAndProvisionId; -# # Try to form a connection to the joined capability's host, verifying that it has received -# # all of the JoinKeyParts. Once the connection is formed, the caller should send an `Accept` -# # message on it with the specified `ProvisionId` in order to receive the final capability. -# } -# -# acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath)) -# :ConnectionAndProvisionId; -# # Called on a joined capability's host to receive the connection from the joiner, once all -# # key parts have arrived. The caller should expect to receive an `Accept` message over the -# # connection with the given ProvisionId. -# } -# -# interface Connection { -# # Level 0 features ----------------------------------------------- -# -# send(message :Message) :Void; -# # Send the message. Returns successfully when the message (and all preceding messages) has -# # been acknowledged by the recipient. -# -# receive() :Message; -# # Receive the next message, and acknowledges receipt to the sender. Messages are received in -# # the order in which they are sent. -# -# # Level 3 features ----------------------------------------------- -# -# introduceTo(recipient :Connection) :IntroductionInfo; -# # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on -# # this connection and a `ThirdPartyCapId` is to be sent to `recipient`. -# -# struct IntroductionInfo { -# sendToRecipient :ThirdPartyCapId; -# sendToTarget :RecipientId; -# } -# -# connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId; -# # Given a ThirdPartyCapId received over this connection, connect to the third party. The -# # caller should then send an `Accept` message over the new connection. -# -# acceptIntroducedConnection(recipientId :RecipientId) :Connection; -# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the -# # recipient to connect, and return the connection formed. Usually, the first message received -# # on the new connection will be an `Accept` message. -# } -# -# struct ConnectionAndProvisionId { -# # **(level 3)** -# -# connection :Connection; -# # Connection on which to issue `Accept` message. -# -# provision :ProvisionId; -# # `ProvisionId` to send in the `Accept` message. -# } +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xb312981b2552a250; +# Recall that Cap'n Proto RPC allows messages to contain references to remote objects that +# implement interfaces. These references are called "capabilities", because they both designate +# the remote object to use and confer permission to use it. +# +# Recall also that Cap'n Proto RPC has the feature that when a method call itself returns a +# capability, the caller can begin calling methods on that capability _before the first call has +# returned_. The caller essentially sends a message saying "Hey server, as soon as you finish +# that previous call, do this with the result!". Cap'n Proto's RPC protocol makes this possible. +# +# The protocol is significantly more complicated than most RPC protocols. However, this is +# implementation complexity that underlies an easy-to-grasp higher-level model of object oriented +# programming. That is, just like TCP is a surprisingly complicated protocol that implements a +# conceptually-simple byte stream abstraction, Cap'n Proto is a surprisingly complicated protocol +# that implements a conceptually-simple object abstraction. +# +# Cap'n Proto RPC is based heavily on CapTP, the object-capability protocol used by the E +# programming language: +# http://www.erights.org/elib/distrib/captp/index.html +# +# Cap'n Proto RPC takes place between "vats". A vat hosts some set of objects and talks to other +# vats through direct bilateral connections. Typically, there is a 1:1 correspondence between vats +# and processes (in the unix sense of the word), although this is not strictly always true (one +# process could run multiple vats, or a distributed virtual vat might live across many processes). +# +# Cap'n Proto does not distinguish between "clients" and "servers" -- this is up to the application. +# Either end of any connection can potentially hold capabilities pointing to the other end, and +# can call methods on those capabilities. In the doc comments below, we use the words "sender" +# and "receiver". These refer to the sender and receiver of an instance of the struct or field +# being documented. Sometimes we refer to a "third-party" that is neither the sender nor the +# receiver. Documentation is generally written from the point of view of the sender. +# +# It is generally up to the vat network implementation to securely verify that connections are made +# to the intended vat as well as to encrypt transmitted data for privacy and integrity. See the +# `VatNetwork` example interface near the end of this file. +# +# When a new connection is formed, the only interesting things that can be done are to send a +# `Bootstrap` (level 0) or `Accept` (level 3) message. +# +# Unless otherwise specified, messages must be delivered to the receiving application in the same +# order in which they were initiated by the sending application. The goal is to support "E-Order", +# which states that two calls made on the same reference must be delivered in the order which they +# were made: +# http://erights.org/elib/concurrency/partial-order.html +# +# Since the full protocol is complicated, we define multiple levels of support that an +# implementation may target. For many applications, level 1 support will be sufficient. +# Comments in this file indicate which level requires the corresponding feature to be +# implemented. +# +# * **Level 0:** The implementation does not support object references. Only the bootstrap interface +# can be called. At this level, the implementation does not support object-oriented protocols and +# is similar in complexity to JSON-RPC or Protobuf services. This level should be considered only +# a temporary stepping-stone toward level 1 as the lack of object references drastically changes +# how protocols are designed. Applications _should not_ attempt to design their protocols around +# the limitations of level 0 implementations. +# +# * **Level 1:** The implementation supports simple bilateral interaction with object references +# and promise pipelining, but interactions between three or more parties are supported only via +# proxying of objects. E.g. if Alice (in Vat A) wants to send Bob (in Vat B) a capability +# pointing to Carol (in Vat C), Alice must create a proxy of Carol within Vat A and send Bob a +# reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do +# not support checking if two capabilities received from different vats actually point to the +# same object ("join"), although they should be able to do this check on capabilities received +# from the same vat. +# +# * **Level 2:** The implementation supports saving persistent capabilities -- i.e. capabilities +# that remain valid even after disconnect, and can be restored on a future connection. When a +# capability is saved, the requester receives a `SturdyRef`, which is a token that can be used +# to restore the capability later. +# +# * **Level 3:** The implementation supports three-way interactions. That is, if Alice (in Vat A) +# sends Bob (in Vat B) a capability pointing to Carol (in Vat C), then Vat B will automatically +# form a direct connection to Vat C rather than have requests be proxied through Vat A. +# +# * **Level 4:** The entire protocol is implemented, including joins (checking if two capabilities +# are equivalent). +# +# Note that an implementation must also support specific networks (transports), as described in +# the "Network-specific Parameters" section below. An implementation might have different levels +# depending on the network used. +# +# New implementations of Cap'n Proto should start out targeting the simplistic two-party network +# type as defined in `rpc-twoparty.capnp`. With this network type, level 3 is irrelevant and +# levels 2 and 4 are much easier than usual to implement. When such an implementation is paired +# with a container proxy, the contained app effectively gets to make full use of the proxy's +# network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to +# bother implementing any other vat network protocol -- just use the correct container type and get +# it for free. + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("capnp::rpc"); + +# ======================================================================================== +# The Four Tables +# +# Cap'n Proto RPC connections are stateful (although an application built on Cap'n Proto could +# export a stateless interface). As in CapTP, for each open connection, a vat maintains four state +# tables: questions, answers, imports, and exports. See the diagram at: +# http://www.erights.org/elib/distrib/captp/4tables.html +# +# The question table corresponds to the other end's answer table, and the imports table corresponds +# to the other end's exports table. +# +# The entries in each table are identified by ID numbers (defined below as 32-bit integers). These +# numbers are always specific to the connection; a newly-established connection starts with no +# valid IDs. Since low-numbered IDs will pack better, it is suggested that IDs be assigned like +# Unix file descriptors -- prefer the lowest-number ID that is currently available. +# +# IDs in the questions/answers tables are chosen by the questioner and generally represent method +# calls that are in progress. +# +# IDs in the imports/exports tables are chosen by the exporter and generally represent objects on +# which methods may be called. Exports may be "settled", meaning the exported object is an actual +# object living in the exporter's vat, or they may be "promises", meaning the exported object is +# the as-yet-unknown result of an ongoing operation and will eventually be resolved to some other +# object once that operation completes. Calls made to a promise will be forwarded to the eventual +# target once it is known. The eventual replacement object does *not* get the same ID as the +# promise, as it may turn out to be an object that is already exported (so already has an ID) or +# may even live in a completely different vat (and so won't get an ID on the same export table +# at all). +# +# IDs can be reused over time. To make this safe, we carefully define the lifetime of IDs. Since +# messages using the ID could be traveling in both directions simultaneously, we must define the +# end of life of each ID _in each direction_. The ID is only safe to reuse once it has been +# released by both sides. +# +# When a Cap'n Proto connection is lost, everything on the four tables is lost. All questions are +# canceled and throw exceptions. All imports become broken (all future calls to them throw +# exceptions). All exports and answers are implicitly released. The only things not lost are +# persistent capabilities (`SturdyRef`s). The application must plan for this and should respond by +# establishing a new connection and restoring from these persistent capabilities. + +using QuestionId = UInt32; +# **(level 0)** +# +# Identifies a question in the sender's question table (which corresponds to the receiver's answer +# table). The questioner (caller) chooses an ID when making a call. The ID remains valid in +# caller -> callee messages until a Finish message is sent, and remains valid in callee -> caller +# messages until a Return message is sent. + +using AnswerId = QuestionId; +# **(level 0)** +# +# Identifies an answer in the sender's answer table (which corresponds to the receiver's question +# table). +# +# AnswerId is physically equivalent to QuestionId, since the question and answer tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. + +using ExportId = UInt32; +# **(level 1)** +# +# Identifies an exported capability or promise in the sender's export table (which corresponds +# to the receiver's import table). The exporter chooses an ID before sending a capability over the +# wire. If the capability is already in the table, the exporter should reuse the same ID. If the +# ID is a promise (as opposed to a settled capability), this must be indicated at the time the ID +# is introduced (e.g. by using `senderPromise` instead of `senderHosted` in `CapDescriptor`); in +# this case, the importer shall expect a later `Resolve` message that replaces the promise. +# +# ExportId/ImportIds are subject to reference counting. Whenever an `ExportId` is sent over the +# wire (from the exporter to the importer), the export's reference count is incremented (unless +# otherwise specified). The reference count is later decremented by a `Release` message. Since +# the `Release` message can specify an arbitrary number by which to reduce the reference count, the +# importer should usually batch reference decrements and only send a `Release` when it believes the +# reference count has hit zero. Of course, it is possible that a new reference to the export is +# in-flight at the time that the `Release` message is sent, so it is necessary for the exporter to +# keep track of the reference count on its end as well to avoid race conditions. +# +# When a connection is lost, all exports are implicitly released. It is not possible to restore +# a connection state after disconnect (although a transport layer could implement a concept of +# persistent connections if it is transparent to the RPC layer). + +using ImportId = ExportId; +# **(level 1)** +# +# Identifies an imported capability or promise in the sender's import table (which corresponds to +# the receiver's export table). +# +# ImportId is physically equivalent to ExportId, since the export and import tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. +# +# An `ImportId` remains valid in importer -> exporter messages until the importer has sent +# `Release` messages that (it believes) have reduced the reference count to zero. + +# ======================================================================================== +# Messages + +struct Message { + # An RPC connection is a bi-directional stream of Messages. + + union { + unimplemented @0 :Message; + # The sender previously received this message from the peer but didn't understand it or doesn't + # yet implement the functionality that was requested. So, the sender is echoing the message + # back. In some cases, the receiver may be able to recover from this by pretending the sender + # had taken some appropriate "null" action. + # + # For example, say `resolve` is received by a level 0 implementation (because a previous call + # or return happened to contain a promise). The level 0 implementation will echo it back as + # `unimplemented`. The original sender can then simply release the cap to which the promise + # had resolved, thus avoiding a leak. + # + # For any message type that introduces a question, if the message comes back unimplemented, + # the original sender may simply treat it as if the question failed with an exception. + # + # In cases where there is no sensible way to react to an `unimplemented` message (without + # resource leaks or other serious problems), the connection may need to be aborted. This is + # a gray area; different implementations may take different approaches. + + abort @1 :Exception; + # Sent when a connection is being aborted due to an unrecoverable error. This could be e.g. + # because the sender received an invalid or nonsensical message (`isCallersFault` is true) or + # because the sender had an internal error (`isCallersFault` is false). The sender will shut + # down the outgoing half of the connection after `abort` and will completely close the + # connection shortly thereafter (it's up to the sender how much of a time buffer they want to + # offer for the client to receive the `abort` before the connection is reset). + + # Level 0 features ----------------------------------------------- + + bootstrap @8 :Bootstrap; # Request the peer's bootstrap interface. + call @2 :Call; # Begin a method call. + return @3 :Return; # Complete a method call. + finish @4 :Finish; # Release a returned answer / cancel a call. + + # Level 1 features ----------------------------------------------- + + resolve @5 :Resolve; # Resolve a previously-sent promise. + release @6 :Release; # Release a capability so that the remote object can be deallocated. + disembargo @13 :Disembargo; # Lift an embargo used to enforce E-order over promise resolution. + + # Level 2 features ----------------------------------------------- + + obsoleteSave @7 :AnyPointer; + # Obsolete request to save a capability, resulting in a SturdyRef. This has been replaced + # by the `Persistent` interface defined in `persistent.capnp`. This operation was never + # implemented. + + obsoleteDelete @9 :AnyPointer; + # Obsolete way to delete a SturdyRef. This operation was never implemented. + + # Level 3 features ----------------------------------------------- + + provide @10 :Provide; # Provide a capability to a third party. + accept @11 :Accept; # Accept a capability provided by a third party. + + # Level 4 features ----------------------------------------------- + + join @12 :Join; # Directly connect to the common root of two or more proxied caps. + } +} + +# Level 0 message types ---------------------------------------------- + +struct Bootstrap { + # **(level 0)** + # + # Get the "bootstrap" interface exported by the remote vat. + # + # For level 0, 1, and 2 implementations, the "bootstrap" interface is simply the main interface + # exported by a vat. If the vat acts as a server fielding connections from clients, then the + # bootstrap interface defines the basic functionality available to a client when it connects. + # The exact interface definition obviously depends on the application. + # + # We call this a "bootstrap" because in an ideal Cap'n Proto world, bootstrap interfaces would + # never be used. In such a world, any time you connect to a new vat, you do so because you + # received an introduction from some other vat (see `ThirdPartyCapId`). Thus, the first message + # you send is `Accept`, and further communications derive from there. `Bootstrap` is not used. + # + # In such an ideal world, DNS itself would support Cap'n Proto -- performing a DNS lookup would + # actually return a new Cap'n Proto capability, thus introducing you to the target system via + # level 3 RPC. Applications would receive the capability to talk to DNS in the first place as + # an initial endowment or part of a Powerbox interaction. Therefore, an app can form arbitrary + # connections without ever using `Bootstrap`. + # + # Of course, in the real world, DNS is not Cap'n-Proto-based, and we don't want Cap'n Proto to + # require a whole new internet infrastructure to be useful. Therefore, we offer bootstrap + # interfaces as a way to get up and running without a level 3 introduction. Thus, bootstrap + # interfaces are used to "bootstrap" from other, non-Cap'n-Proto-based means of service discovery, + # such as legacy DNS. + # + # Note that a vat need not provide a bootstrap interface, and in fact many vats (especially those + # acting as clients) do not. In this case, the vat should either reply to `Bootstrap` with a + # `Return` indicating an exception, or should return a dummy capability with no methods. + + questionId @0 :QuestionId; + # A new question ID identifying this request, which will eventually receive a Return message + # containing the restored capability. + + deprecatedObjectId @1 :AnyPointer; + # ** DEPRECATED ** + # + # A Vat may export multiple bootstrap interfaces. In this case, `deprecatedObjectId` specifies + # which one to return. If this pointer is null, then the default bootstrap interface is returned. + # + # As of verison 0.5, use of this field is deprecated. If a service wants to export multiple + # bootstrap interfaces, it should instead define a single bootstarp interface that has methods + # that return each of the other interfaces. + # + # **History** + # + # In the first version of Cap'n Proto RPC (0.4.x) the `Bootstrap` message was called `Restore`. + # At the time, it was thought that this would eventually serve as the way to restore SturdyRefs + # (level 2). Meanwhile, an application could offer its "main" interface on a well-known + # (non-secret) SturdyRef. + # + # Since level 2 RPC was not implemented at the time, the `Restore` message was in practice only + # used to obtain the main interface. Since most applications had only one main interface that + # they wanted to restore, they tended to designate this with a null `objectId`. + # + # Unfortunately, the earliest version of the EZ RPC interfaces set a precedent of exporting + # multiple main interfaces by allowing them to be exported under string names. In this case, + # `objectId` was a Text value specifying the name. + # + # All of this proved problematic for several reasons: + # + # - The arrangement assumed that a client wishing to restore a SturdyRef would know exactly what + # machine to connect to and would be able to immediately restore a SturdyRef on connection. + # However, in practice, the ability to restore SturdyRefs is itself a capability that may + # require going through an authentication process to obtain. Thus, it makes more sense to + # define a "restorer service" as a full Cap'n Proto interface. If this restorer interface is + # offered as the vat's bootstrap interface, then this is equivalent to the old arrangement. + # + # - Overloading "Restore" for the purpose of obtaining well-known capabilities encouraged the + # practice of exporting singleton services with string names. If singleton services are desired, + # it is better to have one main interface that has methods that can be used to obtain each + # service, in order to get all the usual benefits of schemas and type checking. + # + # - Overloading "Restore" also had a security problem: Often, "main" or "well-known" + # capabilities exported by a vat are in fact not public: they are intended to be accessed only + # by clients who are capable of forming a connection to the vat. This can lead to trouble if + # the client itself has other clients and wishes to foward some `Restore` requests from those + # external clients -- it has to be very careful not to allow through `Restore` requests + # addressing the default capability. + # + # For example, consider the case of a sandboxed Sandstorm application and its supervisor. The + # application exports a default capability to its supervisor that provides access to + # functionality that only the supervisor is supposed to access. Meanwhile, though, applications + # may publish other capabilities that may be persistent, in which case the application needs + # to field `Restore` requests that could come from anywhere. These requests of course have to + # pass through the supervisor, as all communications with the outside world must. But, the + # supervisor has to be careful not to honor an external request addressing the application's + # default capability, since this capability is privileged. Unfortunately, the default + # capability cannot be given an unguessable name, because then the supervisor itself would not + # be able to address it! + # + # As of Cap'n Proto 0.5, `Restore` has been renamed to `Bootstrap` and is no longer planned for + # use in restoring SturdyRefs. + # + # Note that 0.4 also defined a message type called `Delete` that, like `Restore`, addressed a + # SturdyRef, but indicated that the client would not restore the ref again in the future. This + # operation was never implemented, so it was removed entirely. If a "delete" operation is desired, + # it should exist as a method on the same interface that handles restoring SturdyRefs. However, + # the utility of such an operation is questionable. You wouldn't be able to rely on it for + # garbage collection since a client could always disappear permanently without remembering to + # delete all its SturdyRefs, thus leaving them dangling forever. Therefore, it is advisable to + # design systems such that SturdyRefs never represent "owned" pointers. + # + # For example, say a SturdyRef points to an image file hosted on some server. That image file + # should also live inside a collection (a gallery, perhaps) hosted on the same server, owned by + # a user who can delete the image at any time. If the user deletes the image, the SturdyRef + # stops working. On the other hand, if the SturdyRef is discarded, this has no effect on the + # existence of the image in its collection. +} + +struct Call { + # **(level 0)** + # + # Message type initiating a method call on a capability. + + questionId @0 :QuestionId; + # A number, chosen by the caller, that identifies this call in future messages. This number + # must be different from all other calls originating from the same end of the connection (but + # may overlap with question IDs originating from the opposite end). A fine strategy is to use + # sequential question IDs, but the recipient should not assume this. + # + # A question ID can be reused once both: + # - A matching Return has been received from the callee. + # - A matching Finish has been sent from the caller. + + target @1 :MessageTarget; + # The object that should receive this call. + + interfaceId @2 :UInt64; + # The type ID of the interface being called. Each capability may implement multiple interfaces. + + methodId @3 :UInt16; + # The ordinal number of the method to call within the requested interface. + + allowThirdPartyTailCall @8 :Bool = false; + # Indicates whether or not the receiver is allowed to send a `Return` containing + # `acceptFromThirdParty`. Level 3 implementations should set this true. Otherwise, the callee + # will have to proxy the return in the case of a tail call to a third-party vat. + + params @4 :Payload; + # The call parameters. `params.content` is a struct whose fields correspond to the parameters of + # the method. + + sendResultsTo :union { + # Where should the return message be sent? + + caller @5 :Void; + # Send the return message back to the caller (the usual). + + yourself @6 :Void; + # **(level 1)** + # + # Don't actually return the results to the sender. Instead, hold on to them and await + # instructions from the sender regarding what to do with them. In particular, the sender + # may subsequently send a `Return` for some other call (which the receiver had previously made + # to the sender) with `takeFromOtherQuestion` set. The results from this call are then used + # as the results of the other call. + # + # When `yourself` is used, the receiver must still send a `Return` for the call, but sets the + # field `resultsSentElsewhere` in that `Return` rather than including the results. + # + # This feature can be used to implement tail calls in which a call from Vat A to Vat B ends up + # returning the result of a call from Vat B back to Vat A. + # + # In particular, the most common use case for this feature is when Vat A makes a call to a + # promise in Vat B, and then that promise ends up resolving to a capability back in Vat A. + # Vat B must forward all the queued calls on that promise back to Vat A, but can set `yourself` + # in the calls so that the results need not pass back through Vat B. + # + # For example: + # - Alice, in Vat A, call foo() on Bob in Vat B. + # - Alice makes a pipelined call bar() on the promise returned by foo(). + # - Later on, Bob resolves the promise from foo() to point at Carol, who lives in Vat A (next + # to Alice). + # - Vat B dutifully forwards the bar() call to Carol. Let us call this forwarded call bar'(). + # Notice that bar() and bar'() are travelling in opposite directions on the same network + # link. + # - The `Call` for bar'() has `sendResultsTo` set to `yourself`, with the value being the + # question ID originally assigned to the bar() call. + # - Vat A receives bar'() and delivers it to Carol. + # - When bar'() returns, Vat A immediately takes the results and returns them from bar(). + # - Meanwhile, Vat A sends a `Return` for bar'() to Vat B, with `resultsSentElsewhere` set in + # place of results. + # - Vat A sends a `Finish` for that call to Vat B. + # - Vat B receives the `Return` for bar'() and sends a `Return` for bar(), with + # `receivedFromYourself` set in place of the results. + # - Vat B receives the `Finish` for bar() and sends a `Finish` to bar'(). + + thirdParty @7 :RecipientId; + # **(level 3)** + # + # The call's result should be returned to a different vat. The receiver (the callee) expects + # to receive an `Accept` message from the indicated vat, and should return the call's result + # to it, rather than to the sender of the `Call`. + # + # This operates much like `yourself`, above, except that Carol is in a separate Vat C. `Call` + # messages are sent from Vat A -> Vat B and Vat B -> Vat C. A `Return` message is sent from + # Vat B -> Vat A that contains `acceptFromThirdParty` in place of results. When Vat A sends + # an `Accept` to Vat C, it receives back a `Return` containing the call's actual result. Vat C + # also sends a `Return` to Vat B with `resultsSentElsewhere`. + } +} + +struct Return { + # **(level 0)** + # + # Message type sent from callee to caller indicating that the call has completed. + + answerId @0 :AnswerId; + # Equal to the QuestionId of the corresponding `Call` message. + + releaseParamCaps @1 :Bool = true; + # If true, all capabilities that were in the params should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # to set it to false they'll quickly get errors. + + union { + results @2 :Payload; + # The result. + # + # For regular method calls, `results.content` points to the result struct. + # + # For a `Return` in response to an `Accept`, `results` contains a single capability (rather + # than a struct), and `results.content` is just a capability pointer with index 0. A `Finish` + # is still required in this case. + + exception @3 :Exception; + # Indicates that the call failed and explains why. + + canceled @4 :Void; + # Indicates that the call was canceled due to the caller sending a Finish message + # before the call had completed. + + resultsSentElsewhere @5 :Void; + # This is set when returning from a `Call` that had `sendResultsTo` set to something other + # than `caller`. + + takeFromOtherQuestion @6 :QuestionId; + # The sender has also sent (before this message) a `Call` with the given question ID and with + # `sendResultsTo.yourself` set, and the results of that other call should be used as the + # results here. + + acceptFromThirdParty @7 :ThirdPartyCapId; + # **(level 3)** + # + # The caller should contact a third-party vat to pick up the results. An `Accept` message + # sent to the vat will return the result. This pairs with `Call.sendResultsTo.thirdParty`. + # It should only be used if the corresponding `Call` had `allowThirdPartyTailCall` set. + } +} + +struct Finish { + # **(level 0)** + # + # Message type sent from the caller to the callee to indicate: + # 1) The questionId will no longer be used in any messages sent by the callee (no further + # pipelined requests). + # 2) If the call has not returned yet, the caller no longer cares about the result. If nothing + # else cares about the result either (e.g. there are no other outstanding calls pipelined on + # the result of this one) then the callee may wish to immediately cancel the operation and + # send back a Return message with "canceled" set. However, implementations are not required + # to support premature cancellation -- instead, the implementation may wait until the call + # actually completes and send a normal `Return` message. + # + # TODO(someday): Should we separate (1) and implicitly releasing result capabilities? It would be + # possible and useful to notify the server that it doesn't need to keep around the response to + # service pipeline requests even though the caller still wants to receive it / hasn't yet + # finished processing it. It could also be useful to notify the server that it need not marshal + # the results because the caller doesn't want them anyway, even if the caller is still sending + # pipelined calls, although this seems less useful (just saving some bytes on the wire). + + questionId @0 :QuestionId; + # ID of the call whose result is to be released. + + releaseResultCaps @1 :Bool = true; + # If true, all capabilities that were in the results should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # set it false they'll quickly get errors. +} + +# Level 1 message types ---------------------------------------------- + +struct Resolve { + # **(level 1)** + # + # Message type sent to indicate that a previously-sent promise has now been resolved to some other + # object (possibly another promise) -- or broken, or canceled. + # + # Keep in mind that it's possible for a `Resolve` to be sent to a level 0 implementation that + # doesn't implement it. For example, a method call or return might contain a capability in the + # payload. Normally this is fine even if the receiver is level 0, because they will implicitly + # release all such capabilities on return / finish. But if the cap happens to be a promise, then + # a follow-up `Resolve` may be sent regardless of this release. The level 0 receiver will reply + # with an `unimplemented` message, and the sender (of the `Resolve`) can respond to this as if the + # receiver had immediately released any capability to which the promise resolved. + # + # When implementing promise resolution, it's important to understand how embargos work and the + # tricky case of the Tribble 4-way race condition. See the comments for the Disembargo message, + # below. + + promiseId @0 :ExportId; + # The ID of the promise to be resolved. + # + # Unlike all other instances of `ExportId` sent from the exporter, the `Resolve` message does + # _not_ increase the reference count of `promiseId`. In fact, it is expected that the receiver + # will release the export soon after receiving `Resolve`, and the sender will not send this + # `ExportId` again until it has been released and recycled. + # + # When an export ID sent over the wire (e.g. in a `CapDescriptor`) is indicated to be a promise, + # this indicates that the sender will follow up at some point with a `Resolve` message. If the + # same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the + # same ID is sent again later _after_ a `Resolve`, it can only be because the export's + # reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore + # this later promise does _not_ correspond to the earlier `Resolve`. + # + # If a promise ID's reference count reaches zero before a `Resolve` is sent, the `Resolve` + # message may or may not still be sent (the `Resolve` may have already been in-flight when + # `Release` was sent, but if the `Release` is received before `Resolve` then there is no longer + # any reason to send a `Resolve`). Thus a `Resolve` may be received for a promise of which + # the receiver has no knowledge, because it already released it earlier. In this case, the + # receiver should simply release the capability to which the promise resolved. + + union { + cap @1 :CapDescriptor; + # The object to which the promise resolved. + # + # The sender promises that from this point forth, until `promiseId` is released, it shall + # simply forward all messages to the capability designated by `cap`. This is true even if + # `cap` itself happens to desigate another promise, and that other promise later resolves -- + # messages sent to `promiseId` shall still go to that other promise, not to its resolution. + # This is important in the case that the receiver of the `Resolve` ends up sending a + # `Disembargo` message towards `promiseId` in order to control message ordering -- that + # `Disembargo` really needs to reflect back to exactly the object designated by `cap` even + # if that object is itself a promise. + + exception @2 :Exception; + # Indicates that the promise was broken. + } +} + +struct Release { + # **(level 1)** + # + # Message type sent to indicate that the sender is done with the given capability and the receiver + # can free resources allocated to it. + + id @0 :ImportId; + # What to release. + + referenceCount @1 :UInt32; + # The amount by which to decrement the reference count. The export is only actually released + # when the reference count reaches zero. +} + +struct Disembargo { + # **(level 1)** + # + # Message sent to indicate that an embargo on a recently-resolved promise may now be lifted. + # + # Embargos are used to enforce E-order in the presence of promise resolution. That is, if an + # application makes two calls foo() and bar() on the same capability reference, in that order, + # the calls should be delivered in the order in which they were made. But if foo() is called + # on a promise, and that promise happens to resolve before bar() is called, then the two calls + # may travel different paths over the network, and thus could arrive in the wrong order. In + # this case, the call to `bar()` must be embargoed, and a `Disembargo` message must be sent along + # the same path as `foo()` to ensure that the `Disembargo` arrives after `foo()`. Once the + # `Disembargo` arrives, `bar()` can then be delivered. + # + # There are two particular cases where embargos are important. Consider object Alice, in Vat A, + # who holds a promise P, pointing towards Vat B, that eventually resolves to Carol. The two + # cases are: + # - Carol lives in Vat A, i.e. next to Alice. In this case, Vat A needs to send a `Disembargo` + # message that echos through Vat B and back, to ensure that all pipelined calls on the promise + # have been delivered. + # - Carol lives in a different Vat C. When the promise resolves, a three-party handoff occurs + # (see `Provide` and `Accept`, which constitute level 3 of the protocol). In this case, we + # piggyback on the state that has already been set up to handle the handoff: the `Accept` + # message (from Vat A to Vat C) is embargoed, as are all pipelined messages sent to it, while + # a `Disembargo` message is sent from Vat A through Vat B to Vat C. See `Accept.embargo` for + # an example. + # + # Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise + # already pointed at), no embargo is needed, because the pipelined calls are delivered over the + # same path as the later direct calls. + # + # Keep in mind that promise resolution happens both in the form of Resolve messages as well as + # Return messages (which resolve PromisedAnswers). Embargos apply in both cases. + # + # An alternative strategy for enforcing E-order over promise resolution could be for Vat A to + # implement the embargo internally. When Vat A is notified of promise resolution, it could + # send a dummy no-op call to promise P and wait for it to complete. Until that call completes, + # all calls to the capability are queued locally. This strategy works, but is pessimistic: + # in the three-party case, it requires an A -> B -> C -> B -> A round trip before calls can start + # being delivered directly to from Vat A to Vat C. The `Disembargo` message allows latency to be + # reduced. (In the two-party loopback case, the `Disembargo` message is just a more explicit way + # of accomplishing the same thing as a no-op call, but isn't any faster.) + # + # *The Tribble 4-way Race Condition* + # + # Any implementation of promise resolution and embargos must be aware of what we call the + # "Tribble 4-way race condition", after Dean Tribble, who explained the problem in a lively + # Friam meeting. + # + # Embargos are designed to work in the case where a two-hop path is being shortened to one hop. + # But sometimes there are more hops. Imagine that Alice has a reference to a remote promise P1 + # that eventually resolves to _another_ remote promise P2 (in a third vat), which _at the same + # time_ happens to resolve to Bob (in a fourth vat). In this case, we're shortening from a 3-hop + # path (with four parties) to a 1-hop path (Alice -> Bob). + # + # Extending the embargo/disembargo protocol to be able to shorted multiple hops at once seems + # difficult. Instead, we make a rule that prevents this case from coming up: + # + # One a promise P has been resolved to a remove object reference R, then all further messages + # received addressed to P will be forwarded strictly to R. Even if it turns out later that R is + # itself a promise, and has resolved to some other object Q, messages sent to P will still be + # forwarded to R, not directly to Q (R will of course further forward the messages to Q). + # + # This rule does not cause a significant performance burden because once P has resolved to R, it + # is expected that people sending messages to P will shortly start sending them to R instead and + # drop P. P is at end-of-life anyway, so it doesn't matter if it ignores chances to further + # optimize its path. + + target @0 :MessageTarget; + # What is to be disembargoed. + + using EmbargoId = UInt32; + # Used in `senderLoopback` and `receiverLoopback`, below. + + context :union { + senderLoopback @1 :EmbargoId; + # The sender is requesting a disembargo on a promise that is known to resolve back to a + # capability hosted by the sender. As soon as the receiver has echoed back all pipelined calls + # on this promise, it will deliver the Disembargo back to the sender with `receiverLoopback` + # set to the same value as `senderLoopback`. This value is chosen by the sender, and since + # it is also consumed be the sender, the sender can use whatever strategy it wants to make sure + # the value is unambiguous. + # + # The receiver must verify that the target capability actually resolves back to the sender's + # vat. Otherwise, the sender has committed a protocol error and should be disconnected. + + receiverLoopback @2 :EmbargoId; + # The receiver previously sent a `senderLoopback` Disembargo towards a promise resolving to + # this capability, and that Disembargo is now being echoed back. + + accept @3 :Void; + # **(level 3)** + # + # The sender is requesting a disembargo on a promise that is known to resolve to a third-party + # capability that the sender is currently in the process of accepting (using `Accept`). + # The receiver of this `Disembargo` has an outstanding `Provide` on said capability. The + # receiver should now send a `Disembargo` with `provide` set to the question ID of that + # `Provide` message. + # + # See `Accept.embargo` for an example. + + provide @4 :QuestionId; + # **(level 3)** + # + # The sender is requesting a disembargo on a capability currently being provided to a third + # party. The question ID identifies the `Provide` message previously sent by the sender to + # this capability. On receipt, the receiver (the capability host) shall release the embargo + # on the `Accept` message that it has received from the third party. See `Accept.embargo` for + # an example. + } +} + +# Level 2 message types ---------------------------------------------- + +# See persistent.capnp. + +# Level 3 message types ---------------------------------------------- + +struct Provide { + # **(level 3)** + # + # Message type sent to indicate that the sender wishes to make a particular capability implemented + # by the receiver available to a third party for direct access (without the need for the third + # party to proxy through the sender). + # + # (In CapTP, `Provide` and `Accept` are methods of the global `NonceLocator` object exported by + # every vat. In Cap'n Proto, we bake this into the core protocol.) + + questionId @0 :QuestionId; + # Question ID to be held open until the recipient has received the capability. A result will be + # returned once the third party has successfully received the capability. The sender must at some + # point send a `Finish` message as with any other call, and that message can be used to cancel the + # whole operation. + + target @1 :MessageTarget; + # What is to be provided to the third party. + + recipient @2 :RecipientId; + # Identity of the third party that is expected to pick up the capability. +} + +struct Accept { + # **(level 3)** + # + # Message type sent to pick up a capability hosted by the receiving vat and provided by a third + # party. The third party previously designated the capability using `Provide`. + # + # This message is also used to pick up a redirected return -- see `Return.redirect`. + + questionId @0 :QuestionId; + # A new question ID identifying this accept message, which will eventually receive a Return + # message containing the provided capability (or the call result in the case of a redirected + # return). + + provision @1 :ProvisionId; + # Identifies the provided object to be picked up. + + embargo @2 :Bool; + # If true, this accept shall be temporarily embargoed. The resulting `Return` will not be sent, + # and any pipelined calls will not be delivered, until the embargo is released. The receiver + # (the capability host) will expect the provider (the vat that sent the `Provide` message) to + # eventually send a `Disembargo` message with the field `context.provide` set to the question ID + # of the original `Provide` message. At that point, the embargo is released and the queued + # messages are delivered. + # + # For example: + # - Alice, in Vat A, holds a promise P, which currently points toward Vat B. + # - Alice calls foo() on P. The `Call` message is sent to Vat B. + # - The promise P in Vat B ends up resolving to Carol, in Vat C. + # - Vat B sends a `Provide` message to Vat C, identifying Vat A as the recipient. + # - Vat B sends a `Resolve` message to Vat A, indicating that the promise has resolved to a + # `ThirdPartyCapId` identifying Carol in Vat C. + # - Vat A sends an `Accept` message to Vat C to pick up the capability. Since Vat A knows that + # it has an outstanding call to the promise, it sets `embargo` to `true` in the `Accept` + # message. + # - Vat A sends a `Disembargo` message to Vat B on promise P, with `context.accept` set. + # - Alice makes a call bar() to promise P, which is now pointing towards Vat C. Alice doesn't + # know anything about the mechanics of promise resolution happening under the hood, but she + # expects that bar() will be delivered after foo() because that is the order in which she + # initiated the calls. + # - Vat A sends the bar() call to Vat C, as a pipelined call on the result of the `Accept` (which + # hasn't returned yet, due to the embargo). Since calls to the newly-accepted capability + # are embargoed, Vat C does not deliver the call yet. + # - At some point, Vat B forwards the foo() call from the beginning of this example on to Vat C. + # - Vat B forwards the `Disembargo` from Vat A on to vat C. It sets `context.provide` to the + # question ID of the `Provide` message it had sent previously. + # - Vat C receives foo() before `Disembargo`, thus allowing it to correctly deliver foo() + # before delivering bar(). + # - Vat C receives `Disembargo` from Vat B. It can now send a `Return` for the `Accept` from + # Vat A, as well as deliver bar(). +} + +# Level 4 message types ---------------------------------------------- + +struct Join { + # **(level 4)** + # + # Message type sent to implement E.join(), which, given a number of capabilities that are + # expected to be equivalent, finds the underlying object upon which they all agree and forms a + # direct connection to it, skipping any proxies that may have been constructed by other vats + # while transmitting the capability. See: + # http://erights.org/elib/equality/index.html + # + # Note that this should only serve to bypass fully-transparent proxies -- proxies that were + # created merely for convenience, without any intention of hiding the underlying object. + # + # For example, say Bob holds two capabilities hosted by Alice and Carol, but he expects that both + # are simply proxies for a capability hosted elsewhere. He then issues a join request, which + # operates as follows: + # - Bob issues Join requests on both Alice and Carol. Each request contains a different piece + # of the JoinKey. + # - Alice is proxying a capability hosted by Dana, so forwards the request to Dana's cap. + # - Dana receives the first request and sees that the JoinKeyPart is one of two. She notes that + # she doesn't have the other part yet, so she records the request and responds with a + # JoinResult. + # - Alice relays the JoinAswer back to Bob. + # - Carol is also proxying a capability from Dana, and so forwards her Join request to Dana as + # well. + # - Dana receives Carol's request and notes that she now has both parts of a JoinKey. She + # combines them in order to form information needed to form a secure connection to Bob. She + # also responds with another JoinResult. + # - Bob receives the responses from Alice and Carol. He uses the returned JoinResults to + # determine how to connect to Dana and attempts to form the connection. Since Bob and Dana now + # agree on a secret key that neither Alice nor Carol ever saw, this connection can be made + # securely even if Alice or Carol is conspiring against the other. (If Alice and Carol are + # conspiring _together_, they can obviously reproduce the key, but this doesn't matter because + # the whole point of the join is to verify that Alice and Carol agree on what capability they + # are proxying.) + # + # If the two capabilities aren't actually proxies of the same object, then the join requests + # will come back with conflicting `hostId`s and the join will fail before attempting to form any + # connection. + + questionId @0 :QuestionId; + # Question ID used to respond to this Join. (Note that this ID only identifies one part of the + # request for one hop; each part has a different ID and relayed copies of the request have + # (probably) different IDs still.) + # + # The receiver will reply with a `Return` whose `results` is a JoinResult. This `JoinResult` + # is relayed from the joined object's host, possibly with transformation applied as needed + # by the network. + # + # Like any return, the result must be released using a `Finish`. However, this release + # should not occur until the joiner has either successfully connected to the joined object. + # Vats relaying a `Join` message similarly must not release the result they receive until the + # return they relayed back towards the joiner has itself been released. This allows the + # joined object's host to detect when the Join operation is canceled before completing -- if + # it receives a `Finish` for one of the join results before the joiner successfully + # connects. It can then free any resources it had allocated as part of the join. + + target @1 :MessageTarget; + # The capability to join. + + keyPart @2 :JoinKeyPart; + # A part of the join key. These combine to form the complete join key, which is used to establish + # a direct connection. + + # TODO(before implementing): Change this so that multiple parts can be sent in a single Join + # message, so that if multiple join parts are going to cross the same connection they can be sent + # together, so that the receive can potentially optimize its handling of them. In the case where + # all parts are bundled together, should the recipient be expected to simply return a cap, so + # that the caller can immediately start pipelining to it? +} + +# ======================================================================================== +# Common structures used in messages + +struct MessageTarget { + # The target of a `Call` or other messages that target a capability. + + union { + importedCap @0 :ImportId; + # This message is to a capability or promise previously imported by the caller (exported by + # the receiver). + + promisedAnswer @1 :PromisedAnswer; + # This message is to a capability that is expected to be returned by another call that has not + # yet been completed. + # + # At level 0, this is supported only for addressing the result of a previous `Bootstrap`, so + # that initial startup doesn't require a round trip. + } +} + +struct Payload { + # Represents some data structure that might contain capabilities. + + content @0 :AnyPointer; + # Some Cap'n Proto data structure. Capability pointers embedded in this structure index into + # `capTable`. + + capTable @1 :List(CapDescriptor); + # Descriptors corresponding to the cap pointers in `content`. +} + +struct CapDescriptor { + # **(level 1)** + # + # When an application-defined type contains an interface pointer, that pointer contains an index + # into the message's capability table -- i.e. the `capTable` part of the `Payload`. Each + # capability in the table is represented as a `CapDescriptor`. The runtime API should not reveal + # the CapDescriptor directly to the application, but should instead wrap it in some kind of + # callable object with methods corresponding to the interface that the capability implements. + # + # Keep in mind that `ExportIds` in a `CapDescriptor` are subject to reference counting. See the + # description of `ExportId`. + + union { + none @0 :Void; + # There is no capability here. This `CapDescriptor` should not appear in the payload content. + # A `none` CapDescriptor can be generated when an application inserts a capability into a + # message and then later changes its mind and removes it -- rewriting all of the other + # capability pointers may be hard, so instead a tombstone is left, similar to the way a removed + # struct or list instance is zeroed out of the message but the space is not reclaimed. + # Hopefully this is unusual. + + senderHosted @1 :ExportId; + # A capability newly exported by the sender. This is the ID of the new capability in the + # sender's export table (receiver's import table). + + senderPromise @2 :ExportId; + # A promise that the sender will resolve later. The sender will send exactly one Resolve + # message at a future point in time to replace this promise. Note that even if the same + # `senderPromise` is received multiple times, only one `Resolve` is sent to cover all of + # them. If `senderPromise` is released before the `Resolve` is sent, the sender (of this + # `CapDescriptor`) may choose not to send the `Resolve` at all. + + receiverHosted @3 :ImportId; + # A capability (or promise) previously exported by the receiver (imported by the sender). + + receiverAnswer @4 :PromisedAnswer; + # A capability expected to be returned in the results of a currently-outstanding call posed + # by the sender. + + thirdPartyHosted @5 :ThirdPartyCapDescriptor; + # **(level 3)** + # + # A capability that lives in neither the sender's nor the receiver's vat. The sender needs + # to form a direct connection to a third party to pick up the capability. + # + # Level 1 and 2 implementations that receive a `thirdPartyHosted` may simply send calls to its + # `vine` instead. + } +} + +struct PromisedAnswer { + # **(mostly level 1)** + # + # Specifies how to derive a promise from an unanswered question, by specifying the path of fields + # to follow from the root of the eventual result struct to get to the desired capability. Used + # to address method calls to a not-yet-returned capability or to pass such a capability as an + # input to some other method call. + # + # Level 0 implementations must support `PromisedAnswer` only for the case where the answer is + # to a `Bootstrap` message. In this case, `path` is always empty since `Bootstrap` always returns + # a raw capability. + + questionId @0 :QuestionId; + # ID of the question (in the sender's question table / receiver's answer table) whose answer is + # expected to contain the capability. + + transform @1 :List(Op); + # Operations / transformations to apply to the result in order to get the capability actually + # being addressed. E.g. if the result is a struct and you want to call a method on a capability + # pointed to by a field of the struct, you need a `getPointerField` op. + + struct Op { + union { + noop @0 :Void; + # Does nothing. This member is mostly defined so that we can make `Op` a union even + # though (as of this writing) only one real operation is defined. + + getPointerField @1 :UInt16; + # Get a pointer field within a struct. The number is an index into the pointer section, NOT + # a field ordinal, so that the receiver does not need to understand the schema. + + # TODO(someday): We could add: + # - For lists, the ability to address every member of the list, or a slice of the list, the + # result of which would be another list. This is useful for implementing the equivalent of + # a SQL table join (not to be confused with the `Join` message type). + # - Maybe some ability to test a union. + # - Probably not a good idea: the ability to specify an arbitrary script to run on the + # result. We could define a little stack-based language where `Op` specifies one + # "instruction" or transformation to apply. Although this is not a good idea + # (over-engineered), any narrower additions to `Op` should be designed as if this + # were the eventual goal. + } + } +} + +struct ThirdPartyCapDescriptor { + # **(level 3)** + # + # Identifies a capability in a third-party vat that the sender wants the receiver to pick up. + + id @0 :ThirdPartyCapId; + # Identifies the third-party host and the specific capability to accept from it. + + vineId @1 :ExportId; + # A proxy for the third-party object exported by the sender. In CapTP terminology this is called + # a "vine", because it is an indirect reference to the third-party object that snakes through the + # sender vat. This serves two purposes: + # + # * Level 1 and 2 implementations that don't understand how to connect to a third party may + # simply send calls to the vine. Such calls will be forwarded to the third-party by the + # sender. + # + # * Level 3 implementations must release the vine once they have successfully picked up the + # object from the third party. This ensures that the capability is not released by the sender + # prematurely. + # + # The sender will close the `Provide` request that it has sent to the third party as soon as + # it receives either a `Call` or a `Release` message directed at the vine. +} + +struct Exception { + # **(level 0)** + # + # Describes an arbitrary error that prevented an operation (e.g. a call) from completing. + # + # Cap'n Proto exceptions always indicate that something went wrong. In other words, in a fantasy + # world where everything always works as expected, no exceptions would ever be thrown. Clients + # should only ever catch exceptions as a means to implement fault-tolerance, where "fault" can + # mean: + # - Bugs. + # - Invalid input. + # - Configuration errors. + # - Network problems. + # - Insufficient resources. + # - Version skew (unimplemented functionality). + # - Other logistical problems. + # + # Exceptions should NOT be used to flag application-specific conditions that a client is expected + # to handle in an application-specific way. Put another way, in the Cap'n Proto world, + # "checked exceptions" (where an interface explicitly defines the exceptions it throws and + # clients are forced by the type system to handle those exceptions) do NOT make sense. + + reason @0 :Text; + # Human-readable failure description. + + type @3 :Type; + # The type of the error. The purpose of this enum is not to describe the error itself, but + # rather to describe how the client might want to respond to the error. + + enum Type { + failed @0; + # A generic problem occurred, and it is believed that if the operation were repeated without + # any change in the state of the world, the problem would occur again. + # + # A client might respond to this error by logging it for investigation by the developer and/or + # displaying it to the user. + + overloaded @1; + # The request was rejected due to a temporary lack of resources. + # + # Examples include: + # - There's not enough CPU time to keep up with incoming requests, so some are rejected. + # - The server ran out of RAM or disk space during the request. + # - The operation timed out (took significantly longer than it should have). + # + # A client might respond to this error by scheduling to retry the operation much later. The + # client should NOT retry again immediately since this would likely exacerbate the problem. + + disconnected @2; + # The method failed because a connection to some necessary capability was lost. + # + # Examples include: + # - The client introduced the server to a third-party capability, the connection to that third + # party was subsequently lost, and then the client requested that the server use the dead + # capability for something. + # - The client previously requested that the server obtain a capability from some third party. + # The server returned a capability to an object wrapping the third-party capability. Later, + # the server's connection to the third party was lost. + # - The capability has been revoked. Revocation does not necessarily mean that the client is + # no longer authorized to use the capability; it is often used simply as a way to force the + # client to repeat the setup process, perhaps to efficiently move them to a new back-end or + # get them to recognize some other change that has occurred. + # + # A client should normally respond to this error by releasing all capabilities it is currently + # holding related to the one it called and then re-creating them by restoring SturdyRefs and/or + # repeating the method calls used to create them originally. In other words, disconnect and + # start over. This should in turn cause the server to obtain a new copy of the capability that + # it lost, thus making everything work. + # + # If the client receives another `disconnencted` error in the process of rebuilding the + # capability and retrying the call, it should treat this as an `overloaded` error: the network + # is currently unreliable, possibly due to load or other temporary issues. + + unimplemented @3; + # The server doesn't implement the requested method. If there is some other method that the + # client could call (perhaps an older and/or slower interface), it should try that instead. + # Otherwise, this should be treated like `failed`. + } + + obsoleteIsCallersFault @1 :Bool; + # OBSOLETE. Ignore. + + obsoleteDurability @2 :UInt16; + # OBSOLETE. See `type` instead. +} + +# ======================================================================================== +# Network-specific Parameters +# +# Some parts of the Cap'n Proto RPC protocol are not specified here because different vat networks +# may wish to use different approaches to solving them. For example, on the public internet, you +# may want to authenticate vats using public-key cryptography, but on a local intranet with trusted +# infrastructure, you may be happy to authenticate based on network address only, or some other +# lightweight mechanism. +# +# To accommodate this, we specify several "parameter" types. Each type is defined here as an +# alias for `AnyPointer`, but a specific network will want to define a specific set of types to use. +# All vats in a vat network must agree on these parameters in order to be able to communicate. +# Inter-network communication can be accomplished through "gateways" that perform translation +# between the primitives used on each network; these gateways may need to be deeply stateful, +# depending on the translations they perform. +# +# For interaction over the global internet between parties with no other prior arrangement, a +# particular set of bindings for these types is defined elsewhere. (TODO(someday): Specify where +# these common definitions live.) +# +# Another common network type is the two-party network, in which one of the parties typically +# interacts with the outside world entirely through the other party. In such a connection between +# Alice and Bob, all objects that exist on Bob's other networks appear to Alice as if they were +# hosted by Bob himself, and similarly all objects on Alice's network (if she even has one) appear +# to Bob as if they were hosted by Alice. This network type is interesting because from the point +# of view of a simple application that communicates with only one other party via the two-party +# protocol, there are no three-party interactions at all, and joins are unusually simple to +# implement, so implementing at level 4 is barely more complicated than implementing at level 1. +# Moreover, if you pair an app implementing the two-party network with a container that implements +# some other network, the app can then participate on the container's network just as if it +# implemented that network directly. The types used by the two-party network are defined in +# `rpc-twoparty.capnp`. +# +# The things that we need to parameterize are: +# - How to store capabilities long-term without holding a connection open (mostly level 2). +# - How to authenticate vats in three-party introductions (level 3). +# - How to implement `Join` (level 4). +# +# Persistent references +# --------------------- +# +# **(mostly level 2)** +# +# We want to allow some capabilities to be stored long-term, even if a connection is lost and later +# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't +# help here. We need a way to specify long-term identifiers, as well as a strategy for +# reconnecting to a referenced capability later. +# +# Three-party interactions +# ------------------------ +# +# **(level 3)** +# +# In cases where more than two vats are interacting, we have situations where VatA holds a +# capability hosted by VatB and wants to send that capability to VatC. This can be accomplished +# by VatA proxying requests on the new capability, but doing so has two big problems: +# - It's inefficient, requiring an extra network hop. +# - If VatC receives another capability to the same object from VatD, it is difficult for VatC to +# detect that the two capabilities are really the same and to implement the E "join" operation, +# which is necessary for certain four-or-more-party interactions, such as the escrow pattern. +# See: http://www.erights.org/elib/equality/grant-matcher/index.html +# +# Instead, we want a way for VatC to form a direct, authenticated connection to VatB. +# +# Join +# ---- +# +# **(level 4)** +# +# The `Join` message type and corresponding operation arranges for a direct connection to be formed +# between the joiner and the host of the joined object, and this connection must be authenticated. +# Thus, the details are network-dependent. + +using SturdyRef = AnyPointer; +# **(level 2)** +# +# Identifies a persisted capability that can be restored in the future. How exactly a SturdyRef +# is restored to a live object is specified along with the SturdyRef definition (i.e. not by +# rpc.capnp). +# +# Generally a SturdyRef needs to specify three things: +# - How to reach the vat that can restore the ref (e.g. a hostname or IP address). +# - How to authenticate the vat after connecting (e.g. a public key fingerprint). +# - The identity of a specific object hosted by the vat. Generally, this is an opaque pointer whose +# format is defined by the specific vat -- the client has no need to inspect the object ID. +# It is important that the objec ID be unguessable if the object is not public (and objects +# should almost never be public). +# +# The above are only suggestions. Some networks might work differently. For example, a private +# network might employ a special restorer service whose sole purpose is to restore SturdyRefs. +# In this case, the entire contents of SturdyRef might be opaque, because they are intended only +# to be forwarded to the restorer service. + +using ProvisionId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in an `Accept` message to identify the object being accepted. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the provider vat along with the question ID used in the `Provide` message sent from +# that provider. + +using RecipientId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in a `Provide` message to identify the recipient of the +# capability. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the recipient. (CapTP also calls for a nonce to identify the object. In our +# case, the `Provide` message's `questionId` can serve as the nonce.) + +using ThirdPartyCapId = AnyPointer; +# **(level 3)** +# +# The information needed to connect to a third party and accept a capability from it. +# +# In a network where each vat has a public/private key pair, this could be a combination of the +# third party's public key fingerprint, hints on how to connect to the third party (e.g. an IP +# address), and the question ID used in the corresponding `Provide` message sent to that third party +# (used to identify which capability to pick up). + +using JoinKeyPart = AnyPointer; +# **(level 4)** +# +# A piece of a secret key. One piece is sent along each path that is expected to lead to the same +# place. Once the pieces are combined, a direct connection may be formed between the sender and +# the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type. +# +# The motivation for Joins is discussed under "Supporting Equality" in the "Unibus" protocol +# sketch: http://www.erights.org/elib/distrib/captp/unibus.html +# +# In a network where each vat has a public/private key pair and each vat forms no more than one +# connection to each other vat, Joins will rarely -- perhaps never -- be needed, as objects never +# need to be transparently proxied and references to the same object sent over the same connection +# have the same export ID. Thus, a successful join requires only checking that the two objects +# come from the same connection and have the same ID, and then completes immediately. +# +# However, in networks where two vats may form more than one connection between each other, or +# where proxying of objects occurs, joins are necessary. +# +# Typically, each JoinKeyPart would include a fixed-length data value such that all value parts +# XOR'd together forms a shared secret that can be used to form an encrypted connection between +# the joiner and the joined object's host. Each JoinKeyPart should also include an indication of +# how many parts to expect and a hash of the shared secret (used to match up parts). + +using JoinResult = AnyPointer; +# **(level 4)** +# +# Information returned as the result to a `Join` message, needed by the joiner in order to form a +# direct connection to a joined object. This might simply be the address of the joined object's +# host vat, since the `JoinKey` has already been communicated so the two vats already have a shared +# secret to use to authenticate each other. +# +# The `JoinResult` should also contain information that can be used to detect when the Join +# requests ended up reaching different objects, so that this situation can be detected easily. +# This could be a simple matter of including a sequence number -- if the joiner receives two +# `JoinResult`s with sequence number 0, then they must have come from different objects and the +# whole join is a failure. + +# ======================================================================================== +# Network interface sketch +# +# The interfaces below are meant to be pseudo-code to illustrate how the details of a particular +# vat network might be abstracted away. They are written like Cap'n Proto interfaces, but in +# practice you'd probably define these interfaces manually in the target programming language. A +# Cap'n Proto RPC implementation should be able to use these interfaces without knowing the +# definitions of the various network-specific parameters defined above. + +# interface VatNetwork { +# # Represents a vat network, with the ability to connect to particular vats and receive +# # connections from vats. +# # +# # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the +# # caller is expected to find and share state with existing users of the connection. +# +# # Level 0 features ----------------------------------------------- +# +# connect(vatId :VatId) :Connection; +# # Connect to the given vat. The transport should return a promise that does not +# # resolve until authentication has completed, but allows messages to be pipelined in before +# # that; the transport either queues these messages until authenticated, or sends them encrypted +# # such that only the authentic vat would be able to decrypt them. The latter approach avoids a +# # round trip for authentication. +# +# accept() :Connection; +# # Wait for the next incoming connection and return it. Only connections formed by +# # connect() are returned by this method. +# +# # Level 4 features ----------------------------------------------- +# +# newJoiner(count :UInt32) :NewJoinerResponse; +# # Prepare a new Join operation, which will eventually lead to forming a new direct connection +# # to the host of the joined capability. `count` is the number of capabilities to join. +# +# struct NewJoinerResponse { +# joinKeyParts :List(JoinKeyPart); +# # Key parts to send in Join messages to each capability. +# +# joiner :Joiner; +# # Used to establish the final connection. +# } +# +# interface Joiner { +# addJoinResult(result :JoinResult) :Void; +# # Add a JoinResult received in response to one of the `Join` messages. All `JoinResult`s +# # returned from all paths must be added before trying to connect. +# +# connect() :ConnectionAndProvisionId; +# # Try to form a connection to the joined capability's host, verifying that it has received +# # all of the JoinKeyParts. Once the connection is formed, the caller should send an `Accept` +# # message on it with the specified `ProvisionId` in order to receive the final capability. +# } +# +# acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath)) +# :ConnectionAndProvisionId; +# # Called on a joined capability's host to receive the connection from the joiner, once all +# # key parts have arrived. The caller should expect to receive an `Accept` message over the +# # connection with the given ProvisionId. +# } +# +# interface Connection { +# # Level 0 features ----------------------------------------------- +# +# send(message :Message) :Void; +# # Send the message. Returns successfully when the message (and all preceding messages) has +# # been acknowledged by the recipient. +# +# receive() :Message; +# # Receive the next message, and acknowledges receipt to the sender. Messages are received in +# # the order in which they are sent. +# +# # Level 3 features ----------------------------------------------- +# +# introduceTo(recipient :Connection) :IntroductionInfo; +# # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on +# # this connection and a `ThirdPartyCapId` is to be sent to `recipient`. +# +# struct IntroductionInfo { +# sendToRecipient :ThirdPartyCapId; +# sendToTarget :RecipientId; +# } +# +# connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId; +# # Given a ThirdPartyCapId received over this connection, connect to the third party. The +# # caller should then send an `Accept` message over the new connection. +# +# acceptIntroducedConnection(recipientId :RecipientId) :Connection; +# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the +# # recipient to connect, and return the connection formed. Usually, the first message received +# # on the new connection will be an `Accept` message. +# } +# +# struct ConnectionAndProvisionId { +# # **(level 3)** +# +# connection :Connection; +# # Connection on which to issue `Accept` message. +# +# provision :ProvisionId; +# # `ProvisionId` to send in the `Accept` message. +# } diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc.capnp.h --- a/osx/include/capnp/rpc.capnp.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -1,4808 +1,4898 @@ -// Generated by Cap'n Proto compiler, DO NOT EDIT -// source: rpc.capnp - -#ifndef CAPNP_INCLUDED_b312981b2552a250_ -#define CAPNP_INCLUDED_b312981b2552a250_ - -#include - -#if CAPNP_VERSION != 6000 -#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." -#endif - - -namespace capnp { -namespace schemas { - -CAPNP_DECLARE_SCHEMA(91b79f1f808db032); -CAPNP_DECLARE_SCHEMA(e94ccf8031176ec4); -CAPNP_DECLARE_SCHEMA(836a53ce789d4cd4); -CAPNP_DECLARE_SCHEMA(dae8b0f61aab5f99); -CAPNP_DECLARE_SCHEMA(9e19b28d3db3573a); -CAPNP_DECLARE_SCHEMA(d37d2eb2c2f80e63); -CAPNP_DECLARE_SCHEMA(bbc29655fa89086e); -CAPNP_DECLARE_SCHEMA(ad1a6c0d7dd07497); -CAPNP_DECLARE_SCHEMA(f964368b0fbd3711); -CAPNP_DECLARE_SCHEMA(d562b4df655bdd4d); -CAPNP_DECLARE_SCHEMA(9c6a046bfbc1ac5a); -CAPNP_DECLARE_SCHEMA(d4c9b56290554016); -CAPNP_DECLARE_SCHEMA(fbe1980490e001af); -CAPNP_DECLARE_SCHEMA(95bc14545813fbc1); -CAPNP_DECLARE_SCHEMA(9a0e61223d96743b); -CAPNP_DECLARE_SCHEMA(8523ddc40b86b8b0); -CAPNP_DECLARE_SCHEMA(d800b1d6cd6f1ca0); -CAPNP_DECLARE_SCHEMA(f316944415569081); -CAPNP_DECLARE_SCHEMA(d37007fde1f0027d); -CAPNP_DECLARE_SCHEMA(d625b7063acf691a); -CAPNP_DECLARE_SCHEMA(b28c96e23f4cbd58); -enum class Type_b28c96e23f4cbd58: uint16_t { - FAILED, - OVERLOADED, - DISCONNECTED, - UNIMPLEMENTED, -}; -CAPNP_DECLARE_ENUM(Type, b28c96e23f4cbd58); - -} // namespace schemas -} // namespace capnp - -namespace capnp { -namespace rpc { - -struct Message { - Message() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - UNIMPLEMENTED, - ABORT, - CALL, - RETURN, - FINISH, - RESOLVE, - RELEASE, - OBSOLETE_SAVE, - BOOTSTRAP, - OBSOLETE_DELETE, - PROVIDE, - ACCEPT, - JOIN, - DISEMBARGO, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(91b79f1f808db032, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Bootstrap { - Bootstrap() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(e94ccf8031176ec4, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Call { - Call() = delete; - - class Reader; - class Builder; - class Pipeline; - struct SendResultsTo; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(836a53ce789d4cd4, 3, 3) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Call::SendResultsTo { - SendResultsTo() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - CALLER, - YOURSELF, - THIRD_PARTY, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(dae8b0f61aab5f99, 3, 3) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Return { - Return() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - RESULTS, - EXCEPTION, - CANCELED, - RESULTS_SENT_ELSEWHERE, - TAKE_FROM_OTHER_QUESTION, - ACCEPT_FROM_THIRD_PARTY, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9e19b28d3db3573a, 2, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Finish { - Finish() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d37d2eb2c2f80e63, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Resolve { - Resolve() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - CAP, - EXCEPTION, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(bbc29655fa89086e, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Release { - Release() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ad1a6c0d7dd07497, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Disembargo { - Disembargo() = delete; - - class Reader; - class Builder; - class Pipeline; - struct Context; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(f964368b0fbd3711, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Disembargo::Context { - Context() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - SENDER_LOOPBACK, - RECEIVER_LOOPBACK, - ACCEPT, - PROVIDE, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d562b4df655bdd4d, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Provide { - Provide() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9c6a046bfbc1ac5a, 1, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Accept { - Accept() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d4c9b56290554016, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Join { - Join() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(fbe1980490e001af, 1, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct MessageTarget { - MessageTarget() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - IMPORTED_CAP, - PROMISED_ANSWER, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(95bc14545813fbc1, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Payload { - Payload() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9a0e61223d96743b, 0, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct CapDescriptor { - CapDescriptor() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - NONE, - SENDER_HOSTED, - SENDER_PROMISE, - RECEIVER_HOSTED, - RECEIVER_ANSWER, - THIRD_PARTY_HOSTED, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(8523ddc40b86b8b0, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct PromisedAnswer { - PromisedAnswer() = delete; - - class Reader; - class Builder; - class Pipeline; - struct Op; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d800b1d6cd6f1ca0, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct PromisedAnswer::Op { - Op() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - NOOP, - GET_POINTER_FIELD, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(f316944415569081, 1, 0) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct ThirdPartyCapDescriptor { - ThirdPartyCapDescriptor() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d37007fde1f0027d, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Exception { - Exception() = delete; - - class Reader; - class Builder; - class Pipeline; - typedef ::capnp::schemas::Type_b28c96e23f4cbd58 Type; - - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d625b7063acf691a, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -// ======================================================================================= - -class Message::Reader { -public: - typedef Message Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isUnimplemented() const; - inline bool hasUnimplemented() const; - inline ::capnp::rpc::Message::Reader getUnimplemented() const; - - inline bool isAbort() const; - inline bool hasAbort() const; - inline ::capnp::rpc::Exception::Reader getAbort() const; - - inline bool isCall() const; - inline bool hasCall() const; - inline ::capnp::rpc::Call::Reader getCall() const; - - inline bool isReturn() const; - inline bool hasReturn() const; - inline ::capnp::rpc::Return::Reader getReturn() const; - - inline bool isFinish() const; - inline bool hasFinish() const; - inline ::capnp::rpc::Finish::Reader getFinish() const; - - inline bool isResolve() const; - inline bool hasResolve() const; - inline ::capnp::rpc::Resolve::Reader getResolve() const; - - inline bool isRelease() const; - inline bool hasRelease() const; - inline ::capnp::rpc::Release::Reader getRelease() const; - - inline bool isObsoleteSave() const; - inline bool hasObsoleteSave() const; - inline ::capnp::AnyPointer::Reader getObsoleteSave() const; - - inline bool isBootstrap() const; - inline bool hasBootstrap() const; - inline ::capnp::rpc::Bootstrap::Reader getBootstrap() const; - - inline bool isObsoleteDelete() const; - inline bool hasObsoleteDelete() const; - inline ::capnp::AnyPointer::Reader getObsoleteDelete() const; - - inline bool isProvide() const; - inline bool hasProvide() const; - inline ::capnp::rpc::Provide::Reader getProvide() const; - - inline bool isAccept() const; - inline bool hasAccept() const; - inline ::capnp::rpc::Accept::Reader getAccept() const; - - inline bool isJoin() const; - inline bool hasJoin() const; - inline ::capnp::rpc::Join::Reader getJoin() const; - - inline bool isDisembargo() const; - inline bool hasDisembargo() const; - inline ::capnp::rpc::Disembargo::Reader getDisembargo() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Message::Builder { -public: - typedef Message Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isUnimplemented(); - inline bool hasUnimplemented(); - inline ::capnp::rpc::Message::Builder getUnimplemented(); - inline void setUnimplemented( ::capnp::rpc::Message::Reader value); - inline ::capnp::rpc::Message::Builder initUnimplemented(); - inline void adoptUnimplemented(::capnp::Orphan< ::capnp::rpc::Message>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Message> disownUnimplemented(); - - inline bool isAbort(); - inline bool hasAbort(); - inline ::capnp::rpc::Exception::Builder getAbort(); - inline void setAbort( ::capnp::rpc::Exception::Reader value); - inline ::capnp::rpc::Exception::Builder initAbort(); - inline void adoptAbort(::capnp::Orphan< ::capnp::rpc::Exception>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Exception> disownAbort(); - - inline bool isCall(); - inline bool hasCall(); - inline ::capnp::rpc::Call::Builder getCall(); - inline void setCall( ::capnp::rpc::Call::Reader value); - inline ::capnp::rpc::Call::Builder initCall(); - inline void adoptCall(::capnp::Orphan< ::capnp::rpc::Call>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Call> disownCall(); - - inline bool isReturn(); - inline bool hasReturn(); - inline ::capnp::rpc::Return::Builder getReturn(); - inline void setReturn( ::capnp::rpc::Return::Reader value); - inline ::capnp::rpc::Return::Builder initReturn(); - inline void adoptReturn(::capnp::Orphan< ::capnp::rpc::Return>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Return> disownReturn(); - - inline bool isFinish(); - inline bool hasFinish(); - inline ::capnp::rpc::Finish::Builder getFinish(); - inline void setFinish( ::capnp::rpc::Finish::Reader value); - inline ::capnp::rpc::Finish::Builder initFinish(); - inline void adoptFinish(::capnp::Orphan< ::capnp::rpc::Finish>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Finish> disownFinish(); - - inline bool isResolve(); - inline bool hasResolve(); - inline ::capnp::rpc::Resolve::Builder getResolve(); - inline void setResolve( ::capnp::rpc::Resolve::Reader value); - inline ::capnp::rpc::Resolve::Builder initResolve(); - inline void adoptResolve(::capnp::Orphan< ::capnp::rpc::Resolve>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Resolve> disownResolve(); - - inline bool isRelease(); - inline bool hasRelease(); - inline ::capnp::rpc::Release::Builder getRelease(); - inline void setRelease( ::capnp::rpc::Release::Reader value); - inline ::capnp::rpc::Release::Builder initRelease(); - inline void adoptRelease(::capnp::Orphan< ::capnp::rpc::Release>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Release> disownRelease(); - - inline bool isObsoleteSave(); - inline bool hasObsoleteSave(); - inline ::capnp::AnyPointer::Builder getObsoleteSave(); - inline ::capnp::AnyPointer::Builder initObsoleteSave(); - - inline bool isBootstrap(); - inline bool hasBootstrap(); - inline ::capnp::rpc::Bootstrap::Builder getBootstrap(); - inline void setBootstrap( ::capnp::rpc::Bootstrap::Reader value); - inline ::capnp::rpc::Bootstrap::Builder initBootstrap(); - inline void adoptBootstrap(::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> disownBootstrap(); - - inline bool isObsoleteDelete(); - inline bool hasObsoleteDelete(); - inline ::capnp::AnyPointer::Builder getObsoleteDelete(); - inline ::capnp::AnyPointer::Builder initObsoleteDelete(); - - inline bool isProvide(); - inline bool hasProvide(); - inline ::capnp::rpc::Provide::Builder getProvide(); - inline void setProvide( ::capnp::rpc::Provide::Reader value); - inline ::capnp::rpc::Provide::Builder initProvide(); - inline void adoptProvide(::capnp::Orphan< ::capnp::rpc::Provide>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Provide> disownProvide(); - - inline bool isAccept(); - inline bool hasAccept(); - inline ::capnp::rpc::Accept::Builder getAccept(); - inline void setAccept( ::capnp::rpc::Accept::Reader value); - inline ::capnp::rpc::Accept::Builder initAccept(); - inline void adoptAccept(::capnp::Orphan< ::capnp::rpc::Accept>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Accept> disownAccept(); - - inline bool isJoin(); - inline bool hasJoin(); - inline ::capnp::rpc::Join::Builder getJoin(); - inline void setJoin( ::capnp::rpc::Join::Reader value); - inline ::capnp::rpc::Join::Builder initJoin(); - inline void adoptJoin(::capnp::Orphan< ::capnp::rpc::Join>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Join> disownJoin(); - - inline bool isDisembargo(); - inline bool hasDisembargo(); - inline ::capnp::rpc::Disembargo::Builder getDisembargo(); - inline void setDisembargo( ::capnp::rpc::Disembargo::Reader value); - inline ::capnp::rpc::Disembargo::Builder initDisembargo(); - inline void adoptDisembargo(::capnp::Orphan< ::capnp::rpc::Disembargo>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Disembargo> disownDisembargo(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Message::Pipeline { -public: - typedef Message Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Bootstrap::Reader { -public: - typedef Bootstrap Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasDeprecatedObjectId() const; - inline ::capnp::AnyPointer::Reader getDeprecatedObjectId() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Bootstrap::Builder { -public: - typedef Bootstrap Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasDeprecatedObjectId(); - inline ::capnp::AnyPointer::Builder getDeprecatedObjectId(); - inline ::capnp::AnyPointer::Builder initDeprecatedObjectId(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Bootstrap::Pipeline { -public: - typedef Bootstrap Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Call::Reader { -public: - typedef Call Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasTarget() const; - inline ::capnp::rpc::MessageTarget::Reader getTarget() const; - - inline ::uint64_t getInterfaceId() const; - - inline ::uint16_t getMethodId() const; - - inline bool hasParams() const; - inline ::capnp::rpc::Payload::Reader getParams() const; - - inline typename SendResultsTo::Reader getSendResultsTo() const; - - inline bool getAllowThirdPartyTailCall() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Call::Builder { -public: - typedef Call Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasTarget(); - inline ::capnp::rpc::MessageTarget::Builder getTarget(); - inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); - inline ::capnp::rpc::MessageTarget::Builder initTarget(); - inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); - inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); - - inline ::uint64_t getInterfaceId(); - inline void setInterfaceId( ::uint64_t value); - - inline ::uint16_t getMethodId(); - inline void setMethodId( ::uint16_t value); - - inline bool hasParams(); - inline ::capnp::rpc::Payload::Builder getParams(); - inline void setParams( ::capnp::rpc::Payload::Reader value); - inline ::capnp::rpc::Payload::Builder initParams(); - inline void adoptParams(::capnp::Orphan< ::capnp::rpc::Payload>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Payload> disownParams(); - - inline typename SendResultsTo::Builder getSendResultsTo(); - inline typename SendResultsTo::Builder initSendResultsTo(); - - inline bool getAllowThirdPartyTailCall(); - inline void setAllowThirdPartyTailCall(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Call::Pipeline { -public: - typedef Call Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); - inline ::capnp::rpc::Payload::Pipeline getParams(); - inline typename SendResultsTo::Pipeline getSendResultsTo(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Call::SendResultsTo::Reader { -public: - typedef SendResultsTo Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isCaller() const; - inline ::capnp::Void getCaller() const; - - inline bool isYourself() const; - inline ::capnp::Void getYourself() const; - - inline bool isThirdParty() const; - inline bool hasThirdParty() const; - inline ::capnp::AnyPointer::Reader getThirdParty() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Call::SendResultsTo::Builder { -public: - typedef SendResultsTo Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isCaller(); - inline ::capnp::Void getCaller(); - inline void setCaller( ::capnp::Void value = ::capnp::VOID); - - inline bool isYourself(); - inline ::capnp::Void getYourself(); - inline void setYourself( ::capnp::Void value = ::capnp::VOID); - - inline bool isThirdParty(); - inline bool hasThirdParty(); - inline ::capnp::AnyPointer::Builder getThirdParty(); - inline ::capnp::AnyPointer::Builder initThirdParty(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Call::SendResultsTo::Pipeline { -public: - typedef SendResultsTo Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Return::Reader { -public: - typedef Return Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline ::uint32_t getAnswerId() const; - - inline bool getReleaseParamCaps() const; - - inline bool isResults() const; - inline bool hasResults() const; - inline ::capnp::rpc::Payload::Reader getResults() const; - - inline bool isException() const; - inline bool hasException() const; - inline ::capnp::rpc::Exception::Reader getException() const; - - inline bool isCanceled() const; - inline ::capnp::Void getCanceled() const; - - inline bool isResultsSentElsewhere() const; - inline ::capnp::Void getResultsSentElsewhere() const; - - inline bool isTakeFromOtherQuestion() const; - inline ::uint32_t getTakeFromOtherQuestion() const; - - inline bool isAcceptFromThirdParty() const; - inline bool hasAcceptFromThirdParty() const; - inline ::capnp::AnyPointer::Reader getAcceptFromThirdParty() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Return::Builder { -public: - typedef Return Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline ::uint32_t getAnswerId(); - inline void setAnswerId( ::uint32_t value); - - inline bool getReleaseParamCaps(); - inline void setReleaseParamCaps(bool value); - - inline bool isResults(); - inline bool hasResults(); - inline ::capnp::rpc::Payload::Builder getResults(); - inline void setResults( ::capnp::rpc::Payload::Reader value); - inline ::capnp::rpc::Payload::Builder initResults(); - inline void adoptResults(::capnp::Orphan< ::capnp::rpc::Payload>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Payload> disownResults(); - - inline bool isException(); - inline bool hasException(); - inline ::capnp::rpc::Exception::Builder getException(); - inline void setException( ::capnp::rpc::Exception::Reader value); - inline ::capnp::rpc::Exception::Builder initException(); - inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); - - inline bool isCanceled(); - inline ::capnp::Void getCanceled(); - inline void setCanceled( ::capnp::Void value = ::capnp::VOID); - - inline bool isResultsSentElsewhere(); - inline ::capnp::Void getResultsSentElsewhere(); - inline void setResultsSentElsewhere( ::capnp::Void value = ::capnp::VOID); - - inline bool isTakeFromOtherQuestion(); - inline ::uint32_t getTakeFromOtherQuestion(); - inline void setTakeFromOtherQuestion( ::uint32_t value); - - inline bool isAcceptFromThirdParty(); - inline bool hasAcceptFromThirdParty(); - inline ::capnp::AnyPointer::Builder getAcceptFromThirdParty(); - inline ::capnp::AnyPointer::Builder initAcceptFromThirdParty(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Return::Pipeline { -public: - typedef Return Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Finish::Reader { -public: - typedef Finish Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool getReleaseResultCaps() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Finish::Builder { -public: - typedef Finish Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool getReleaseResultCaps(); - inline void setReleaseResultCaps(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Finish::Pipeline { -public: - typedef Finish Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Resolve::Reader { -public: - typedef Resolve Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline ::uint32_t getPromiseId() const; - - inline bool isCap() const; - inline bool hasCap() const; - inline ::capnp::rpc::CapDescriptor::Reader getCap() const; - - inline bool isException() const; - inline bool hasException() const; - inline ::capnp::rpc::Exception::Reader getException() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Resolve::Builder { -public: - typedef Resolve Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline ::uint32_t getPromiseId(); - inline void setPromiseId( ::uint32_t value); - - inline bool isCap(); - inline bool hasCap(); - inline ::capnp::rpc::CapDescriptor::Builder getCap(); - inline void setCap( ::capnp::rpc::CapDescriptor::Reader value); - inline ::capnp::rpc::CapDescriptor::Builder initCap(); - inline void adoptCap(::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value); - inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> disownCap(); - - inline bool isException(); - inline bool hasException(); - inline ::capnp::rpc::Exception::Builder getException(); - inline void setException( ::capnp::rpc::Exception::Reader value); - inline ::capnp::rpc::Exception::Builder initException(); - inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); - inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Resolve::Pipeline { -public: - typedef Resolve Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Release::Reader { -public: - typedef Release Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getId() const; - - inline ::uint32_t getReferenceCount() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Release::Builder { -public: - typedef Release Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getId(); - inline void setId( ::uint32_t value); - - inline ::uint32_t getReferenceCount(); - inline void setReferenceCount( ::uint32_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Release::Pipeline { -public: - typedef Release Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Disembargo::Reader { -public: - typedef Disembargo Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasTarget() const; - inline ::capnp::rpc::MessageTarget::Reader getTarget() const; - - inline typename Context::Reader getContext() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Disembargo::Builder { -public: - typedef Disembargo Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasTarget(); - inline ::capnp::rpc::MessageTarget::Builder getTarget(); - inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); - inline ::capnp::rpc::MessageTarget::Builder initTarget(); - inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); - inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); - - inline typename Context::Builder getContext(); - inline typename Context::Builder initContext(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Disembargo::Pipeline { -public: - typedef Disembargo Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); - inline typename Context::Pipeline getContext(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Disembargo::Context::Reader { -public: - typedef Context Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isSenderLoopback() const; - inline ::uint32_t getSenderLoopback() const; - - inline bool isReceiverLoopback() const; - inline ::uint32_t getReceiverLoopback() const; - - inline bool isAccept() const; - inline ::capnp::Void getAccept() const; - - inline bool isProvide() const; - inline ::uint32_t getProvide() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Disembargo::Context::Builder { -public: - typedef Context Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isSenderLoopback(); - inline ::uint32_t getSenderLoopback(); - inline void setSenderLoopback( ::uint32_t value); - - inline bool isReceiverLoopback(); - inline ::uint32_t getReceiverLoopback(); - inline void setReceiverLoopback( ::uint32_t value); - - inline bool isAccept(); - inline ::capnp::Void getAccept(); - inline void setAccept( ::capnp::Void value = ::capnp::VOID); - - inline bool isProvide(); - inline ::uint32_t getProvide(); - inline void setProvide( ::uint32_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Disembargo::Context::Pipeline { -public: - typedef Context Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Provide::Reader { -public: - typedef Provide Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasTarget() const; - inline ::capnp::rpc::MessageTarget::Reader getTarget() const; - - inline bool hasRecipient() const; - inline ::capnp::AnyPointer::Reader getRecipient() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Provide::Builder { -public: - typedef Provide Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasTarget(); - inline ::capnp::rpc::MessageTarget::Builder getTarget(); - inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); - inline ::capnp::rpc::MessageTarget::Builder initTarget(); - inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); - inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); - - inline bool hasRecipient(); - inline ::capnp::AnyPointer::Builder getRecipient(); - inline ::capnp::AnyPointer::Builder initRecipient(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Provide::Pipeline { -public: - typedef Provide Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Accept::Reader { -public: - typedef Accept Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasProvision() const; - inline ::capnp::AnyPointer::Reader getProvision() const; - - inline bool getEmbargo() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Accept::Builder { -public: - typedef Accept Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasProvision(); - inline ::capnp::AnyPointer::Builder getProvision(); - inline ::capnp::AnyPointer::Builder initProvision(); - - inline bool getEmbargo(); - inline void setEmbargo(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Accept::Pipeline { -public: - typedef Accept Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Join::Reader { -public: - typedef Join Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasTarget() const; - inline ::capnp::rpc::MessageTarget::Reader getTarget() const; - - inline bool hasKeyPart() const; - inline ::capnp::AnyPointer::Reader getKeyPart() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Join::Builder { -public: - typedef Join Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasTarget(); - inline ::capnp::rpc::MessageTarget::Builder getTarget(); - inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); - inline ::capnp::rpc::MessageTarget::Builder initTarget(); - inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); - inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); - - inline bool hasKeyPart(); - inline ::capnp::AnyPointer::Builder getKeyPart(); - inline ::capnp::AnyPointer::Builder initKeyPart(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Join::Pipeline { -public: - typedef Join Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class MessageTarget::Reader { -public: - typedef MessageTarget Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isImportedCap() const; - inline ::uint32_t getImportedCap() const; - - inline bool isPromisedAnswer() const; - inline bool hasPromisedAnswer() const; - inline ::capnp::rpc::PromisedAnswer::Reader getPromisedAnswer() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class MessageTarget::Builder { -public: - typedef MessageTarget Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isImportedCap(); - inline ::uint32_t getImportedCap(); - inline void setImportedCap( ::uint32_t value); - - inline bool isPromisedAnswer(); - inline bool hasPromisedAnswer(); - inline ::capnp::rpc::PromisedAnswer::Builder getPromisedAnswer(); - inline void setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value); - inline ::capnp::rpc::PromisedAnswer::Builder initPromisedAnswer(); - inline void adoptPromisedAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); - inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownPromisedAnswer(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class MessageTarget::Pipeline { -public: - typedef MessageTarget Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Payload::Reader { -public: - typedef Payload Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasContent() const; - inline ::capnp::AnyPointer::Reader getContent() const; - - inline bool hasCapTable() const; - inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader getCapTable() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Payload::Builder { -public: - typedef Payload Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasContent(); - inline ::capnp::AnyPointer::Builder getContent(); - inline ::capnp::AnyPointer::Builder initContent(); - - inline bool hasCapTable(); - inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder getCapTable(); - inline void setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value); - inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder initCapTable(unsigned int size); - inline void adoptCapTable(::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> disownCapTable(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Payload::Pipeline { -public: - typedef Payload Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class CapDescriptor::Reader { -public: - typedef CapDescriptor Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isNone() const; - inline ::capnp::Void getNone() const; - - inline bool isSenderHosted() const; - inline ::uint32_t getSenderHosted() const; - - inline bool isSenderPromise() const; - inline ::uint32_t getSenderPromise() const; - - inline bool isReceiverHosted() const; - inline ::uint32_t getReceiverHosted() const; - - inline bool isReceiverAnswer() const; - inline bool hasReceiverAnswer() const; - inline ::capnp::rpc::PromisedAnswer::Reader getReceiverAnswer() const; - - inline bool isThirdPartyHosted() const; - inline bool hasThirdPartyHosted() const; - inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader getThirdPartyHosted() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class CapDescriptor::Builder { -public: - typedef CapDescriptor Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isNone(); - inline ::capnp::Void getNone(); - inline void setNone( ::capnp::Void value = ::capnp::VOID); - - inline bool isSenderHosted(); - inline ::uint32_t getSenderHosted(); - inline void setSenderHosted( ::uint32_t value); - - inline bool isSenderPromise(); - inline ::uint32_t getSenderPromise(); - inline void setSenderPromise( ::uint32_t value); - - inline bool isReceiverHosted(); - inline ::uint32_t getReceiverHosted(); - inline void setReceiverHosted( ::uint32_t value); - - inline bool isReceiverAnswer(); - inline bool hasReceiverAnswer(); - inline ::capnp::rpc::PromisedAnswer::Builder getReceiverAnswer(); - inline void setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value); - inline ::capnp::rpc::PromisedAnswer::Builder initReceiverAnswer(); - inline void adoptReceiverAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); - inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownReceiverAnswer(); - - inline bool isThirdPartyHosted(); - inline bool hasThirdPartyHosted(); - inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder getThirdPartyHosted(); - inline void setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value); - inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder initThirdPartyHosted(); - inline void adoptThirdPartyHosted(::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value); - inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> disownThirdPartyHosted(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class CapDescriptor::Pipeline { -public: - typedef CapDescriptor Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class PromisedAnswer::Reader { -public: - typedef PromisedAnswer Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId() const; - - inline bool hasTransform() const; - inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader getTransform() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class PromisedAnswer::Builder { -public: - typedef PromisedAnswer Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getQuestionId(); - inline void setQuestionId( ::uint32_t value); - - inline bool hasTransform(); - inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder getTransform(); - inline void setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value); - inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder initTransform(unsigned int size); - inline void adoptTransform(::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> disownTransform(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class PromisedAnswer::Pipeline { -public: - typedef PromisedAnswer Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class PromisedAnswer::Op::Reader { -public: - typedef Op Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isNoop() const; - inline ::capnp::Void getNoop() const; - - inline bool isGetPointerField() const; - inline ::uint16_t getGetPointerField() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class PromisedAnswer::Op::Builder { -public: - typedef Op Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isNoop(); - inline ::capnp::Void getNoop(); - inline void setNoop( ::capnp::Void value = ::capnp::VOID); - - inline bool isGetPointerField(); - inline ::uint16_t getGetPointerField(); - inline void setGetPointerField( ::uint16_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class PromisedAnswer::Op::Pipeline { -public: - typedef Op Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class ThirdPartyCapDescriptor::Reader { -public: - typedef ThirdPartyCapDescriptor Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasId() const; - inline ::capnp::AnyPointer::Reader getId() const; - - inline ::uint32_t getVineId() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class ThirdPartyCapDescriptor::Builder { -public: - typedef ThirdPartyCapDescriptor Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasId(); - inline ::capnp::AnyPointer::Builder getId(); - inline ::capnp::AnyPointer::Builder initId(); - - inline ::uint32_t getVineId(); - inline void setVineId( ::uint32_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class ThirdPartyCapDescriptor::Pipeline { -public: - typedef ThirdPartyCapDescriptor Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Exception::Reader { -public: - typedef Exception Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasReason() const; - inline ::capnp::Text::Reader getReason() const; - - inline bool getObsoleteIsCallersFault() const; - - inline ::uint16_t getObsoleteDurability() const; - - inline ::capnp::rpc::Exception::Type getType() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Exception::Builder { -public: - typedef Exception Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasReason(); - inline ::capnp::Text::Builder getReason(); - inline void setReason( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initReason(unsigned int size); - inline void adoptReason(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownReason(); - - inline bool getObsoleteIsCallersFault(); - inline void setObsoleteIsCallersFault(bool value); - - inline ::uint16_t getObsoleteDurability(); - inline void setObsoleteDurability( ::uint16_t value); - - inline ::capnp::rpc::Exception::Type getType(); - inline void setType( ::capnp::rpc::Exception::Type value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Exception::Pipeline { -public: - typedef Exception Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -// ======================================================================================= - -inline ::capnp::rpc::Message::Which Message::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::Message::Which Message::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool Message::Reader::isUnimplemented() const { - return which() == Message::UNIMPLEMENTED; -} -inline bool Message::Builder::isUnimplemented() { - return which() == Message::UNIMPLEMENTED; -} -inline bool Message::Reader::hasUnimplemented() const { - if (which() != Message::UNIMPLEMENTED) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasUnimplemented() { - if (which() != Message::UNIMPLEMENTED) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Message::Reader Message::Reader::getUnimplemented() const { - KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Message::Builder Message::Builder::getUnimplemented() { - KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setUnimplemented( ::capnp::rpc::Message::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); - ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Message::Builder Message::Builder::initUnimplemented() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptUnimplemented( - ::capnp::Orphan< ::capnp::rpc::Message>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); - ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Message> Message::Builder::disownUnimplemented() { - KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isAbort() const { - return which() == Message::ABORT; -} -inline bool Message::Builder::isAbort() { - return which() == Message::ABORT; -} -inline bool Message::Reader::hasAbort() const { - if (which() != Message::ABORT) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasAbort() { - if (which() != Message::ABORT) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Exception::Reader Message::Reader::getAbort() const { - KJ_IREQUIRE((which() == Message::ABORT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Exception::Builder Message::Builder::getAbort() { - KJ_IREQUIRE((which() == Message::ABORT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setAbort( ::capnp::rpc::Exception::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ABORT); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Exception::Builder Message::Builder::initAbort() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ABORT); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptAbort( - ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ABORT); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Exception> Message::Builder::disownAbort() { - KJ_IREQUIRE((which() == Message::ABORT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isCall() const { - return which() == Message::CALL; -} -inline bool Message::Builder::isCall() { - return which() == Message::CALL; -} -inline bool Message::Reader::hasCall() const { - if (which() != Message::CALL) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasCall() { - if (which() != Message::CALL) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Call::Reader Message::Reader::getCall() const { - KJ_IREQUIRE((which() == Message::CALL), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Call::Builder Message::Builder::getCall() { - KJ_IREQUIRE((which() == Message::CALL), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setCall( ::capnp::rpc::Call::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::CALL); - ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Call::Builder Message::Builder::initCall() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::CALL); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptCall( - ::capnp::Orphan< ::capnp::rpc::Call>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::CALL); - ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Call> Message::Builder::disownCall() { - KJ_IREQUIRE((which() == Message::CALL), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isReturn() const { - return which() == Message::RETURN; -} -inline bool Message::Builder::isReturn() { - return which() == Message::RETURN; -} -inline bool Message::Reader::hasReturn() const { - if (which() != Message::RETURN) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasReturn() { - if (which() != Message::RETURN) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Return::Reader Message::Reader::getReturn() const { - KJ_IREQUIRE((which() == Message::RETURN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Return::Builder Message::Builder::getReturn() { - KJ_IREQUIRE((which() == Message::RETURN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setReturn( ::capnp::rpc::Return::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RETURN); - ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Return::Builder Message::Builder::initReturn() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RETURN); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptReturn( - ::capnp::Orphan< ::capnp::rpc::Return>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RETURN); - ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Return> Message::Builder::disownReturn() { - KJ_IREQUIRE((which() == Message::RETURN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isFinish() const { - return which() == Message::FINISH; -} -inline bool Message::Builder::isFinish() { - return which() == Message::FINISH; -} -inline bool Message::Reader::hasFinish() const { - if (which() != Message::FINISH) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasFinish() { - if (which() != Message::FINISH) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Finish::Reader Message::Reader::getFinish() const { - KJ_IREQUIRE((which() == Message::FINISH), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Finish::Builder Message::Builder::getFinish() { - KJ_IREQUIRE((which() == Message::FINISH), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setFinish( ::capnp::rpc::Finish::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::FINISH); - ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Finish::Builder Message::Builder::initFinish() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::FINISH); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptFinish( - ::capnp::Orphan< ::capnp::rpc::Finish>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::FINISH); - ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Finish> Message::Builder::disownFinish() { - KJ_IREQUIRE((which() == Message::FINISH), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isResolve() const { - return which() == Message::RESOLVE; -} -inline bool Message::Builder::isResolve() { - return which() == Message::RESOLVE; -} -inline bool Message::Reader::hasResolve() const { - if (which() != Message::RESOLVE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasResolve() { - if (which() != Message::RESOLVE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Resolve::Reader Message::Reader::getResolve() const { - KJ_IREQUIRE((which() == Message::RESOLVE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Resolve::Builder Message::Builder::getResolve() { - KJ_IREQUIRE((which() == Message::RESOLVE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setResolve( ::capnp::rpc::Resolve::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RESOLVE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Resolve::Builder Message::Builder::initResolve() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RESOLVE); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptResolve( - ::capnp::Orphan< ::capnp::rpc::Resolve>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RESOLVE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Resolve> Message::Builder::disownResolve() { - KJ_IREQUIRE((which() == Message::RESOLVE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isRelease() const { - return which() == Message::RELEASE; -} -inline bool Message::Builder::isRelease() { - return which() == Message::RELEASE; -} -inline bool Message::Reader::hasRelease() const { - if (which() != Message::RELEASE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasRelease() { - if (which() != Message::RELEASE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Release::Reader Message::Reader::getRelease() const { - KJ_IREQUIRE((which() == Message::RELEASE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Release::Builder Message::Builder::getRelease() { - KJ_IREQUIRE((which() == Message::RELEASE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setRelease( ::capnp::rpc::Release::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RELEASE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Release::Builder Message::Builder::initRelease() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RELEASE); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptRelease( - ::capnp::Orphan< ::capnp::rpc::Release>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::RELEASE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Release> Message::Builder::disownRelease() { - KJ_IREQUIRE((which() == Message::RELEASE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isObsoleteSave() const { - return which() == Message::OBSOLETE_SAVE; -} -inline bool Message::Builder::isObsoleteSave() { - return which() == Message::OBSOLETE_SAVE; -} -inline bool Message::Reader::hasObsoleteSave() const { - if (which() != Message::OBSOLETE_SAVE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasObsoleteSave() { - if (which() != Message::OBSOLETE_SAVE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteSave() const { - KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteSave() { - KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteSave() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::OBSOLETE_SAVE); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Message::Reader::isBootstrap() const { - return which() == Message::BOOTSTRAP; -} -inline bool Message::Builder::isBootstrap() { - return which() == Message::BOOTSTRAP; -} -inline bool Message::Reader::hasBootstrap() const { - if (which() != Message::BOOTSTRAP) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasBootstrap() { - if (which() != Message::BOOTSTRAP) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Bootstrap::Reader Message::Reader::getBootstrap() const { - KJ_IREQUIRE((which() == Message::BOOTSTRAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Bootstrap::Builder Message::Builder::getBootstrap() { - KJ_IREQUIRE((which() == Message::BOOTSTRAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setBootstrap( ::capnp::rpc::Bootstrap::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::BOOTSTRAP); - ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Bootstrap::Builder Message::Builder::initBootstrap() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::BOOTSTRAP); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptBootstrap( - ::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::BOOTSTRAP); - ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> Message::Builder::disownBootstrap() { - KJ_IREQUIRE((which() == Message::BOOTSTRAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isObsoleteDelete() const { - return which() == Message::OBSOLETE_DELETE; -} -inline bool Message::Builder::isObsoleteDelete() { - return which() == Message::OBSOLETE_DELETE; -} -inline bool Message::Reader::hasObsoleteDelete() const { - if (which() != Message::OBSOLETE_DELETE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasObsoleteDelete() { - if (which() != Message::OBSOLETE_DELETE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteDelete() const { - KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteDelete() { - KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteDelete() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::OBSOLETE_DELETE); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Message::Reader::isProvide() const { - return which() == Message::PROVIDE; -} -inline bool Message::Builder::isProvide() { - return which() == Message::PROVIDE; -} -inline bool Message::Reader::hasProvide() const { - if (which() != Message::PROVIDE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasProvide() { - if (which() != Message::PROVIDE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Provide::Reader Message::Reader::getProvide() const { - KJ_IREQUIRE((which() == Message::PROVIDE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Provide::Builder Message::Builder::getProvide() { - KJ_IREQUIRE((which() == Message::PROVIDE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setProvide( ::capnp::rpc::Provide::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::PROVIDE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Provide::Builder Message::Builder::initProvide() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::PROVIDE); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptProvide( - ::capnp::Orphan< ::capnp::rpc::Provide>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::PROVIDE); - ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Provide> Message::Builder::disownProvide() { - KJ_IREQUIRE((which() == Message::PROVIDE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isAccept() const { - return which() == Message::ACCEPT; -} -inline bool Message::Builder::isAccept() { - return which() == Message::ACCEPT; -} -inline bool Message::Reader::hasAccept() const { - if (which() != Message::ACCEPT) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasAccept() { - if (which() != Message::ACCEPT) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Accept::Reader Message::Reader::getAccept() const { - KJ_IREQUIRE((which() == Message::ACCEPT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Accept::Builder Message::Builder::getAccept() { - KJ_IREQUIRE((which() == Message::ACCEPT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setAccept( ::capnp::rpc::Accept::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ACCEPT); - ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Accept::Builder Message::Builder::initAccept() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ACCEPT); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptAccept( - ::capnp::Orphan< ::capnp::rpc::Accept>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::ACCEPT); - ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Accept> Message::Builder::disownAccept() { - KJ_IREQUIRE((which() == Message::ACCEPT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isJoin() const { - return which() == Message::JOIN; -} -inline bool Message::Builder::isJoin() { - return which() == Message::JOIN; -} -inline bool Message::Reader::hasJoin() const { - if (which() != Message::JOIN) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasJoin() { - if (which() != Message::JOIN) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Join::Reader Message::Reader::getJoin() const { - KJ_IREQUIRE((which() == Message::JOIN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Join::Builder Message::Builder::getJoin() { - KJ_IREQUIRE((which() == Message::JOIN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setJoin( ::capnp::rpc::Join::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::JOIN); - ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Join::Builder Message::Builder::initJoin() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::JOIN); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptJoin( - ::capnp::Orphan< ::capnp::rpc::Join>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::JOIN); - ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Join> Message::Builder::disownJoin() { - KJ_IREQUIRE((which() == Message::JOIN), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Message::Reader::isDisembargo() const { - return which() == Message::DISEMBARGO; -} -inline bool Message::Builder::isDisembargo() { - return which() == Message::DISEMBARGO; -} -inline bool Message::Reader::hasDisembargo() const { - if (which() != Message::DISEMBARGO) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Message::Builder::hasDisembargo() { - if (which() != Message::DISEMBARGO) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Disembargo::Reader Message::Reader::getDisembargo() const { - KJ_IREQUIRE((which() == Message::DISEMBARGO), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Disembargo::Builder Message::Builder::getDisembargo() { - KJ_IREQUIRE((which() == Message::DISEMBARGO), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::setDisembargo( ::capnp::rpc::Disembargo::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::DISEMBARGO); - ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Disembargo::Builder Message::Builder::initDisembargo() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::DISEMBARGO); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Message::Builder::adoptDisembargo( - ::capnp::Orphan< ::capnp::rpc::Disembargo>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Message::DISEMBARGO); - ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Disembargo> Message::Builder::disownDisembargo() { - KJ_IREQUIRE((which() == Message::DISEMBARGO), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint32_t Bootstrap::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Bootstrap::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Bootstrap::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Bootstrap::Reader::hasDeprecatedObjectId() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Bootstrap::Builder::hasDeprecatedObjectId() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Bootstrap::Reader::getDeprecatedObjectId() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Bootstrap::Builder::getDeprecatedObjectId() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Bootstrap::Builder::initDeprecatedObjectId() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::uint32_t Call::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Call::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Call::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Call::Reader::hasTarget() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Call::Builder::hasTarget() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::MessageTarget::Reader Call::Reader::getTarget() const { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::MessageTarget::Builder Call::Builder::getTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::rpc::MessageTarget::Pipeline Call::Pipeline::getTarget() { - return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Call::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::MessageTarget::Builder Call::Builder::initTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Call::Builder::adoptTarget( - ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Call::Builder::disownTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint64_t Call::Reader::getInterfaceId() const { - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Call::Builder::getInterfaceId() { - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Call::Builder::setInterfaceId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Call::Reader::getMethodId() const { - return _reader.getDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Call::Builder::getMethodId() { - return _builder.getDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Call::Builder::setMethodId( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Call::Reader::hasParams() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Call::Builder::hasParams() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Payload::Reader Call::Reader::getParams() const { - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Payload::Builder Call::Builder::getParams() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::rpc::Payload::Pipeline Call::Pipeline::getParams() { - return ::capnp::rpc::Payload::Pipeline(_typeless.getPointerField(1)); -} -#endif // !CAPNP_LITE -inline void Call::Builder::setParams( ::capnp::rpc::Payload::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Payload::Builder Call::Builder::initParams() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Call::Builder::adoptParams( - ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Payload> Call::Builder::disownParams() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline typename Call::SendResultsTo::Reader Call::Reader::getSendResultsTo() const { - return typename Call::SendResultsTo::Reader(_reader); -} -inline typename Call::SendResultsTo::Builder Call::Builder::getSendResultsTo() { - return typename Call::SendResultsTo::Builder(_builder); -} -#if !CAPNP_LITE -inline typename Call::SendResultsTo::Pipeline Call::Pipeline::getSendResultsTo() { - return typename Call::SendResultsTo::Pipeline(_typeless.noop()); -} -#endif // !CAPNP_LITE -inline typename Call::SendResultsTo::Builder Call::Builder::initSendResultsTo() { - _builder.setDataField< ::uint16_t>(3 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(2 * ::capnp::POINTERS).clear(); - return typename Call::SendResultsTo::Builder(_builder); -} -inline bool Call::Reader::getAllowThirdPartyTailCall() const { - return _reader.getDataField( - 128 * ::capnp::ELEMENTS); -} - -inline bool Call::Builder::getAllowThirdPartyTailCall() { - return _builder.getDataField( - 128 * ::capnp::ELEMENTS); -} -inline void Call::Builder::setAllowThirdPartyTailCall(bool value) { - _builder.setDataField( - 128 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Reader::which() const { - return _reader.getDataField(3 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Builder::which() { - return _builder.getDataField(3 * ::capnp::ELEMENTS); -} - -inline bool Call::SendResultsTo::Reader::isCaller() const { - return which() == Call::SendResultsTo::CALLER; -} -inline bool Call::SendResultsTo::Builder::isCaller() { - return which() == Call::SendResultsTo::CALLER; -} -inline ::capnp::Void Call::SendResultsTo::Reader::getCaller() const { - KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Call::SendResultsTo::Builder::getCaller() { - KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Call::SendResultsTo::Builder::setCaller( ::capnp::Void value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Call::SendResultsTo::CALLER); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Call::SendResultsTo::Reader::isYourself() const { - return which() == Call::SendResultsTo::YOURSELF; -} -inline bool Call::SendResultsTo::Builder::isYourself() { - return which() == Call::SendResultsTo::YOURSELF; -} -inline ::capnp::Void Call::SendResultsTo::Reader::getYourself() const { - KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Call::SendResultsTo::Builder::getYourself() { - KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Call::SendResultsTo::Builder::setYourself( ::capnp::Void value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Call::SendResultsTo::YOURSELF); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Call::SendResultsTo::Reader::isThirdParty() const { - return which() == Call::SendResultsTo::THIRD_PARTY; -} -inline bool Call::SendResultsTo::Builder::isThirdParty() { - return which() == Call::SendResultsTo::THIRD_PARTY; -} -inline bool Call::SendResultsTo::Reader::hasThirdParty() const { - if (which() != Call::SendResultsTo::THIRD_PARTY) return false; - return !_reader.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline bool Call::SendResultsTo::Builder::hasThirdParty() { - if (which() != Call::SendResultsTo::THIRD_PARTY) return false; - return !_builder.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Call::SendResultsTo::Reader::getThirdParty() const { - KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(2 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::getThirdParty() { - KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::initThirdParty() { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Call::SendResultsTo::THIRD_PARTY); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(2 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::capnp::rpc::Return::Which Return::Reader::which() const { - return _reader.getDataField(3 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::Return::Which Return::Builder::which() { - return _builder.getDataField(3 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Return::Reader::getAnswerId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Return::Builder::getAnswerId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Return::Builder::setAnswerId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Return::Reader::getReleaseParamCaps() const { - return _reader.getDataField( - 32 * ::capnp::ELEMENTS, true); -} - -inline bool Return::Builder::getReleaseParamCaps() { - return _builder.getDataField( - 32 * ::capnp::ELEMENTS, true); -} -inline void Return::Builder::setReleaseParamCaps(bool value) { - _builder.setDataField( - 32 * ::capnp::ELEMENTS, value, true); -} - -inline bool Return::Reader::isResults() const { - return which() == Return::RESULTS; -} -inline bool Return::Builder::isResults() { - return which() == Return::RESULTS; -} -inline bool Return::Reader::hasResults() const { - if (which() != Return::RESULTS) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Return::Builder::hasResults() { - if (which() != Return::RESULTS) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Payload::Reader Return::Reader::getResults() const { - KJ_IREQUIRE((which() == Return::RESULTS), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Payload::Builder Return::Builder::getResults() { - KJ_IREQUIRE((which() == Return::RESULTS), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Return::Builder::setResults( ::capnp::rpc::Payload::Reader value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::RESULTS); - ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Payload::Builder Return::Builder::initResults() { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::RESULTS); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Return::Builder::adoptResults( - ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::RESULTS); - ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Payload> Return::Builder::disownResults() { - KJ_IREQUIRE((which() == Return::RESULTS), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Return::Reader::isException() const { - return which() == Return::EXCEPTION; -} -inline bool Return::Builder::isException() { - return which() == Return::EXCEPTION; -} -inline bool Return::Reader::hasException() const { - if (which() != Return::EXCEPTION) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Return::Builder::hasException() { - if (which() != Return::EXCEPTION) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Exception::Reader Return::Reader::getException() const { - KJ_IREQUIRE((which() == Return::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Exception::Builder Return::Builder::getException() { - KJ_IREQUIRE((which() == Return::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Return::Builder::setException( ::capnp::rpc::Exception::Reader value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::EXCEPTION); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Exception::Builder Return::Builder::initException() { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::EXCEPTION); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Return::Builder::adoptException( - ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::EXCEPTION); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Exception> Return::Builder::disownException() { - KJ_IREQUIRE((which() == Return::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Return::Reader::isCanceled() const { - return which() == Return::CANCELED; -} -inline bool Return::Builder::isCanceled() { - return which() == Return::CANCELED; -} -inline ::capnp::Void Return::Reader::getCanceled() const { - KJ_IREQUIRE((which() == Return::CANCELED), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Return::Builder::getCanceled() { - KJ_IREQUIRE((which() == Return::CANCELED), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Return::Builder::setCanceled( ::capnp::Void value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::CANCELED); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Return::Reader::isResultsSentElsewhere() const { - return which() == Return::RESULTS_SENT_ELSEWHERE; -} -inline bool Return::Builder::isResultsSentElsewhere() { - return which() == Return::RESULTS_SENT_ELSEWHERE; -} -inline ::capnp::Void Return::Reader::getResultsSentElsewhere() const { - KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Return::Builder::getResultsSentElsewhere() { - KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Return::Builder::setResultsSentElsewhere( ::capnp::Void value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::RESULTS_SENT_ELSEWHERE); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Return::Reader::isTakeFromOtherQuestion() const { - return which() == Return::TAKE_FROM_OTHER_QUESTION; -} -inline bool Return::Builder::isTakeFromOtherQuestion() { - return which() == Return::TAKE_FROM_OTHER_QUESTION; -} -inline ::uint32_t Return::Reader::getTakeFromOtherQuestion() const { - KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Return::Builder::getTakeFromOtherQuestion() { - KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Return::Builder::setTakeFromOtherQuestion( ::uint32_t value) { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::TAKE_FROM_OTHER_QUESTION); - _builder.setDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Return::Reader::isAcceptFromThirdParty() const { - return which() == Return::ACCEPT_FROM_THIRD_PARTY; -} -inline bool Return::Builder::isAcceptFromThirdParty() { - return which() == Return::ACCEPT_FROM_THIRD_PARTY; -} -inline bool Return::Reader::hasAcceptFromThirdParty() const { - if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Return::Builder::hasAcceptFromThirdParty() { - if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Return::Reader::getAcceptFromThirdParty() const { - KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Return::Builder::getAcceptFromThirdParty() { - KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Return::Builder::initAcceptFromThirdParty() { - _builder.setDataField( - 3 * ::capnp::ELEMENTS, Return::ACCEPT_FROM_THIRD_PARTY); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::uint32_t Finish::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Finish::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Finish::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Finish::Reader::getReleaseResultCaps() const { - return _reader.getDataField( - 32 * ::capnp::ELEMENTS, true); -} - -inline bool Finish::Builder::getReleaseResultCaps() { - return _builder.getDataField( - 32 * ::capnp::ELEMENTS, true); -} -inline void Finish::Builder::setReleaseResultCaps(bool value) { - _builder.setDataField( - 32 * ::capnp::ELEMENTS, value, true); -} - -inline ::capnp::rpc::Resolve::Which Resolve::Reader::which() const { - return _reader.getDataField(2 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::Resolve::Which Resolve::Builder::which() { - return _builder.getDataField(2 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Resolve::Reader::getPromiseId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Resolve::Builder::getPromiseId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Resolve::Builder::setPromiseId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Resolve::Reader::isCap() const { - return which() == Resolve::CAP; -} -inline bool Resolve::Builder::isCap() { - return which() == Resolve::CAP; -} -inline bool Resolve::Reader::hasCap() const { - if (which() != Resolve::CAP) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Resolve::Builder::hasCap() { - if (which() != Resolve::CAP) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::CapDescriptor::Reader Resolve::Reader::getCap() const { - KJ_IREQUIRE((which() == Resolve::CAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::getCap() { - KJ_IREQUIRE((which() == Resolve::CAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Resolve::Builder::setCap( ::capnp::rpc::CapDescriptor::Reader value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::CAP); - ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::initCap() { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::CAP); - return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Resolve::Builder::adoptCap( - ::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::CAP); - ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> Resolve::Builder::disownCap() { - KJ_IREQUIRE((which() == Resolve::CAP), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Resolve::Reader::isException() const { - return which() == Resolve::EXCEPTION; -} -inline bool Resolve::Builder::isException() { - return which() == Resolve::EXCEPTION; -} -inline bool Resolve::Reader::hasException() const { - if (which() != Resolve::EXCEPTION) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Resolve::Builder::hasException() { - if (which() != Resolve::EXCEPTION) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::Exception::Reader Resolve::Reader::getException() const { - KJ_IREQUIRE((which() == Resolve::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::Exception::Builder Resolve::Builder::getException() { - KJ_IREQUIRE((which() == Resolve::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Resolve::Builder::setException( ::capnp::rpc::Exception::Reader value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::EXCEPTION); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::Exception::Builder Resolve::Builder::initException() { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::EXCEPTION); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Resolve::Builder::adoptException( - ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Resolve::EXCEPTION); - ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::Exception> Resolve::Builder::disownException() { - KJ_IREQUIRE((which() == Resolve::EXCEPTION), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint32_t Release::Reader::getId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Release::Builder::getId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Release::Builder::setId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t Release::Reader::getReferenceCount() const { - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Release::Builder::getReferenceCount() { - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Release::Builder::setReferenceCount( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Disembargo::Reader::hasTarget() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Disembargo::Builder::hasTarget() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::MessageTarget::Reader Disembargo::Reader::getTarget() const { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::getTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::rpc::MessageTarget::Pipeline Disembargo::Pipeline::getTarget() { - return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Disembargo::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::initTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Disembargo::Builder::adoptTarget( - ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Disembargo::Builder::disownTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline typename Disembargo::Context::Reader Disembargo::Reader::getContext() const { - return typename Disembargo::Context::Reader(_reader); -} -inline typename Disembargo::Context::Builder Disembargo::Builder::getContext() { - return typename Disembargo::Context::Builder(_builder); -} -#if !CAPNP_LITE -inline typename Disembargo::Context::Pipeline Disembargo::Pipeline::getContext() { - return typename Disembargo::Context::Pipeline(_typeless.noop()); -} -#endif // !CAPNP_LITE -inline typename Disembargo::Context::Builder Disembargo::Builder::initContext() { - _builder.setDataField< ::uint32_t>(0 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(2 * ::capnp::ELEMENTS, 0); - return typename Disembargo::Context::Builder(_builder); -} -inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Reader::which() const { - return _reader.getDataField(2 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Builder::which() { - return _builder.getDataField(2 * ::capnp::ELEMENTS); -} - -inline bool Disembargo::Context::Reader::isSenderLoopback() const { - return which() == Disembargo::Context::SENDER_LOOPBACK; -} -inline bool Disembargo::Context::Builder::isSenderLoopback() { - return which() == Disembargo::Context::SENDER_LOOPBACK; -} -inline ::uint32_t Disembargo::Context::Reader::getSenderLoopback() const { - KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Disembargo::Context::Builder::getSenderLoopback() { - KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Disembargo::Context::Builder::setSenderLoopback( ::uint32_t value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Disembargo::Context::SENDER_LOOPBACK); - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Disembargo::Context::Reader::isReceiverLoopback() const { - return which() == Disembargo::Context::RECEIVER_LOOPBACK; -} -inline bool Disembargo::Context::Builder::isReceiverLoopback() { - return which() == Disembargo::Context::RECEIVER_LOOPBACK; -} -inline ::uint32_t Disembargo::Context::Reader::getReceiverLoopback() const { - KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Disembargo::Context::Builder::getReceiverLoopback() { - KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Disembargo::Context::Builder::setReceiverLoopback( ::uint32_t value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Disembargo::Context::RECEIVER_LOOPBACK); - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Disembargo::Context::Reader::isAccept() const { - return which() == Disembargo::Context::ACCEPT; -} -inline bool Disembargo::Context::Builder::isAccept() { - return which() == Disembargo::Context::ACCEPT; -} -inline ::capnp::Void Disembargo::Context::Reader::getAccept() const { - KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Disembargo::Context::Builder::getAccept() { - KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Disembargo::Context::Builder::setAccept( ::capnp::Void value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Disembargo::Context::ACCEPT); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Disembargo::Context::Reader::isProvide() const { - return which() == Disembargo::Context::PROVIDE; -} -inline bool Disembargo::Context::Builder::isProvide() { - return which() == Disembargo::Context::PROVIDE; -} -inline ::uint32_t Disembargo::Context::Reader::getProvide() const { - KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Disembargo::Context::Builder::getProvide() { - KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Disembargo::Context::Builder::setProvide( ::uint32_t value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, Disembargo::Context::PROVIDE); - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t Provide::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Provide::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Provide::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Provide::Reader::hasTarget() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Provide::Builder::hasTarget() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::MessageTarget::Reader Provide::Reader::getTarget() const { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::getTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::rpc::MessageTarget::Pipeline Provide::Pipeline::getTarget() { - return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Provide::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::initTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Provide::Builder::adoptTarget( - ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Provide::Builder::disownTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Provide::Reader::hasRecipient() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Provide::Builder::hasRecipient() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Provide::Reader::getRecipient() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Provide::Builder::getRecipient() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Provide::Builder::initRecipient() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(1 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::uint32_t Accept::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Accept::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Accept::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Accept::Reader::hasProvision() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Accept::Builder::hasProvision() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Accept::Reader::getProvision() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Accept::Builder::getProvision() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Accept::Builder::initProvision() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Accept::Reader::getEmbargo() const { - return _reader.getDataField( - 32 * ::capnp::ELEMENTS); -} - -inline bool Accept::Builder::getEmbargo() { - return _builder.getDataField( - 32 * ::capnp::ELEMENTS); -} -inline void Accept::Builder::setEmbargo(bool value) { - _builder.setDataField( - 32 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t Join::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Join::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Join::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Join::Reader::hasTarget() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Join::Builder::hasTarget() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::MessageTarget::Reader Join::Reader::getTarget() const { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::MessageTarget::Builder Join::Builder::getTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::rpc::MessageTarget::Pipeline Join::Pipeline::getTarget() { - return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Join::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::MessageTarget::Builder Join::Builder::initTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Join::Builder::adoptTarget( - ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { - ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Join::Builder::disownTarget() { - return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Join::Reader::hasKeyPart() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Join::Builder::hasKeyPart() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Join::Reader::getKeyPart() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Join::Builder::getKeyPart() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Join::Builder::initKeyPart() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(1 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::capnp::rpc::MessageTarget::Which MessageTarget::Reader::which() const { - return _reader.getDataField(2 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::MessageTarget::Which MessageTarget::Builder::which() { - return _builder.getDataField(2 * ::capnp::ELEMENTS); -} - -inline bool MessageTarget::Reader::isImportedCap() const { - return which() == MessageTarget::IMPORTED_CAP; -} -inline bool MessageTarget::Builder::isImportedCap() { - return which() == MessageTarget::IMPORTED_CAP; -} -inline ::uint32_t MessageTarget::Reader::getImportedCap() const { - KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t MessageTarget::Builder::getImportedCap() { - KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void MessageTarget::Builder::setImportedCap( ::uint32_t value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, MessageTarget::IMPORTED_CAP); - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool MessageTarget::Reader::isPromisedAnswer() const { - return which() == MessageTarget::PROMISED_ANSWER; -} -inline bool MessageTarget::Builder::isPromisedAnswer() { - return which() == MessageTarget::PROMISED_ANSWER; -} -inline bool MessageTarget::Reader::hasPromisedAnswer() const { - if (which() != MessageTarget::PROMISED_ANSWER) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool MessageTarget::Builder::hasPromisedAnswer() { - if (which() != MessageTarget::PROMISED_ANSWER) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::PromisedAnswer::Reader MessageTarget::Reader::getPromisedAnswer() const { - KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::getPromisedAnswer() { - KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void MessageTarget::Builder::setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); - ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::initPromisedAnswer() { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void MessageTarget::Builder::adoptPromisedAnswer( - ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { - _builder.setDataField( - 2 * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); - ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> MessageTarget::Builder::disownPromisedAnswer() { - KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Payload::Reader::hasContent() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Payload::Builder::hasContent() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Payload::Reader::getContent() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Payload::Builder::getContent() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Payload::Builder::initContent() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Payload::Reader::hasCapTable() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Payload::Builder::hasCapTable() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader Payload::Reader::getCapTable() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::getCapTable() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Payload::Builder::setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::initCapTable(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void Payload::Builder::adoptCapTable( - ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> Payload::Builder::disownCapTable() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool CapDescriptor::Reader::isNone() const { - return which() == CapDescriptor::NONE; -} -inline bool CapDescriptor::Builder::isNone() { - return which() == CapDescriptor::NONE; -} -inline ::capnp::Void CapDescriptor::Reader::getNone() const { - KJ_IREQUIRE((which() == CapDescriptor::NONE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void CapDescriptor::Builder::getNone() { - KJ_IREQUIRE((which() == CapDescriptor::NONE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void CapDescriptor::Builder::setNone( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::NONE); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool CapDescriptor::Reader::isSenderHosted() const { - return which() == CapDescriptor::SENDER_HOSTED; -} -inline bool CapDescriptor::Builder::isSenderHosted() { - return which() == CapDescriptor::SENDER_HOSTED; -} -inline ::uint32_t CapDescriptor::Reader::getSenderHosted() const { - KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t CapDescriptor::Builder::getSenderHosted() { - KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void CapDescriptor::Builder::setSenderHosted( ::uint32_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::SENDER_HOSTED); - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool CapDescriptor::Reader::isSenderPromise() const { - return which() == CapDescriptor::SENDER_PROMISE; -} -inline bool CapDescriptor::Builder::isSenderPromise() { - return which() == CapDescriptor::SENDER_PROMISE; -} -inline ::uint32_t CapDescriptor::Reader::getSenderPromise() const { - KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t CapDescriptor::Builder::getSenderPromise() { - KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void CapDescriptor::Builder::setSenderPromise( ::uint32_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::SENDER_PROMISE); - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool CapDescriptor::Reader::isReceiverHosted() const { - return which() == CapDescriptor::RECEIVER_HOSTED; -} -inline bool CapDescriptor::Builder::isReceiverHosted() { - return which() == CapDescriptor::RECEIVER_HOSTED; -} -inline ::uint32_t CapDescriptor::Reader::getReceiverHosted() const { - KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t CapDescriptor::Builder::getReceiverHosted() { - KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void CapDescriptor::Builder::setReceiverHosted( ::uint32_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_HOSTED); - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool CapDescriptor::Reader::isReceiverAnswer() const { - return which() == CapDescriptor::RECEIVER_ANSWER; -} -inline bool CapDescriptor::Builder::isReceiverAnswer() { - return which() == CapDescriptor::RECEIVER_ANSWER; -} -inline bool CapDescriptor::Reader::hasReceiverAnswer() const { - if (which() != CapDescriptor::RECEIVER_ANSWER) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool CapDescriptor::Builder::hasReceiverAnswer() { - if (which() != CapDescriptor::RECEIVER_ANSWER) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::PromisedAnswer::Reader CapDescriptor::Reader::getReceiverAnswer() const { - KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::getReceiverAnswer() { - KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CapDescriptor::Builder::setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); - ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::initReceiverAnswer() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CapDescriptor::Builder::adoptReceiverAnswer( - ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); - ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> CapDescriptor::Builder::disownReceiverAnswer() { - KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool CapDescriptor::Reader::isThirdPartyHosted() const { - return which() == CapDescriptor::THIRD_PARTY_HOSTED; -} -inline bool CapDescriptor::Builder::isThirdPartyHosted() { - return which() == CapDescriptor::THIRD_PARTY_HOSTED; -} -inline bool CapDescriptor::Reader::hasThirdPartyHosted() const { - if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool CapDescriptor::Builder::hasThirdPartyHosted() { - if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader CapDescriptor::Reader::getThirdPartyHosted() const { - KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::getThirdPartyHosted() { - KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CapDescriptor::Builder::setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); - ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::initThirdPartyHosted() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); - return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CapDescriptor::Builder::adoptThirdPartyHosted( - ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); - ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> CapDescriptor::Builder::disownThirdPartyHosted() { - KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint32_t PromisedAnswer::Reader::getQuestionId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t PromisedAnswer::Builder::getQuestionId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void PromisedAnswer::Builder::setQuestionId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool PromisedAnswer::Reader::hasTransform() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool PromisedAnswer::Builder::hasTransform() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader PromisedAnswer::Reader::getTransform() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::getTransform() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void PromisedAnswer::Builder::setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::initTransform(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void PromisedAnswer::Builder::adoptTransform( - ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> PromisedAnswer::Builder::disownTransform() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool PromisedAnswer::Op::Reader::isNoop() const { - return which() == PromisedAnswer::Op::NOOP; -} -inline bool PromisedAnswer::Op::Builder::isNoop() { - return which() == PromisedAnswer::Op::NOOP; -} -inline ::capnp::Void PromisedAnswer::Op::Reader::getNoop() const { - KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void PromisedAnswer::Op::Builder::getNoop() { - KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void PromisedAnswer::Op::Builder::setNoop( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, PromisedAnswer::Op::NOOP); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool PromisedAnswer::Op::Reader::isGetPointerField() const { - return which() == PromisedAnswer::Op::GET_POINTER_FIELD; -} -inline bool PromisedAnswer::Op::Builder::isGetPointerField() { - return which() == PromisedAnswer::Op::GET_POINTER_FIELD; -} -inline ::uint16_t PromisedAnswer::Op::Reader::getGetPointerField() const { - KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint16_t PromisedAnswer::Op::Builder::getGetPointerField() { - KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} -inline void PromisedAnswer::Op::Builder::setGetPointerField( ::uint16_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, PromisedAnswer::Op::GET_POINTER_FIELD); - _builder.setDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool ThirdPartyCapDescriptor::Reader::hasId() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool ThirdPartyCapDescriptor::Builder::hasId() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader ThirdPartyCapDescriptor::Reader::getId() const { - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::getId() { - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::initId() { - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::uint32_t ThirdPartyCapDescriptor::Reader::getVineId() const { - return _reader.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint32_t ThirdPartyCapDescriptor::Builder::getVineId() { - return _builder.getDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS); -} -inline void ThirdPartyCapDescriptor::Builder::setVineId( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Exception::Reader::hasReason() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Exception::Builder::hasReason() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Exception::Reader::getReason() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Exception::Builder::getReason() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Exception::Builder::setReason( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Exception::Builder::initReason(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Exception::Builder::adoptReason( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Exception::Builder::disownReason() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Exception::Reader::getObsoleteIsCallersFault() const { - return _reader.getDataField( - 0 * ::capnp::ELEMENTS); -} - -inline bool Exception::Builder::getObsoleteIsCallersFault() { - return _builder.getDataField( - 0 * ::capnp::ELEMENTS); -} -inline void Exception::Builder::setObsoleteIsCallersFault(bool value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Exception::Reader::getObsoleteDurability() const { - return _reader.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Exception::Builder::getObsoleteDurability() { - return _builder.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Exception::Builder::setObsoleteDurability( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::rpc::Exception::Type Exception::Reader::getType() const { - return _reader.getDataField< ::capnp::rpc::Exception::Type>( - 2 * ::capnp::ELEMENTS); -} - -inline ::capnp::rpc::Exception::Type Exception::Builder::getType() { - return _builder.getDataField< ::capnp::rpc::Exception::Type>( - 2 * ::capnp::ELEMENTS); -} -inline void Exception::Builder::setType( ::capnp::rpc::Exception::Type value) { - _builder.setDataField< ::capnp::rpc::Exception::Type>( - 2 * ::capnp::ELEMENTS, value); -} - -} // namespace -} // namespace - -#endif // CAPNP_INCLUDED_b312981b2552a250_ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc.capnp + +#ifndef CAPNP_INCLUDED_b312981b2552a250_ +#define CAPNP_INCLUDED_b312981b2552a250_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(91b79f1f808db032); +CAPNP_DECLARE_SCHEMA(e94ccf8031176ec4); +CAPNP_DECLARE_SCHEMA(836a53ce789d4cd4); +CAPNP_DECLARE_SCHEMA(dae8b0f61aab5f99); +CAPNP_DECLARE_SCHEMA(9e19b28d3db3573a); +CAPNP_DECLARE_SCHEMA(d37d2eb2c2f80e63); +CAPNP_DECLARE_SCHEMA(bbc29655fa89086e); +CAPNP_DECLARE_SCHEMA(ad1a6c0d7dd07497); +CAPNP_DECLARE_SCHEMA(f964368b0fbd3711); +CAPNP_DECLARE_SCHEMA(d562b4df655bdd4d); +CAPNP_DECLARE_SCHEMA(9c6a046bfbc1ac5a); +CAPNP_DECLARE_SCHEMA(d4c9b56290554016); +CAPNP_DECLARE_SCHEMA(fbe1980490e001af); +CAPNP_DECLARE_SCHEMA(95bc14545813fbc1); +CAPNP_DECLARE_SCHEMA(9a0e61223d96743b); +CAPNP_DECLARE_SCHEMA(8523ddc40b86b8b0); +CAPNP_DECLARE_SCHEMA(d800b1d6cd6f1ca0); +CAPNP_DECLARE_SCHEMA(f316944415569081); +CAPNP_DECLARE_SCHEMA(d37007fde1f0027d); +CAPNP_DECLARE_SCHEMA(d625b7063acf691a); +CAPNP_DECLARE_SCHEMA(b28c96e23f4cbd58); +enum class Type_b28c96e23f4cbd58: uint16_t { + FAILED, + OVERLOADED, + DISCONNECTED, + UNIMPLEMENTED, +}; +CAPNP_DECLARE_ENUM(Type, b28c96e23f4cbd58); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace rpc { + +struct Message { + Message() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNIMPLEMENTED, + ABORT, + CALL, + RETURN, + FINISH, + RESOLVE, + RELEASE, + OBSOLETE_SAVE, + BOOTSTRAP, + OBSOLETE_DELETE, + PROVIDE, + ACCEPT, + JOIN, + DISEMBARGO, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(91b79f1f808db032, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Bootstrap { + Bootstrap() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e94ccf8031176ec4, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Call { + Call() = delete; + + class Reader; + class Builder; + class Pipeline; + struct SendResultsTo; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(836a53ce789d4cd4, 3, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Call::SendResultsTo { + SendResultsTo() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + CALLER, + YOURSELF, + THIRD_PARTY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(dae8b0f61aab5f99, 3, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Return { + Return() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + RESULTS, + EXCEPTION, + CANCELED, + RESULTS_SENT_ELSEWHERE, + TAKE_FROM_OTHER_QUESTION, + ACCEPT_FROM_THIRD_PARTY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9e19b28d3db3573a, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Finish { + Finish() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d37d2eb2c2f80e63, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Resolve { + Resolve() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + CAP, + EXCEPTION, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bbc29655fa89086e, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Release { + Release() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ad1a6c0d7dd07497, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Disembargo { + Disembargo() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Context; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f964368b0fbd3711, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Disembargo::Context { + Context() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + SENDER_LOOPBACK, + RECEIVER_LOOPBACK, + ACCEPT, + PROVIDE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d562b4df655bdd4d, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Provide { + Provide() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9c6a046bfbc1ac5a, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Accept { + Accept() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d4c9b56290554016, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Join { + Join() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(fbe1980490e001af, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct MessageTarget { + MessageTarget() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + IMPORTED_CAP, + PROMISED_ANSWER, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(95bc14545813fbc1, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Payload { + Payload() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9a0e61223d96743b, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CapDescriptor { + CapDescriptor() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + SENDER_HOSTED, + SENDER_PROMISE, + RECEIVER_HOSTED, + RECEIVER_ANSWER, + THIRD_PARTY_HOSTED, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8523ddc40b86b8b0, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct PromisedAnswer { + PromisedAnswer() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Op; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d800b1d6cd6f1ca0, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct PromisedAnswer::Op { + Op() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NOOP, + GET_POINTER_FIELD, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f316944415569081, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ThirdPartyCapDescriptor { + ThirdPartyCapDescriptor() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d37007fde1f0027d, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Exception { + Exception() = delete; + + class Reader; + class Builder; + class Pipeline; + typedef ::capnp::schemas::Type_b28c96e23f4cbd58 Type; + + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d625b7063acf691a, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class Message::Reader { +public: + typedef Message Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnimplemented() const; + inline bool hasUnimplemented() const; + inline ::capnp::rpc::Message::Reader getUnimplemented() const; + + inline bool isAbort() const; + inline bool hasAbort() const; + inline ::capnp::rpc::Exception::Reader getAbort() const; + + inline bool isCall() const; + inline bool hasCall() const; + inline ::capnp::rpc::Call::Reader getCall() const; + + inline bool isReturn() const; + inline bool hasReturn() const; + inline ::capnp::rpc::Return::Reader getReturn() const; + + inline bool isFinish() const; + inline bool hasFinish() const; + inline ::capnp::rpc::Finish::Reader getFinish() const; + + inline bool isResolve() const; + inline bool hasResolve() const; + inline ::capnp::rpc::Resolve::Reader getResolve() const; + + inline bool isRelease() const; + inline bool hasRelease() const; + inline ::capnp::rpc::Release::Reader getRelease() const; + + inline bool isObsoleteSave() const; + inline bool hasObsoleteSave() const; + inline ::capnp::AnyPointer::Reader getObsoleteSave() const; + + inline bool isBootstrap() const; + inline bool hasBootstrap() const; + inline ::capnp::rpc::Bootstrap::Reader getBootstrap() const; + + inline bool isObsoleteDelete() const; + inline bool hasObsoleteDelete() const; + inline ::capnp::AnyPointer::Reader getObsoleteDelete() const; + + inline bool isProvide() const; + inline bool hasProvide() const; + inline ::capnp::rpc::Provide::Reader getProvide() const; + + inline bool isAccept() const; + inline bool hasAccept() const; + inline ::capnp::rpc::Accept::Reader getAccept() const; + + inline bool isJoin() const; + inline bool hasJoin() const; + inline ::capnp::rpc::Join::Reader getJoin() const; + + inline bool isDisembargo() const; + inline bool hasDisembargo() const; + inline ::capnp::rpc::Disembargo::Reader getDisembargo() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Message::Builder { +public: + typedef Message Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnimplemented(); + inline bool hasUnimplemented(); + inline ::capnp::rpc::Message::Builder getUnimplemented(); + inline void setUnimplemented( ::capnp::rpc::Message::Reader value); + inline ::capnp::rpc::Message::Builder initUnimplemented(); + inline void adoptUnimplemented(::capnp::Orphan< ::capnp::rpc::Message>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Message> disownUnimplemented(); + + inline bool isAbort(); + inline bool hasAbort(); + inline ::capnp::rpc::Exception::Builder getAbort(); + inline void setAbort( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initAbort(); + inline void adoptAbort(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownAbort(); + + inline bool isCall(); + inline bool hasCall(); + inline ::capnp::rpc::Call::Builder getCall(); + inline void setCall( ::capnp::rpc::Call::Reader value); + inline ::capnp::rpc::Call::Builder initCall(); + inline void adoptCall(::capnp::Orphan< ::capnp::rpc::Call>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Call> disownCall(); + + inline bool isReturn(); + inline bool hasReturn(); + inline ::capnp::rpc::Return::Builder getReturn(); + inline void setReturn( ::capnp::rpc::Return::Reader value); + inline ::capnp::rpc::Return::Builder initReturn(); + inline void adoptReturn(::capnp::Orphan< ::capnp::rpc::Return>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Return> disownReturn(); + + inline bool isFinish(); + inline bool hasFinish(); + inline ::capnp::rpc::Finish::Builder getFinish(); + inline void setFinish( ::capnp::rpc::Finish::Reader value); + inline ::capnp::rpc::Finish::Builder initFinish(); + inline void adoptFinish(::capnp::Orphan< ::capnp::rpc::Finish>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Finish> disownFinish(); + + inline bool isResolve(); + inline bool hasResolve(); + inline ::capnp::rpc::Resolve::Builder getResolve(); + inline void setResolve( ::capnp::rpc::Resolve::Reader value); + inline ::capnp::rpc::Resolve::Builder initResolve(); + inline void adoptResolve(::capnp::Orphan< ::capnp::rpc::Resolve>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Resolve> disownResolve(); + + inline bool isRelease(); + inline bool hasRelease(); + inline ::capnp::rpc::Release::Builder getRelease(); + inline void setRelease( ::capnp::rpc::Release::Reader value); + inline ::capnp::rpc::Release::Builder initRelease(); + inline void adoptRelease(::capnp::Orphan< ::capnp::rpc::Release>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Release> disownRelease(); + + inline bool isObsoleteSave(); + inline bool hasObsoleteSave(); + inline ::capnp::AnyPointer::Builder getObsoleteSave(); + inline ::capnp::AnyPointer::Builder initObsoleteSave(); + + inline bool isBootstrap(); + inline bool hasBootstrap(); + inline ::capnp::rpc::Bootstrap::Builder getBootstrap(); + inline void setBootstrap( ::capnp::rpc::Bootstrap::Reader value); + inline ::capnp::rpc::Bootstrap::Builder initBootstrap(); + inline void adoptBootstrap(::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> disownBootstrap(); + + inline bool isObsoleteDelete(); + inline bool hasObsoleteDelete(); + inline ::capnp::AnyPointer::Builder getObsoleteDelete(); + inline ::capnp::AnyPointer::Builder initObsoleteDelete(); + + inline bool isProvide(); + inline bool hasProvide(); + inline ::capnp::rpc::Provide::Builder getProvide(); + inline void setProvide( ::capnp::rpc::Provide::Reader value); + inline ::capnp::rpc::Provide::Builder initProvide(); + inline void adoptProvide(::capnp::Orphan< ::capnp::rpc::Provide>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Provide> disownProvide(); + + inline bool isAccept(); + inline bool hasAccept(); + inline ::capnp::rpc::Accept::Builder getAccept(); + inline void setAccept( ::capnp::rpc::Accept::Reader value); + inline ::capnp::rpc::Accept::Builder initAccept(); + inline void adoptAccept(::capnp::Orphan< ::capnp::rpc::Accept>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Accept> disownAccept(); + + inline bool isJoin(); + inline bool hasJoin(); + inline ::capnp::rpc::Join::Builder getJoin(); + inline void setJoin( ::capnp::rpc::Join::Reader value); + inline ::capnp::rpc::Join::Builder initJoin(); + inline void adoptJoin(::capnp::Orphan< ::capnp::rpc::Join>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Join> disownJoin(); + + inline bool isDisembargo(); + inline bool hasDisembargo(); + inline ::capnp::rpc::Disembargo::Builder getDisembargo(); + inline void setDisembargo( ::capnp::rpc::Disembargo::Reader value); + inline ::capnp::rpc::Disembargo::Builder initDisembargo(); + inline void adoptDisembargo(::capnp::Orphan< ::capnp::rpc::Disembargo>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Disembargo> disownDisembargo(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Message::Pipeline { +public: + typedef Message Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Bootstrap::Reader { +public: + typedef Bootstrap Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasDeprecatedObjectId() const; + inline ::capnp::AnyPointer::Reader getDeprecatedObjectId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Bootstrap::Builder { +public: + typedef Bootstrap Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasDeprecatedObjectId(); + inline ::capnp::AnyPointer::Builder getDeprecatedObjectId(); + inline ::capnp::AnyPointer::Builder initDeprecatedObjectId(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Bootstrap::Pipeline { +public: + typedef Bootstrap Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Call::Reader { +public: + typedef Call Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline ::uint64_t getInterfaceId() const; + + inline ::uint16_t getMethodId() const; + + inline bool hasParams() const; + inline ::capnp::rpc::Payload::Reader getParams() const; + + inline typename SendResultsTo::Reader getSendResultsTo() const; + + inline bool getAllowThirdPartyTailCall() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Call::Builder { +public: + typedef Call Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline ::uint64_t getInterfaceId(); + inline void setInterfaceId( ::uint64_t value); + + inline ::uint16_t getMethodId(); + inline void setMethodId( ::uint16_t value); + + inline bool hasParams(); + inline ::capnp::rpc::Payload::Builder getParams(); + inline void setParams( ::capnp::rpc::Payload::Reader value); + inline ::capnp::rpc::Payload::Builder initParams(); + inline void adoptParams(::capnp::Orphan< ::capnp::rpc::Payload>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Payload> disownParams(); + + inline typename SendResultsTo::Builder getSendResultsTo(); + inline typename SendResultsTo::Builder initSendResultsTo(); + + inline bool getAllowThirdPartyTailCall(); + inline void setAllowThirdPartyTailCall(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Call::Pipeline { +public: + typedef Call Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); + inline ::capnp::rpc::Payload::Pipeline getParams(); + inline typename SendResultsTo::Pipeline getSendResultsTo(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Call::SendResultsTo::Reader { +public: + typedef SendResultsTo Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isCaller() const; + inline ::capnp::Void getCaller() const; + + inline bool isYourself() const; + inline ::capnp::Void getYourself() const; + + inline bool isThirdParty() const; + inline bool hasThirdParty() const; + inline ::capnp::AnyPointer::Reader getThirdParty() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Call::SendResultsTo::Builder { +public: + typedef SendResultsTo Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isCaller(); + inline ::capnp::Void getCaller(); + inline void setCaller( ::capnp::Void value = ::capnp::VOID); + + inline bool isYourself(); + inline ::capnp::Void getYourself(); + inline void setYourself( ::capnp::Void value = ::capnp::VOID); + + inline bool isThirdParty(); + inline bool hasThirdParty(); + inline ::capnp::AnyPointer::Builder getThirdParty(); + inline ::capnp::AnyPointer::Builder initThirdParty(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Call::SendResultsTo::Pipeline { +public: + typedef SendResultsTo Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Return::Reader { +public: + typedef Return Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint32_t getAnswerId() const; + + inline bool getReleaseParamCaps() const; + + inline bool isResults() const; + inline bool hasResults() const; + inline ::capnp::rpc::Payload::Reader getResults() const; + + inline bool isException() const; + inline bool hasException() const; + inline ::capnp::rpc::Exception::Reader getException() const; + + inline bool isCanceled() const; + inline ::capnp::Void getCanceled() const; + + inline bool isResultsSentElsewhere() const; + inline ::capnp::Void getResultsSentElsewhere() const; + + inline bool isTakeFromOtherQuestion() const; + inline ::uint32_t getTakeFromOtherQuestion() const; + + inline bool isAcceptFromThirdParty() const; + inline bool hasAcceptFromThirdParty() const; + inline ::capnp::AnyPointer::Reader getAcceptFromThirdParty() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Return::Builder { +public: + typedef Return Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint32_t getAnswerId(); + inline void setAnswerId( ::uint32_t value); + + inline bool getReleaseParamCaps(); + inline void setReleaseParamCaps(bool value); + + inline bool isResults(); + inline bool hasResults(); + inline ::capnp::rpc::Payload::Builder getResults(); + inline void setResults( ::capnp::rpc::Payload::Reader value); + inline ::capnp::rpc::Payload::Builder initResults(); + inline void adoptResults(::capnp::Orphan< ::capnp::rpc::Payload>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Payload> disownResults(); + + inline bool isException(); + inline bool hasException(); + inline ::capnp::rpc::Exception::Builder getException(); + inline void setException( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initException(); + inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); + + inline bool isCanceled(); + inline ::capnp::Void getCanceled(); + inline void setCanceled( ::capnp::Void value = ::capnp::VOID); + + inline bool isResultsSentElsewhere(); + inline ::capnp::Void getResultsSentElsewhere(); + inline void setResultsSentElsewhere( ::capnp::Void value = ::capnp::VOID); + + inline bool isTakeFromOtherQuestion(); + inline ::uint32_t getTakeFromOtherQuestion(); + inline void setTakeFromOtherQuestion( ::uint32_t value); + + inline bool isAcceptFromThirdParty(); + inline bool hasAcceptFromThirdParty(); + inline ::capnp::AnyPointer::Builder getAcceptFromThirdParty(); + inline ::capnp::AnyPointer::Builder initAcceptFromThirdParty(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Return::Pipeline { +public: + typedef Return Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Finish::Reader { +public: + typedef Finish Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool getReleaseResultCaps() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Finish::Builder { +public: + typedef Finish Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool getReleaseResultCaps(); + inline void setReleaseResultCaps(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Finish::Pipeline { +public: + typedef Finish Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Resolve::Reader { +public: + typedef Resolve Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint32_t getPromiseId() const; + + inline bool isCap() const; + inline bool hasCap() const; + inline ::capnp::rpc::CapDescriptor::Reader getCap() const; + + inline bool isException() const; + inline bool hasException() const; + inline ::capnp::rpc::Exception::Reader getException() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Resolve::Builder { +public: + typedef Resolve Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint32_t getPromiseId(); + inline void setPromiseId( ::uint32_t value); + + inline bool isCap(); + inline bool hasCap(); + inline ::capnp::rpc::CapDescriptor::Builder getCap(); + inline void setCap( ::capnp::rpc::CapDescriptor::Reader value); + inline ::capnp::rpc::CapDescriptor::Builder initCap(); + inline void adoptCap(::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value); + inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> disownCap(); + + inline bool isException(); + inline bool hasException(); + inline ::capnp::rpc::Exception::Builder getException(); + inline void setException( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initException(); + inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Resolve::Pipeline { +public: + typedef Resolve Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Release::Reader { +public: + typedef Release Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getId() const; + + inline ::uint32_t getReferenceCount() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Release::Builder { +public: + typedef Release Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getId(); + inline void setId( ::uint32_t value); + + inline ::uint32_t getReferenceCount(); + inline void setReferenceCount( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Release::Pipeline { +public: + typedef Release Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Disembargo::Reader { +public: + typedef Disembargo Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline typename Context::Reader getContext() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Disembargo::Builder { +public: + typedef Disembargo Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline typename Context::Builder getContext(); + inline typename Context::Builder initContext(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Disembargo::Pipeline { +public: + typedef Disembargo Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); + inline typename Context::Pipeline getContext(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Disembargo::Context::Reader { +public: + typedef Context Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isSenderLoopback() const; + inline ::uint32_t getSenderLoopback() const; + + inline bool isReceiverLoopback() const; + inline ::uint32_t getReceiverLoopback() const; + + inline bool isAccept() const; + inline ::capnp::Void getAccept() const; + + inline bool isProvide() const; + inline ::uint32_t getProvide() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Disembargo::Context::Builder { +public: + typedef Context Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isSenderLoopback(); + inline ::uint32_t getSenderLoopback(); + inline void setSenderLoopback( ::uint32_t value); + + inline bool isReceiverLoopback(); + inline ::uint32_t getReceiverLoopback(); + inline void setReceiverLoopback( ::uint32_t value); + + inline bool isAccept(); + inline ::capnp::Void getAccept(); + inline void setAccept( ::capnp::Void value = ::capnp::VOID); + + inline bool isProvide(); + inline ::uint32_t getProvide(); + inline void setProvide( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Disembargo::Context::Pipeline { +public: + typedef Context Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Provide::Reader { +public: + typedef Provide Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline bool hasRecipient() const; + inline ::capnp::AnyPointer::Reader getRecipient() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Provide::Builder { +public: + typedef Provide Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline bool hasRecipient(); + inline ::capnp::AnyPointer::Builder getRecipient(); + inline ::capnp::AnyPointer::Builder initRecipient(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Provide::Pipeline { +public: + typedef Provide Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Accept::Reader { +public: + typedef Accept Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasProvision() const; + inline ::capnp::AnyPointer::Reader getProvision() const; + + inline bool getEmbargo() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Accept::Builder { +public: + typedef Accept Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasProvision(); + inline ::capnp::AnyPointer::Builder getProvision(); + inline ::capnp::AnyPointer::Builder initProvision(); + + inline bool getEmbargo(); + inline void setEmbargo(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Accept::Pipeline { +public: + typedef Accept Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Join::Reader { +public: + typedef Join Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline bool hasKeyPart() const; + inline ::capnp::AnyPointer::Reader getKeyPart() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Join::Builder { +public: + typedef Join Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline bool hasKeyPart(); + inline ::capnp::AnyPointer::Builder getKeyPart(); + inline ::capnp::AnyPointer::Builder initKeyPart(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Join::Pipeline { +public: + typedef Join Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class MessageTarget::Reader { +public: + typedef MessageTarget Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isImportedCap() const; + inline ::uint32_t getImportedCap() const; + + inline bool isPromisedAnswer() const; + inline bool hasPromisedAnswer() const; + inline ::capnp::rpc::PromisedAnswer::Reader getPromisedAnswer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class MessageTarget::Builder { +public: + typedef MessageTarget Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isImportedCap(); + inline ::uint32_t getImportedCap(); + inline void setImportedCap( ::uint32_t value); + + inline bool isPromisedAnswer(); + inline bool hasPromisedAnswer(); + inline ::capnp::rpc::PromisedAnswer::Builder getPromisedAnswer(); + inline void setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value); + inline ::capnp::rpc::PromisedAnswer::Builder initPromisedAnswer(); + inline void adoptPromisedAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); + inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownPromisedAnswer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class MessageTarget::Pipeline { +public: + typedef MessageTarget Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Payload::Reader { +public: + typedef Payload Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasContent() const; + inline ::capnp::AnyPointer::Reader getContent() const; + + inline bool hasCapTable() const; + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader getCapTable() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Payload::Builder { +public: + typedef Payload Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasContent(); + inline ::capnp::AnyPointer::Builder getContent(); + inline ::capnp::AnyPointer::Builder initContent(); + + inline bool hasCapTable(); + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder getCapTable(); + inline void setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value); + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder initCapTable(unsigned int size); + inline void adoptCapTable(::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> disownCapTable(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Payload::Pipeline { +public: + typedef Payload Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CapDescriptor::Reader { +public: + typedef CapDescriptor Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isSenderHosted() const; + inline ::uint32_t getSenderHosted() const; + + inline bool isSenderPromise() const; + inline ::uint32_t getSenderPromise() const; + + inline bool isReceiverHosted() const; + inline ::uint32_t getReceiverHosted() const; + + inline bool isReceiverAnswer() const; + inline bool hasReceiverAnswer() const; + inline ::capnp::rpc::PromisedAnswer::Reader getReceiverAnswer() const; + + inline bool isThirdPartyHosted() const; + inline bool hasThirdPartyHosted() const; + inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader getThirdPartyHosted() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CapDescriptor::Builder { +public: + typedef CapDescriptor Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isSenderHosted(); + inline ::uint32_t getSenderHosted(); + inline void setSenderHosted( ::uint32_t value); + + inline bool isSenderPromise(); + inline ::uint32_t getSenderPromise(); + inline void setSenderPromise( ::uint32_t value); + + inline bool isReceiverHosted(); + inline ::uint32_t getReceiverHosted(); + inline void setReceiverHosted( ::uint32_t value); + + inline bool isReceiverAnswer(); + inline bool hasReceiverAnswer(); + inline ::capnp::rpc::PromisedAnswer::Builder getReceiverAnswer(); + inline void setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value); + inline ::capnp::rpc::PromisedAnswer::Builder initReceiverAnswer(); + inline void adoptReceiverAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); + inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownReceiverAnswer(); + + inline bool isThirdPartyHosted(); + inline bool hasThirdPartyHosted(); + inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder getThirdPartyHosted(); + inline void setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value); + inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder initThirdPartyHosted(); + inline void adoptThirdPartyHosted(::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value); + inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> disownThirdPartyHosted(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CapDescriptor::Pipeline { +public: + typedef CapDescriptor Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class PromisedAnswer::Reader { +public: + typedef PromisedAnswer Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTransform() const; + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader getTransform() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class PromisedAnswer::Builder { +public: + typedef PromisedAnswer Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTransform(); + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder getTransform(); + inline void setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value); + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder initTransform(unsigned int size); + inline void adoptTransform(::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> disownTransform(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class PromisedAnswer::Pipeline { +public: + typedef PromisedAnswer Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class PromisedAnswer::Op::Reader { +public: + typedef Op Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNoop() const; + inline ::capnp::Void getNoop() const; + + inline bool isGetPointerField() const; + inline ::uint16_t getGetPointerField() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class PromisedAnswer::Op::Builder { +public: + typedef Op Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNoop(); + inline ::capnp::Void getNoop(); + inline void setNoop( ::capnp::Void value = ::capnp::VOID); + + inline bool isGetPointerField(); + inline ::uint16_t getGetPointerField(); + inline void setGetPointerField( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class PromisedAnswer::Op::Pipeline { +public: + typedef Op Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ThirdPartyCapDescriptor::Reader { +public: + typedef ThirdPartyCapDescriptor Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasId() const; + inline ::capnp::AnyPointer::Reader getId() const; + + inline ::uint32_t getVineId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ThirdPartyCapDescriptor::Builder { +public: + typedef ThirdPartyCapDescriptor Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasId(); + inline ::capnp::AnyPointer::Builder getId(); + inline ::capnp::AnyPointer::Builder initId(); + + inline ::uint32_t getVineId(); + inline void setVineId( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ThirdPartyCapDescriptor::Pipeline { +public: + typedef ThirdPartyCapDescriptor Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Exception::Reader { +public: + typedef Exception Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasReason() const; + inline ::capnp::Text::Reader getReason() const; + + inline bool getObsoleteIsCallersFault() const; + + inline ::uint16_t getObsoleteDurability() const; + + inline ::capnp::rpc::Exception::Type getType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Exception::Builder { +public: + typedef Exception Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasReason(); + inline ::capnp::Text::Builder getReason(); + inline void setReason( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initReason(unsigned int size); + inline void adoptReason(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownReason(); + + inline bool getObsoleteIsCallersFault(); + inline void setObsoleteIsCallersFault(bool value); + + inline ::uint16_t getObsoleteDurability(); + inline void setObsoleteDurability( ::uint16_t value); + + inline ::capnp::rpc::Exception::Type getType(); + inline void setType( ::capnp::rpc::Exception::Type value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Exception::Pipeline { +public: + typedef Exception Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::rpc::Message::Which Message::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Message::Which Message::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Message::Reader::isUnimplemented() const { + return which() == Message::UNIMPLEMENTED; +} +inline bool Message::Builder::isUnimplemented() { + return which() == Message::UNIMPLEMENTED; +} +inline bool Message::Reader::hasUnimplemented() const { + if (which() != Message::UNIMPLEMENTED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasUnimplemented() { + if (which() != Message::UNIMPLEMENTED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Message::Reader Message::Reader::getUnimplemented() const { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Message::Builder Message::Builder::getUnimplemented() { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setUnimplemented( ::capnp::rpc::Message::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Message::Builder Message::Builder::initUnimplemented() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptUnimplemented( + ::capnp::Orphan< ::capnp::rpc::Message>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Message> Message::Builder::disownUnimplemented() { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isAbort() const { + return which() == Message::ABORT; +} +inline bool Message::Builder::isAbort() { + return which() == Message::ABORT; +} +inline bool Message::Reader::hasAbort() const { + if (which() != Message::ABORT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasAbort() { + if (which() != Message::ABORT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Message::Reader::getAbort() const { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Message::Builder::getAbort() { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setAbort( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Message::Builder::initAbort() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptAbort( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Message::Builder::disownAbort() { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isCall() const { + return which() == Message::CALL; +} +inline bool Message::Builder::isCall() { + return which() == Message::CALL; +} +inline bool Message::Reader::hasCall() const { + if (which() != Message::CALL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasCall() { + if (which() != Message::CALL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Call::Reader Message::Reader::getCall() const { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Call::Builder Message::Builder::getCall() { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setCall( ::capnp::rpc::Call::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Call::Builder Message::Builder::initCall() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptCall( + ::capnp::Orphan< ::capnp::rpc::Call>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Call> Message::Builder::disownCall() { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isReturn() const { + return which() == Message::RETURN; +} +inline bool Message::Builder::isReturn() { + return which() == Message::RETURN; +} +inline bool Message::Reader::hasReturn() const { + if (which() != Message::RETURN) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasReturn() { + if (which() != Message::RETURN) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Return::Reader Message::Reader::getReturn() const { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Return::Builder Message::Builder::getReturn() { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setReturn( ::capnp::rpc::Return::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Return::Builder Message::Builder::initReturn() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptReturn( + ::capnp::Orphan< ::capnp::rpc::Return>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Return> Message::Builder::disownReturn() { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isFinish() const { + return which() == Message::FINISH; +} +inline bool Message::Builder::isFinish() { + return which() == Message::FINISH; +} +inline bool Message::Reader::hasFinish() const { + if (which() != Message::FINISH) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasFinish() { + if (which() != Message::FINISH) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Finish::Reader Message::Reader::getFinish() const { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Finish::Builder Message::Builder::getFinish() { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setFinish( ::capnp::rpc::Finish::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Finish::Builder Message::Builder::initFinish() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptFinish( + ::capnp::Orphan< ::capnp::rpc::Finish>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Finish> Message::Builder::disownFinish() { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isResolve() const { + return which() == Message::RESOLVE; +} +inline bool Message::Builder::isResolve() { + return which() == Message::RESOLVE; +} +inline bool Message::Reader::hasResolve() const { + if (which() != Message::RESOLVE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasResolve() { + if (which() != Message::RESOLVE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Resolve::Reader Message::Reader::getResolve() const { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Resolve::Builder Message::Builder::getResolve() { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setResolve( ::capnp::rpc::Resolve::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Resolve::Builder Message::Builder::initResolve() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptResolve( + ::capnp::Orphan< ::capnp::rpc::Resolve>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Resolve> Message::Builder::disownResolve() { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isRelease() const { + return which() == Message::RELEASE; +} +inline bool Message::Builder::isRelease() { + return which() == Message::RELEASE; +} +inline bool Message::Reader::hasRelease() const { + if (which() != Message::RELEASE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasRelease() { + if (which() != Message::RELEASE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Release::Reader Message::Reader::getRelease() const { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Release::Builder Message::Builder::getRelease() { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setRelease( ::capnp::rpc::Release::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Release::Builder Message::Builder::initRelease() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptRelease( + ::capnp::Orphan< ::capnp::rpc::Release>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Release> Message::Builder::disownRelease() { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isObsoleteSave() const { + return which() == Message::OBSOLETE_SAVE; +} +inline bool Message::Builder::isObsoleteSave() { + return which() == Message::OBSOLETE_SAVE; +} +inline bool Message::Reader::hasObsoleteSave() const { + if (which() != Message::OBSOLETE_SAVE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasObsoleteSave() { + if (which() != Message::OBSOLETE_SAVE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteSave() const { + KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteSave() { + KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteSave() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::OBSOLETE_SAVE); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Message::Reader::isBootstrap() const { + return which() == Message::BOOTSTRAP; +} +inline bool Message::Builder::isBootstrap() { + return which() == Message::BOOTSTRAP; +} +inline bool Message::Reader::hasBootstrap() const { + if (which() != Message::BOOTSTRAP) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasBootstrap() { + if (which() != Message::BOOTSTRAP) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Bootstrap::Reader Message::Reader::getBootstrap() const { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Bootstrap::Builder Message::Builder::getBootstrap() { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setBootstrap( ::capnp::rpc::Bootstrap::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Bootstrap::Builder Message::Builder::initBootstrap() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptBootstrap( + ::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> Message::Builder::disownBootstrap() { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isObsoleteDelete() const { + return which() == Message::OBSOLETE_DELETE; +} +inline bool Message::Builder::isObsoleteDelete() { + return which() == Message::OBSOLETE_DELETE; +} +inline bool Message::Reader::hasObsoleteDelete() const { + if (which() != Message::OBSOLETE_DELETE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasObsoleteDelete() { + if (which() != Message::OBSOLETE_DELETE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteDelete() const { + KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteDelete() { + KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteDelete() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::OBSOLETE_DELETE); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Message::Reader::isProvide() const { + return which() == Message::PROVIDE; +} +inline bool Message::Builder::isProvide() { + return which() == Message::PROVIDE; +} +inline bool Message::Reader::hasProvide() const { + if (which() != Message::PROVIDE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasProvide() { + if (which() != Message::PROVIDE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Provide::Reader Message::Reader::getProvide() const { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Provide::Builder Message::Builder::getProvide() { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setProvide( ::capnp::rpc::Provide::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Provide::Builder Message::Builder::initProvide() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptProvide( + ::capnp::Orphan< ::capnp::rpc::Provide>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Provide> Message::Builder::disownProvide() { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isAccept() const { + return which() == Message::ACCEPT; +} +inline bool Message::Builder::isAccept() { + return which() == Message::ACCEPT; +} +inline bool Message::Reader::hasAccept() const { + if (which() != Message::ACCEPT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasAccept() { + if (which() != Message::ACCEPT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Accept::Reader Message::Reader::getAccept() const { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Accept::Builder Message::Builder::getAccept() { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setAccept( ::capnp::rpc::Accept::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Accept::Builder Message::Builder::initAccept() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptAccept( + ::capnp::Orphan< ::capnp::rpc::Accept>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Accept> Message::Builder::disownAccept() { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isJoin() const { + return which() == Message::JOIN; +} +inline bool Message::Builder::isJoin() { + return which() == Message::JOIN; +} +inline bool Message::Reader::hasJoin() const { + if (which() != Message::JOIN) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasJoin() { + if (which() != Message::JOIN) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Join::Reader Message::Reader::getJoin() const { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Join::Builder Message::Builder::getJoin() { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setJoin( ::capnp::rpc::Join::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Join::Builder Message::Builder::initJoin() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptJoin( + ::capnp::Orphan< ::capnp::rpc::Join>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Join> Message::Builder::disownJoin() { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isDisembargo() const { + return which() == Message::DISEMBARGO; +} +inline bool Message::Builder::isDisembargo() { + return which() == Message::DISEMBARGO; +} +inline bool Message::Reader::hasDisembargo() const { + if (which() != Message::DISEMBARGO) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasDisembargo() { + if (which() != Message::DISEMBARGO) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Disembargo::Reader Message::Reader::getDisembargo() const { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Disembargo::Builder Message::Builder::getDisembargo() { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setDisembargo( ::capnp::rpc::Disembargo::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Disembargo::Builder Message::Builder::initDisembargo() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptDisembargo( + ::capnp::Orphan< ::capnp::rpc::Disembargo>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Disembargo> Message::Builder::disownDisembargo() { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Bootstrap::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Bootstrap::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Bootstrap::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Bootstrap::Reader::hasDeprecatedObjectId() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Bootstrap::Builder::hasDeprecatedObjectId() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Bootstrap::Reader::getDeprecatedObjectId() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Bootstrap::Builder::getDeprecatedObjectId() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Bootstrap::Builder::initDeprecatedObjectId() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Call::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Call::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Call::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Call::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Call::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Call::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Call::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Call::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Call::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Call::Reader::getInterfaceId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Call::Builder::getInterfaceId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setInterfaceId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Call::Reader::getMethodId() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Call::Builder::getMethodId() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setMethodId( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Payload::Reader Call::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Payload::Builder Call::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::Payload::Pipeline Call::Pipeline::getParams() { + return ::capnp::rpc::Payload::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Call::Builder::setParams( ::capnp::rpc::Payload::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Payload::Builder Call::Builder::initParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Call::Builder::adoptParams( + ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Payload> Call::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline typename Call::SendResultsTo::Reader Call::Reader::getSendResultsTo() const { + return typename Call::SendResultsTo::Reader(_reader); +} +inline typename Call::SendResultsTo::Builder Call::Builder::getSendResultsTo() { + return typename Call::SendResultsTo::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Call::SendResultsTo::Pipeline Call::Pipeline::getSendResultsTo() { + return typename Call::SendResultsTo::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Call::SendResultsTo::Builder Call::Builder::initSendResultsTo() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<3>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<2>() * ::capnp::POINTERS).clear(); + return typename Call::SendResultsTo::Builder(_builder); +} +inline bool Call::Reader::getAllowThirdPartyTailCall() const { + return _reader.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} + +inline bool Call::Builder::getAllowThirdPartyTailCall() { + return _builder.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setAllowThirdPartyTailCall(bool value) { + _builder.setDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline bool Call::SendResultsTo::Reader::isCaller() const { + return which() == Call::SendResultsTo::CALLER; +} +inline bool Call::SendResultsTo::Builder::isCaller() { + return which() == Call::SendResultsTo::CALLER; +} +inline ::capnp::Void Call::SendResultsTo::Reader::getCaller() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Call::SendResultsTo::Builder::getCaller() { + KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::SendResultsTo::Builder::setCaller( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::CALLER); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::SendResultsTo::Reader::isYourself() const { + return which() == Call::SendResultsTo::YOURSELF; +} +inline bool Call::SendResultsTo::Builder::isYourself() { + return which() == Call::SendResultsTo::YOURSELF; +} +inline ::capnp::Void Call::SendResultsTo::Reader::getYourself() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Call::SendResultsTo::Builder::getYourself() { + KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::SendResultsTo::Builder::setYourself( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::YOURSELF); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::SendResultsTo::Reader::isThirdParty() const { + return which() == Call::SendResultsTo::THIRD_PARTY; +} +inline bool Call::SendResultsTo::Builder::isThirdParty() { + return which() == Call::SendResultsTo::THIRD_PARTY; +} +inline bool Call::SendResultsTo::Reader::hasThirdParty() const { + if (which() != Call::SendResultsTo::THIRD_PARTY) return false; + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::SendResultsTo::Builder::hasThirdParty() { + if (which() != Call::SendResultsTo::THIRD_PARTY) return false; + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Call::SendResultsTo::Reader::getThirdParty() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::getThirdParty() { + KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::initThirdParty() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::THIRD_PARTY); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::capnp::rpc::Return::Which Return::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Return::Which Return::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Reader::getAnswerId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Builder::getAnswerId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setAnswerId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::getReleaseParamCaps() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} + +inline bool Return::Builder::getReleaseParamCaps() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} +inline void Return::Builder::setReleaseParamCaps(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value, true); +} + +inline bool Return::Reader::isResults() const { + return which() == Return::RESULTS; +} +inline bool Return::Builder::isResults() { + return which() == Return::RESULTS; +} +inline bool Return::Reader::hasResults() const { + if (which() != Return::RESULTS) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasResults() { + if (which() != Return::RESULTS) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Payload::Reader Return::Reader::getResults() const { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Payload::Builder Return::Builder::getResults() { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::setResults( ::capnp::rpc::Payload::Reader value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Payload::Builder Return::Builder::initResults() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::adoptResults( + ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Payload> Return::Builder::disownResults() { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Return::Reader::isException() const { + return which() == Return::EXCEPTION; +} +inline bool Return::Builder::isException() { + return which() == Return::EXCEPTION; +} +inline bool Return::Reader::hasException() const { + if (which() != Return::EXCEPTION) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasException() { + if (which() != Return::EXCEPTION) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Return::Reader::getException() const { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Return::Builder::getException() { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::setException( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Return::Builder::initException() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::adoptException( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Return::Builder::disownException() { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Return::Reader::isCanceled() const { + return which() == Return::CANCELED; +} +inline bool Return::Builder::isCanceled() { + return which() == Return::CANCELED; +} +inline ::capnp::Void Return::Reader::getCanceled() const { + KJ_IREQUIRE((which() == Return::CANCELED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Return::Builder::getCanceled() { + KJ_IREQUIRE((which() == Return::CANCELED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setCanceled( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::CANCELED); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isResultsSentElsewhere() const { + return which() == Return::RESULTS_SENT_ELSEWHERE; +} +inline bool Return::Builder::isResultsSentElsewhere() { + return which() == Return::RESULTS_SENT_ELSEWHERE; +} +inline ::capnp::Void Return::Reader::getResultsSentElsewhere() const { + KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Return::Builder::getResultsSentElsewhere() { + KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setResultsSentElsewhere( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS_SENT_ELSEWHERE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isTakeFromOtherQuestion() const { + return which() == Return::TAKE_FROM_OTHER_QUESTION; +} +inline bool Return::Builder::isTakeFromOtherQuestion() { + return which() == Return::TAKE_FROM_OTHER_QUESTION; +} +inline ::uint32_t Return::Reader::getTakeFromOtherQuestion() const { + KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Builder::getTakeFromOtherQuestion() { + KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setTakeFromOtherQuestion( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::TAKE_FROM_OTHER_QUESTION); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isAcceptFromThirdParty() const { + return which() == Return::ACCEPT_FROM_THIRD_PARTY; +} +inline bool Return::Builder::isAcceptFromThirdParty() { + return which() == Return::ACCEPT_FROM_THIRD_PARTY; +} +inline bool Return::Reader::hasAcceptFromThirdParty() const { + if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasAcceptFromThirdParty() { + if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Return::Reader::getAcceptFromThirdParty() const { + KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Return::Builder::getAcceptFromThirdParty() { + KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Return::Builder::initAcceptFromThirdParty() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::ACCEPT_FROM_THIRD_PARTY); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Finish::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Finish::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Finish::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Finish::Reader::getReleaseResultCaps() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} + +inline bool Finish::Builder::getReleaseResultCaps() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} +inline void Finish::Builder::setReleaseResultCaps(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value, true); +} + +inline ::capnp::rpc::Resolve::Which Resolve::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Resolve::Which Resolve::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Resolve::Reader::getPromiseId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Resolve::Builder::getPromiseId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Resolve::Builder::setPromiseId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Resolve::Reader::isCap() const { + return which() == Resolve::CAP; +} +inline bool Resolve::Builder::isCap() { + return which() == Resolve::CAP; +} +inline bool Resolve::Reader::hasCap() const { + if (which() != Resolve::CAP) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Resolve::Builder::hasCap() { + if (which() != Resolve::CAP) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::CapDescriptor::Reader Resolve::Reader::getCap() const { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::getCap() { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::setCap( ::capnp::rpc::CapDescriptor::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::initCap() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::adoptCap( + ::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> Resolve::Builder::disownCap() { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Resolve::Reader::isException() const { + return which() == Resolve::EXCEPTION; +} +inline bool Resolve::Builder::isException() { + return which() == Resolve::EXCEPTION; +} +inline bool Resolve::Reader::hasException() const { + if (which() != Resolve::EXCEPTION) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Resolve::Builder::hasException() { + if (which() != Resolve::EXCEPTION) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Resolve::Reader::getException() const { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Resolve::Builder::getException() { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::setException( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Resolve::Builder::initException() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::adoptException( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Resolve::Builder::disownException() { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Release::Reader::getId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Release::Builder::getId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Release::Builder::setId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Release::Reader::getReferenceCount() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Release::Builder::getReferenceCount() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Release::Builder::setReferenceCount( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Disembargo::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Disembargo::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Disembargo::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Disembargo::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Disembargo::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Disembargo::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline typename Disembargo::Context::Reader Disembargo::Reader::getContext() const { + return typename Disembargo::Context::Reader(_reader); +} +inline typename Disembargo::Context::Builder Disembargo::Builder::getContext() { + return typename Disembargo::Context::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Disembargo::Context::Pipeline Disembargo::Pipeline::getContext() { + return typename Disembargo::Context::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Disembargo::Context::Builder Disembargo::Builder::initContext() { + _builder.setDataField< ::uint32_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Disembargo::Context::Builder(_builder); +} +inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline bool Disembargo::Context::Reader::isSenderLoopback() const { + return which() == Disembargo::Context::SENDER_LOOPBACK; +} +inline bool Disembargo::Context::Builder::isSenderLoopback() { + return which() == Disembargo::Context::SENDER_LOOPBACK; +} +inline ::uint32_t Disembargo::Context::Reader::getSenderLoopback() const { + KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getSenderLoopback() { + KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setSenderLoopback( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::SENDER_LOOPBACK); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isReceiverLoopback() const { + return which() == Disembargo::Context::RECEIVER_LOOPBACK; +} +inline bool Disembargo::Context::Builder::isReceiverLoopback() { + return which() == Disembargo::Context::RECEIVER_LOOPBACK; +} +inline ::uint32_t Disembargo::Context::Reader::getReceiverLoopback() const { + KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getReceiverLoopback() { + KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setReceiverLoopback( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::RECEIVER_LOOPBACK); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isAccept() const { + return which() == Disembargo::Context::ACCEPT; +} +inline bool Disembargo::Context::Builder::isAccept() { + return which() == Disembargo::Context::ACCEPT; +} +inline ::capnp::Void Disembargo::Context::Reader::getAccept() const { + KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Disembargo::Context::Builder::getAccept() { + KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setAccept( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::ACCEPT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isProvide() const { + return which() == Disembargo::Context::PROVIDE; +} +inline bool Disembargo::Context::Builder::isProvide() { + return which() == Disembargo::Context::PROVIDE; +} +inline ::uint32_t Disembargo::Context::Reader::getProvide() const { + KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getProvide() { + KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setProvide( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::PROVIDE); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Provide::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Provide::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Provide::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Provide::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Provide::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Provide::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Provide::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Provide::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Provide::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Provide::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Provide::Reader::hasRecipient() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Provide::Builder::hasRecipient() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Provide::Reader::getRecipient() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Provide::Builder::getRecipient() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Provide::Builder::initRecipient() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Accept::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Accept::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Accept::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Accept::Reader::hasProvision() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Accept::Builder::hasProvision() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Accept::Reader::getProvision() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Accept::Builder::getProvision() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Accept::Builder::initProvision() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Accept::Reader::getEmbargo() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} + +inline bool Accept::Builder::getEmbargo() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} +inline void Accept::Builder::setEmbargo(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Join::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Join::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Join::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Join::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Join::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Join::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Join::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Join::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Join::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Join::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Join::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Join::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Join::Reader::hasKeyPart() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Join::Builder::hasKeyPart() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Join::Reader::getKeyPart() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Join::Builder::getKeyPart() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Join::Builder::initKeyPart() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::capnp::rpc::MessageTarget::Which MessageTarget::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::MessageTarget::Which MessageTarget::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline bool MessageTarget::Reader::isImportedCap() const { + return which() == MessageTarget::IMPORTED_CAP; +} +inline bool MessageTarget::Builder::isImportedCap() { + return which() == MessageTarget::IMPORTED_CAP; +} +inline ::uint32_t MessageTarget::Reader::getImportedCap() const { + KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t MessageTarget::Builder::getImportedCap() { + KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void MessageTarget::Builder::setImportedCap( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::IMPORTED_CAP); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool MessageTarget::Reader::isPromisedAnswer() const { + return which() == MessageTarget::PROMISED_ANSWER; +} +inline bool MessageTarget::Builder::isPromisedAnswer() { + return which() == MessageTarget::PROMISED_ANSWER; +} +inline bool MessageTarget::Reader::hasPromisedAnswer() const { + if (which() != MessageTarget::PROMISED_ANSWER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool MessageTarget::Builder::hasPromisedAnswer() { + if (which() != MessageTarget::PROMISED_ANSWER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::PromisedAnswer::Reader MessageTarget::Reader::getPromisedAnswer() const { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::getPromisedAnswer() { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void MessageTarget::Builder::setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::initPromisedAnswer() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void MessageTarget::Builder::adoptPromisedAnswer( + ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> MessageTarget::Builder::disownPromisedAnswer() { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Payload::Reader::hasContent() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Payload::Builder::hasContent() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Payload::Reader::getContent() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Payload::Builder::getContent() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Payload::Builder::initContent() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Payload::Reader::hasCapTable() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Payload::Builder::hasCapTable() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader Payload::Reader::getCapTable() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::getCapTable() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Payload::Builder::setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::initCapTable(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Payload::Builder::adoptCapTable( + ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> Payload::Builder::disownCapTable() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool CapDescriptor::Reader::isNone() const { + return which() == CapDescriptor::NONE; +} +inline bool CapDescriptor::Builder::isNone() { + return which() == CapDescriptor::NONE; +} +inline ::capnp::Void CapDescriptor::Reader::getNone() const { + KJ_IREQUIRE((which() == CapDescriptor::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void CapDescriptor::Builder::getNone() { + KJ_IREQUIRE((which() == CapDescriptor::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isSenderHosted() const { + return which() == CapDescriptor::SENDER_HOSTED; +} +inline bool CapDescriptor::Builder::isSenderHosted() { + return which() == CapDescriptor::SENDER_HOSTED; +} +inline ::uint32_t CapDescriptor::Reader::getSenderHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getSenderHosted() { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setSenderHosted( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::SENDER_HOSTED); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isSenderPromise() const { + return which() == CapDescriptor::SENDER_PROMISE; +} +inline bool CapDescriptor::Builder::isSenderPromise() { + return which() == CapDescriptor::SENDER_PROMISE; +} +inline ::uint32_t CapDescriptor::Reader::getSenderPromise() const { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getSenderPromise() { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setSenderPromise( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::SENDER_PROMISE); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isReceiverHosted() const { + return which() == CapDescriptor::RECEIVER_HOSTED; +} +inline bool CapDescriptor::Builder::isReceiverHosted() { + return which() == CapDescriptor::RECEIVER_HOSTED; +} +inline ::uint32_t CapDescriptor::Reader::getReceiverHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getReceiverHosted() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setReceiverHosted( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_HOSTED); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isReceiverAnswer() const { + return which() == CapDescriptor::RECEIVER_ANSWER; +} +inline bool CapDescriptor::Builder::isReceiverAnswer() { + return which() == CapDescriptor::RECEIVER_ANSWER; +} +inline bool CapDescriptor::Reader::hasReceiverAnswer() const { + if (which() != CapDescriptor::RECEIVER_ANSWER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CapDescriptor::Builder::hasReceiverAnswer() { + if (which() != CapDescriptor::RECEIVER_ANSWER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::PromisedAnswer::Reader CapDescriptor::Reader::getReceiverAnswer() const { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::getReceiverAnswer() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::initReceiverAnswer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::adoptReceiverAnswer( + ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> CapDescriptor::Builder::disownReceiverAnswer() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CapDescriptor::Reader::isThirdPartyHosted() const { + return which() == CapDescriptor::THIRD_PARTY_HOSTED; +} +inline bool CapDescriptor::Builder::isThirdPartyHosted() { + return which() == CapDescriptor::THIRD_PARTY_HOSTED; +} +inline bool CapDescriptor::Reader::hasThirdPartyHosted() const { + if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CapDescriptor::Builder::hasThirdPartyHosted() { + if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader CapDescriptor::Reader::getThirdPartyHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::getThirdPartyHosted() { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::initThirdPartyHosted() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::adoptThirdPartyHosted( + ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> CapDescriptor::Builder::disownThirdPartyHosted() { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t PromisedAnswer::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t PromisedAnswer::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool PromisedAnswer::Reader::hasTransform() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool PromisedAnswer::Builder::hasTransform() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader PromisedAnswer::Reader::getTransform() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::getTransform() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void PromisedAnswer::Builder::setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::initTransform(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void PromisedAnswer::Builder::adoptTransform( + ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> PromisedAnswer::Builder::disownTransform() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool PromisedAnswer::Op::Reader::isNoop() const { + return which() == PromisedAnswer::Op::NOOP; +} +inline bool PromisedAnswer::Op::Builder::isNoop() { + return which() == PromisedAnswer::Op::NOOP; +} +inline ::capnp::Void PromisedAnswer::Op::Reader::getNoop() const { + KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void PromisedAnswer::Op::Builder::getNoop() { + KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Op::Builder::setNoop( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, PromisedAnswer::Op::NOOP); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool PromisedAnswer::Op::Reader::isGetPointerField() const { + return which() == PromisedAnswer::Op::GET_POINTER_FIELD; +} +inline bool PromisedAnswer::Op::Builder::isGetPointerField() { + return which() == PromisedAnswer::Op::GET_POINTER_FIELD; +} +inline ::uint16_t PromisedAnswer::Op::Reader::getGetPointerField() const { + KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t PromisedAnswer::Op::Builder::getGetPointerField() { + KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Op::Builder::setGetPointerField( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, PromisedAnswer::Op::GET_POINTER_FIELD); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool ThirdPartyCapDescriptor::Reader::hasId() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool ThirdPartyCapDescriptor::Builder::hasId() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader ThirdPartyCapDescriptor::Reader::getId() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::getId() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::initId() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t ThirdPartyCapDescriptor::Reader::getVineId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t ThirdPartyCapDescriptor::Builder::getVineId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void ThirdPartyCapDescriptor::Builder::setVineId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Exception::Reader::hasReason() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Exception::Builder::hasReason() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Exception::Reader::getReason() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Exception::Builder::getReason() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Exception::Builder::setReason( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Exception::Builder::initReason(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Exception::Builder::adoptReason( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Exception::Builder::disownReason() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Exception::Reader::getObsoleteIsCallersFault() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Exception::Builder::getObsoleteIsCallersFault() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setObsoleteIsCallersFault(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Exception::Reader::getObsoleteDurability() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Exception::Builder::getObsoleteDurability() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setObsoleteDurability( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::rpc::Exception::Type Exception::Reader::getType() const { + return _reader.getDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::capnp::rpc::Exception::Type Exception::Builder::getType() { + return _builder.getDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setType( ::capnp::rpc::Exception::Type value) { + _builder.setDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_b312981b2552a250_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/rpc.h --- a/osx/include/capnp/rpc.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/rpc.h Mon May 22 10:01:37 2017 +0100 @@ -1,537 +1,537 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_RPC_H_ -#define CAPNP_RPC_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "capability.h" -#include "rpc-prelude.h" - -namespace capnp { - -template -class VatNetwork; -template -class SturdyRefRestorer; - -template -class BootstrapFactory: public _::BootstrapFactoryBase { - // Interface that constructs per-client bootstrap interfaces. Use this if you want each client - // who connects to see a different bootstrap interface based on their (authenticated) VatId. - // This allows an application to bootstrap off of the authentication performed at the VatNetwork - // level. (Typically VatId is some sort of public key.) - // - // This is only useful for multi-party networks. For TwoPartyVatNetwork, there's no reason to - // use a BootstrapFactory; just specify a single bootstrap capability in this case. - -public: - virtual Capability::Client createFor(typename VatId::Reader clientId) = 0; - // Create a bootstrap capability appropriate for exposing to the given client. VatNetwork will - // have authenticated the client VatId before this is called. - -private: - Capability::Client baseCreateFor(AnyStruct::Reader clientId) override; -}; - -template -class RpcSystem: public _::RpcSystemBase { - // Represents the RPC system, which is the portal to objects available on the network. - // - // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` - // determines how to form connections between vats -- specifically, two-way, private, reliable, - // sequenced datagram connections. The RPC implementation determines how to use such connections - // to manage object references and make method calls. - // - // See `makeRpcServer()` and `makeRpcClient()` below for convenient syntax for setting up an - // `RpcSystem` given a `VatNetwork`. - // - // See `ez-rpc.h` for an even simpler interface for setting up RPC in a typical two-party - // client/server scenario. - -public: - template - RpcSystem( - VatNetwork& network, - kj::Maybe bootstrapInterface, - kj::Maybe::Client> gateway = nullptr); - - template - RpcSystem( - VatNetwork& network, - BootstrapFactory& bootstrapFactory, - kj::Maybe::Client> gateway = nullptr); - - template - RpcSystem( - VatNetwork& network, - SturdyRefRestorer& restorer); - - RpcSystem(RpcSystem&& other) = default; - - Capability::Client bootstrap(typename VatId::Reader vatId); - // Connect to the given vat and return its bootstrap interface. - - Capability::Client restore(typename VatId::Reader hostId, AnyPointer::Reader objectId) - KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); - // ** DEPRECATED ** - // - // Restores the given SturdyRef from the network and return the capability representing it. - // - // `hostId` identifies the host from which to request the ref, in the format specified by the - // `VatNetwork` in use. `objectId` is the object ID in whatever format is expected by said host. - // - // This method will be removed in a future version of Cap'n Proto. Instead, please transition - // to using bootstrap(), which is equivalent to calling restore() with a null `objectId`. - // You may emulate the old concept of object IDs by exporting a bootstrap interface which has - // methods that can be used to obtain other capabilities by ID. - - void setFlowLimit(size_t words); - // Sets the incoming call flow limit. If more than `words` worth of call messages have not yet - // received responses, the RpcSystem will not read further messages from the stream. This can be - // used as a crude way to prevent a resource exhaustion attack (or bug) in which a peer makes an - // excessive number of simultaneous calls that consume the receiver's RAM. - // - // There are some caveats. When over the flow limit, all messages are blocked, including returns. - // If the outstanding calls are themselves waiting on calls going in the opposite direction, the - // flow limit may prevent those calls from completing, leading to deadlock. However, a - // sufficiently high limit should make this unlikely. - // - // Note that a call's parameter size counts against the flow limit until the call returns, even - // if the recipient calls releaseParams() to free the parameter memory early. This is because - // releaseParams() may simply indicate that the parameters have been forwarded to another - // machine, but are still in-memory there. For illustration, say that Alice made a call to Bob - // who forwarded the call to Carol. Bob has imposed a flow limit on Alice. Alice's calls are - // being forwarded to Carol, so Bob never keeps the parameters in-memory for more than a brief - // period. However, the flow limit counts all calls that haven't returned, even if Bob has - // already freed the memory they consumed. You might argue that the right solution here is - // instead for Carol to impose her own flow limit on Bob. This has a serious problem, though: - // Bob might be forwarding requests to Carol on behalf of many different parties, not just Alice. - // If Alice can pump enough data to hit the Bob -> Carol flow limit, then those other parties - // will be disrupted. Thus, we can only really impose the limit on the Alice -> Bob link, which - // only affects Alice. We need that one flow limit to limit Alice's impact on the whole system, - // so it has to count all in-flight calls. - // - // In Sandstorm, flow limits are imposed by the supervisor on calls coming out of a grain, in - // order to prevent a grain from inundating the system with in-flight calls. In practice, the - // main time this happens is when a grain is pushing a large file download and doesn't implement - // proper cooperative flow control. -}; - -template -RpcSystem makeRpcServer( - VatNetwork& network, - Capability::Client bootstrapInterface); -// Make an RPC server. Typical usage (e.g. in a main() function): -// -// MyEventLoop eventLoop; -// kj::WaitScope waitScope(eventLoop); -// MyNetwork network; -// MyMainInterface::Client bootstrap = makeMain(); -// auto server = makeRpcServer(network, bootstrap); -// kj::NEVER_DONE.wait(waitScope); // run forever -// -// See also ez-rpc.h, which has simpler instructions for the common case of a two-party -// client-server RPC connection. - -template , - typename ExternalRef = _::ExternalRefFromRealmGatewayClient> -RpcSystem makeRpcServer( - VatNetwork& network, - Capability::Client bootstrapInterface, RealmGatewayClient gateway); -// Make an RPC server for a VatNetwork that resides in a different realm from the application. -// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format -// and the network's ("external") format. - -template -RpcSystem makeRpcServer( - VatNetwork& network, - BootstrapFactory& bootstrapFactory); -// Make an RPC server that can serve different bootstrap interfaces to different clients via a -// BootstrapInterface. - -template , - typename ExternalRef = _::ExternalRefFromRealmGatewayClient> -RpcSystem makeRpcServer( - VatNetwork& network, - BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway); -// Make an RPC server that can serve different bootstrap interfaces to different clients via a -// BootstrapInterface and communicates with a different realm than the application is in via a -// RealmGateway. - -template -RpcSystem makeRpcServer( - VatNetwork& network, - SturdyRefRestorer& restorer) - KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); -// ** DEPRECATED ** -// -// Create an RPC server which exports multiple main interfaces by object ID. The `restorer` object -// can be used to look up objects by ID. -// -// Please transition to exporting only one interface, which is known as the "bootstrap" interface. -// For backwards-compatibility with old clients, continue to implement SturdyRefRestorer, but -// return the new bootstrap interface when the request object ID is null. When new clients connect -// and request the bootstrap interface, they will get that interface. Eventually, once all clients -// are updated to request only the bootstrap interface, stop implementing SturdyRefRestorer and -// switch to passing the bootstrap capability itself as the second parameter to `makeRpcServer()`. - -template -RpcSystem makeRpcClient( - VatNetwork& network); -// Make an RPC client. Typical usage (e.g. in a main() function): -// -// MyEventLoop eventLoop; -// kj::WaitScope waitScope(eventLoop); -// MyNetwork network; -// auto client = makeRpcClient(network); -// MyCapability::Client cap = client.restore(hostId, objId).castAs(); -// auto response = cap.fooRequest().send().wait(waitScope); -// handleMyResponse(response); -// -// See also ez-rpc.h, which has simpler instructions for the common case of a two-party -// client-server RPC connection. - -template , - typename ExternalRef = _::ExternalRefFromRealmGatewayClient> -RpcSystem makeRpcClient( - VatNetwork& network, - RealmGatewayClient gateway); -// Make an RPC client for a VatNetwork that resides in a different realm from the application. -// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format -// and the network's ("external") format. - -template -class SturdyRefRestorer: public _::SturdyRefRestorerBase { - // ** DEPRECATED ** - // - // In Cap'n Proto 0.4.x, applications could export multiple main interfaces identified by - // object IDs. The callback used to map object IDs to objects was `SturdyRefRestorer`, as we - // imagined this would eventually be used for restoring SturdyRefs as well. In practice, it was - // never used for real SturdyRefs, only for exporting singleton objects under well-known names. - // - // The new preferred strategy is to export only a _single_ such interface, called the - // "bootstrap interface". That interface can itself have methods for obtaining other objects, of - // course, but that is up to the app. `SturdyRefRestorer` exists for backwards-compatibility. - // - // Hint: Use SturdyRefRestorer to define a server that exports services under - // string names. - -public: - virtual Capability::Client restore(typename SturdyRefObjectId::Reader ref) - KJ_DEPRECATED( - "Please transition to using bootstrap interfaces instead of SturdyRefRestorer.") = 0; - // Restore the given object, returning a capability representing it. - -private: - Capability::Client baseRestore(AnyPointer::Reader ref) override final; -}; - -// ======================================================================================= -// VatNetwork - -class OutgoingRpcMessage { - // A message to be sent by a `VatNetwork`. - -public: - virtual AnyPointer::Builder getBody() = 0; - // Get the message body, which the caller may fill in any way it wants. (The standard RPC - // implementation initializes it as a Message as defined in rpc.capnp.) - - virtual void send() = 0; - // Send the message, or at least put it in a queue to be sent later. Note that the builder - // returned by `getBody()` remains valid at least until the `OutgoingRpcMessage` is destroyed. -}; - -class IncomingRpcMessage { - // A message received from a `VatNetwork`. - -public: - virtual AnyPointer::Reader getBody() = 0; - // Get the message body, to be interpreted by the caller. (The standard RPC implementation - // interprets it as a Message as defined in rpc.capnp.) -}; - -template -class VatNetwork: public _::VatNetworkBase { - // Cap'n Proto RPC operates between vats, where a "vat" is some sort of host of objects. - // Typically one Cap'n Proto process (in the Unix sense) is one vat. The RPC system is what - // allows calls between objects hosted in different vats. - // - // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` - // determines how to form connections between vats -- specifically, two-way, private, reliable, - // sequenced datagram connections. The RPC implementation determines how to use such connections - // to manage object references and make method calls. - // - // The most common implementation of VatNetwork is TwoPartyVatNetwork (rpc-twoparty.h). Most - // simple client-server apps will want to use it. (You may even want to use the EZ RPC - // interfaces in `ez-rpc.h` and avoid all of this.) - // - // TODO(someday): Provide a standard implementation for the public internet. - -public: - class Connection; - - struct ConnectionAndProvisionId { - // Result of connecting to a vat introduced by another vat. - - kj::Own connection; - // Connection to the new vat. - - kj::Own firstMessage; - // An already-allocated `OutgoingRpcMessage` associated with `connection`. The RPC system will - // construct this as an `Accept` message and send it. - - Orphan provisionId; - // A `ProvisionId` already allocated inside `firstMessage`, which the RPC system will use to - // build the `Accept` message. - }; - - class Connection: public _::VatNetworkBase::Connection { - // A two-way RPC connection. - // - // This object may represent a connection that doesn't exist yet, but is expected to exist - // in the future. In this case, sent messages will automatically be queued and sent once the - // connection is ready, so that the caller doesn't need to know the difference. - - public: - // Level 0 features ---------------------------------------------- - - virtual typename VatId::Reader getPeerVatId() = 0; - // Returns the connected vat's authenticated VatId. It is the VatNetwork's responsibility to - // authenticate this, so that the caller can be assured that they are really talking to the - // identified vat and not an imposter. - - virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) override = 0; - // Allocate a new message to be sent on this connection. - // - // If `firstSegmentWordSize` is non-zero, it should be treated as a hint suggesting how large - // to make the first segment. This is entirely a hint and the connection may adjust it up or - // down. If it is zero, the connection should choose the size itself. - - virtual kj::Promise>> receiveIncomingMessage() override = 0; - // Wait for a message to be received and return it. If the read stream cleanly terminates, - // return null. If any other problem occurs, throw an exception. - - virtual kj::Promise shutdown() override KJ_WARN_UNUSED_RESULT = 0; - // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The - // returned promise resolves after shutdown is complete. - - private: - AnyStruct::Reader baseGetPeerVatId() override; - }; - - // Level 0 features ------------------------------------------------ - - virtual kj::Maybe> connect(typename VatId::Reader hostId) = 0; - // Connect to a VatId. Note that this method immediately returns a `Connection`, even - // if the network connection has not yet been established. Messages can be queued to this - // connection and will be delivered once it is open. The caller must attempt to read from the - // connection to verify that it actually succeeded; the read will fail if the connection - // couldn't be opened. Some network implementations may actually start sending messages before - // hearing back from the server at all, to avoid a round trip. - // - // Returns nullptr if `hostId` refers to the local host. - - virtual kj::Promise> accept() = 0; - // Wait for the next incoming connection and return it. - - // Level 4 features ------------------------------------------------ - // TODO(someday) - -private: - kj::Maybe> - baseConnect(AnyStruct::Reader hostId) override final; - kj::Promise> baseAccept() override final; -}; - -// ======================================================================================= -// *************************************************************************************** -// Inline implementation details start here -// *************************************************************************************** -// ======================================================================================= - -template -Capability::Client BootstrapFactory::baseCreateFor(AnyStruct::Reader clientId) { - return createFor(clientId.as()); -} - -template -kj::Maybe> - VatNetwork:: - baseConnect(AnyStruct::Reader ref) { - auto maybe = connect(ref.as()); - return maybe.map([](kj::Own& conn) -> kj::Own<_::VatNetworkBase::Connection> { - return kj::mv(conn); - }); -} - -template -kj::Promise> - VatNetwork::baseAccept() { - return accept().then( - [](kj::Own&& connection) -> kj::Own<_::VatNetworkBase::Connection> { - return kj::mv(connection); - }); -} - -template -AnyStruct::Reader VatNetwork< - SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>:: - Connection::baseGetPeerVatId() { - return getPeerVatId(); -} - -template -Capability::Client SturdyRefRestorer::baseRestore(AnyPointer::Reader ref) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return restore(ref.getAs()); -#pragma GCC diagnostic pop -} - -template -template -RpcSystem::RpcSystem( - VatNetwork& network, - kj::Maybe bootstrap, - kj::Maybe::Client> gateway) - : _::RpcSystemBase(network, kj::mv(bootstrap), kj::mv(gateway)) {} - -template -template -RpcSystem::RpcSystem( - VatNetwork& network, - BootstrapFactory& bootstrapFactory, - kj::Maybe::Client> gateway) - : _::RpcSystemBase(network, bootstrapFactory, kj::mv(gateway)) {} - -template -template -RpcSystem::RpcSystem( - VatNetwork& network, - SturdyRefRestorer& restorer) - : _::RpcSystemBase(network, restorer) {} - -template -Capability::Client RpcSystem::bootstrap(typename VatId::Reader vatId) { - return baseBootstrap(_::PointerHelpers::getInternalReader(vatId)); -} - -template -Capability::Client RpcSystem::restore( - typename VatId::Reader hostId, AnyPointer::Reader objectId) { - return baseRestore(_::PointerHelpers::getInternalReader(hostId), objectId); -} - -template -inline void RpcSystem::setFlowLimit(size_t words) { - baseSetFlowLimit(words); -} - -template -RpcSystem makeRpcServer( - VatNetwork& network, - Capability::Client bootstrapInterface) { - return RpcSystem(network, kj::mv(bootstrapInterface)); -} - -template -RpcSystem makeRpcServer( - VatNetwork& network, - Capability::Client bootstrapInterface, RealmGatewayClient gateway) { - return RpcSystem(network, kj::mv(bootstrapInterface), - gateway.template castAs>()); -} - -template -RpcSystem makeRpcServer( - VatNetwork& network, - BootstrapFactory& bootstrapFactory) { - return RpcSystem(network, bootstrapFactory); -} - -template -RpcSystem makeRpcServer( - VatNetwork& network, - BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway) { - return RpcSystem(network, bootstrapFactory, gateway.template castAs>()); -} - -template -RpcSystem makeRpcServer( - VatNetwork& network, - SturdyRefRestorer& restorer) { - return RpcSystem(network, restorer); -} - -template -RpcSystem makeRpcClient( - VatNetwork& network) { - return RpcSystem(network, nullptr); -} - -template -RpcSystem makeRpcClient( - VatNetwork& network, - RealmGatewayClient gateway) { - return RpcSystem(network, nullptr, gateway.template castAs>()); -} - -} // namespace capnp - -#endif // CAPNP_RPC_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RPC_H_ +#define CAPNP_RPC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "capability.h" +#include "rpc-prelude.h" + +namespace capnp { + +template +class VatNetwork; +template +class SturdyRefRestorer; + +template +class BootstrapFactory: public _::BootstrapFactoryBase { + // Interface that constructs per-client bootstrap interfaces. Use this if you want each client + // who connects to see a different bootstrap interface based on their (authenticated) VatId. + // This allows an application to bootstrap off of the authentication performed at the VatNetwork + // level. (Typically VatId is some sort of public key.) + // + // This is only useful for multi-party networks. For TwoPartyVatNetwork, there's no reason to + // use a BootstrapFactory; just specify a single bootstrap capability in this case. + +public: + virtual Capability::Client createFor(typename VatId::Reader clientId) = 0; + // Create a bootstrap capability appropriate for exposing to the given client. VatNetwork will + // have authenticated the client VatId before this is called. + +private: + Capability::Client baseCreateFor(AnyStruct::Reader clientId) override; +}; + +template +class RpcSystem: public _::RpcSystemBase { + // Represents the RPC system, which is the portal to objects available on the network. + // + // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` + // determines how to form connections between vats -- specifically, two-way, private, reliable, + // sequenced datagram connections. The RPC implementation determines how to use such connections + // to manage object references and make method calls. + // + // See `makeRpcServer()` and `makeRpcClient()` below for convenient syntax for setting up an + // `RpcSystem` given a `VatNetwork`. + // + // See `ez-rpc.h` for an even simpler interface for setting up RPC in a typical two-party + // client/server scenario. + +public: + template + RpcSystem( + VatNetwork& network, + kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway = nullptr); + + template + RpcSystem( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, + kj::Maybe::Client> gateway = nullptr); + + template + RpcSystem( + VatNetwork& network, + SturdyRefRestorer& restorer); + + RpcSystem(RpcSystem&& other) = default; + + Capability::Client bootstrap(typename VatId::Reader vatId); + // Connect to the given vat and return its bootstrap interface. + + Capability::Client restore(typename VatId::Reader hostId, AnyPointer::Reader objectId) + KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); + // ** DEPRECATED ** + // + // Restores the given SturdyRef from the network and return the capability representing it. + // + // `hostId` identifies the host from which to request the ref, in the format specified by the + // `VatNetwork` in use. `objectId` is the object ID in whatever format is expected by said host. + // + // This method will be removed in a future version of Cap'n Proto. Instead, please transition + // to using bootstrap(), which is equivalent to calling restore() with a null `objectId`. + // You may emulate the old concept of object IDs by exporting a bootstrap interface which has + // methods that can be used to obtain other capabilities by ID. + + void setFlowLimit(size_t words); + // Sets the incoming call flow limit. If more than `words` worth of call messages have not yet + // received responses, the RpcSystem will not read further messages from the stream. This can be + // used as a crude way to prevent a resource exhaustion attack (or bug) in which a peer makes an + // excessive number of simultaneous calls that consume the receiver's RAM. + // + // There are some caveats. When over the flow limit, all messages are blocked, including returns. + // If the outstanding calls are themselves waiting on calls going in the opposite direction, the + // flow limit may prevent those calls from completing, leading to deadlock. However, a + // sufficiently high limit should make this unlikely. + // + // Note that a call's parameter size counts against the flow limit until the call returns, even + // if the recipient calls releaseParams() to free the parameter memory early. This is because + // releaseParams() may simply indicate that the parameters have been forwarded to another + // machine, but are still in-memory there. For illustration, say that Alice made a call to Bob + // who forwarded the call to Carol. Bob has imposed a flow limit on Alice. Alice's calls are + // being forwarded to Carol, so Bob never keeps the parameters in-memory for more than a brief + // period. However, the flow limit counts all calls that haven't returned, even if Bob has + // already freed the memory they consumed. You might argue that the right solution here is + // instead for Carol to impose her own flow limit on Bob. This has a serious problem, though: + // Bob might be forwarding requests to Carol on behalf of many different parties, not just Alice. + // If Alice can pump enough data to hit the Bob -> Carol flow limit, then those other parties + // will be disrupted. Thus, we can only really impose the limit on the Alice -> Bob link, which + // only affects Alice. We need that one flow limit to limit Alice's impact on the whole system, + // so it has to count all in-flight calls. + // + // In Sandstorm, flow limits are imposed by the supervisor on calls coming out of a grain, in + // order to prevent a grain from inundating the system with in-flight calls. In practice, the + // main time this happens is when a grain is pushing a large file download and doesn't implement + // proper cooperative flow control. +}; + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface); +// Make an RPC server. Typical usage (e.g. in a main() function): +// +// MyEventLoop eventLoop; +// kj::WaitScope waitScope(eventLoop); +// MyNetwork network; +// MyMainInterface::Client bootstrap = makeMain(); +// auto server = makeRpcServer(network, bootstrap); +// kj::NEVER_DONE.wait(waitScope); // run forever +// +// See also ez-rpc.h, which has simpler instructions for the common case of a two-party +// client-server RPC connection. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface, RealmGatewayClient gateway); +// Make an RPC server for a VatNetwork that resides in a different realm from the application. +// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format +// and the network's ("external") format. + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory); +// Make an RPC server that can serve different bootstrap interfaces to different clients via a +// BootstrapInterface. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway); +// Make an RPC server that can serve different bootstrap interfaces to different clients via a +// BootstrapInterface and communicates with a different realm than the application is in via a +// RealmGateway. + +template +RpcSystem makeRpcServer( + VatNetwork& network, + SturdyRefRestorer& restorer) + KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); +// ** DEPRECATED ** +// +// Create an RPC server which exports multiple main interfaces by object ID. The `restorer` object +// can be used to look up objects by ID. +// +// Please transition to exporting only one interface, which is known as the "bootstrap" interface. +// For backwards-compatibility with old clients, continue to implement SturdyRefRestorer, but +// return the new bootstrap interface when the request object ID is null. When new clients connect +// and request the bootstrap interface, they will get that interface. Eventually, once all clients +// are updated to request only the bootstrap interface, stop implementing SturdyRefRestorer and +// switch to passing the bootstrap capability itself as the second parameter to `makeRpcServer()`. + +template +RpcSystem makeRpcClient( + VatNetwork& network); +// Make an RPC client. Typical usage (e.g. in a main() function): +// +// MyEventLoop eventLoop; +// kj::WaitScope waitScope(eventLoop); +// MyNetwork network; +// auto client = makeRpcClient(network); +// MyCapability::Client cap = client.restore(hostId, objId).castAs(); +// auto response = cap.fooRequest().send().wait(waitScope); +// handleMyResponse(response); +// +// See also ez-rpc.h, which has simpler instructions for the common case of a two-party +// client-server RPC connection. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcClient( + VatNetwork& network, + RealmGatewayClient gateway); +// Make an RPC client for a VatNetwork that resides in a different realm from the application. +// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format +// and the network's ("external") format. + +template +class SturdyRefRestorer: public _::SturdyRefRestorerBase { + // ** DEPRECATED ** + // + // In Cap'n Proto 0.4.x, applications could export multiple main interfaces identified by + // object IDs. The callback used to map object IDs to objects was `SturdyRefRestorer`, as we + // imagined this would eventually be used for restoring SturdyRefs as well. In practice, it was + // never used for real SturdyRefs, only for exporting singleton objects under well-known names. + // + // The new preferred strategy is to export only a _single_ such interface, called the + // "bootstrap interface". That interface can itself have methods for obtaining other objects, of + // course, but that is up to the app. `SturdyRefRestorer` exists for backwards-compatibility. + // + // Hint: Use SturdyRefRestorer to define a server that exports services under + // string names. + +public: + virtual Capability::Client restore(typename SturdyRefObjectId::Reader ref) + KJ_DEPRECATED( + "Please transition to using bootstrap interfaces instead of SturdyRefRestorer.") = 0; + // Restore the given object, returning a capability representing it. + +private: + Capability::Client baseRestore(AnyPointer::Reader ref) override final; +}; + +// ======================================================================================= +// VatNetwork + +class OutgoingRpcMessage { + // A message to be sent by a `VatNetwork`. + +public: + virtual AnyPointer::Builder getBody() = 0; + // Get the message body, which the caller may fill in any way it wants. (The standard RPC + // implementation initializes it as a Message as defined in rpc.capnp.) + + virtual void send() = 0; + // Send the message, or at least put it in a queue to be sent later. Note that the builder + // returned by `getBody()` remains valid at least until the `OutgoingRpcMessage` is destroyed. +}; + +class IncomingRpcMessage { + // A message received from a `VatNetwork`. + +public: + virtual AnyPointer::Reader getBody() = 0; + // Get the message body, to be interpreted by the caller. (The standard RPC implementation + // interprets it as a Message as defined in rpc.capnp.) +}; + +template +class VatNetwork: public _::VatNetworkBase { + // Cap'n Proto RPC operates between vats, where a "vat" is some sort of host of objects. + // Typically one Cap'n Proto process (in the Unix sense) is one vat. The RPC system is what + // allows calls between objects hosted in different vats. + // + // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` + // determines how to form connections between vats -- specifically, two-way, private, reliable, + // sequenced datagram connections. The RPC implementation determines how to use such connections + // to manage object references and make method calls. + // + // The most common implementation of VatNetwork is TwoPartyVatNetwork (rpc-twoparty.h). Most + // simple client-server apps will want to use it. (You may even want to use the EZ RPC + // interfaces in `ez-rpc.h` and avoid all of this.) + // + // TODO(someday): Provide a standard implementation for the public internet. + +public: + class Connection; + + struct ConnectionAndProvisionId { + // Result of connecting to a vat introduced by another vat. + + kj::Own connection; + // Connection to the new vat. + + kj::Own firstMessage; + // An already-allocated `OutgoingRpcMessage` associated with `connection`. The RPC system will + // construct this as an `Accept` message and send it. + + Orphan provisionId; + // A `ProvisionId` already allocated inside `firstMessage`, which the RPC system will use to + // build the `Accept` message. + }; + + class Connection: public _::VatNetworkBase::Connection { + // A two-way RPC connection. + // + // This object may represent a connection that doesn't exist yet, but is expected to exist + // in the future. In this case, sent messages will automatically be queued and sent once the + // connection is ready, so that the caller doesn't need to know the difference. + + public: + // Level 0 features ---------------------------------------------- + + virtual typename VatId::Reader getPeerVatId() = 0; + // Returns the connected vat's authenticated VatId. It is the VatNetwork's responsibility to + // authenticate this, so that the caller can be assured that they are really talking to the + // identified vat and not an imposter. + + virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) override = 0; + // Allocate a new message to be sent on this connection. + // + // If `firstSegmentWordSize` is non-zero, it should be treated as a hint suggesting how large + // to make the first segment. This is entirely a hint and the connection may adjust it up or + // down. If it is zero, the connection should choose the size itself. + + virtual kj::Promise>> receiveIncomingMessage() override = 0; + // Wait for a message to be received and return it. If the read stream cleanly terminates, + // return null. If any other problem occurs, throw an exception. + + virtual kj::Promise shutdown() override KJ_WARN_UNUSED_RESULT = 0; + // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The + // returned promise resolves after shutdown is complete. + + private: + AnyStruct::Reader baseGetPeerVatId() override; + }; + + // Level 0 features ------------------------------------------------ + + virtual kj::Maybe> connect(typename VatId::Reader hostId) = 0; + // Connect to a VatId. Note that this method immediately returns a `Connection`, even + // if the network connection has not yet been established. Messages can be queued to this + // connection and will be delivered once it is open. The caller must attempt to read from the + // connection to verify that it actually succeeded; the read will fail if the connection + // couldn't be opened. Some network implementations may actually start sending messages before + // hearing back from the server at all, to avoid a round trip. + // + // Returns nullptr if `hostId` refers to the local host. + + virtual kj::Promise> accept() = 0; + // Wait for the next incoming connection and return it. + + // Level 4 features ------------------------------------------------ + // TODO(someday) + +private: + kj::Maybe> + baseConnect(AnyStruct::Reader hostId) override final; + kj::Promise> baseAccept() override final; +}; + +// ======================================================================================= +// *************************************************************************************** +// Inline implementation details start here +// *************************************************************************************** +// ======================================================================================= + +template +Capability::Client BootstrapFactory::baseCreateFor(AnyStruct::Reader clientId) { + return createFor(clientId.as()); +} + +template +kj::Maybe> + VatNetwork:: + baseConnect(AnyStruct::Reader ref) { + auto maybe = connect(ref.as()); + return maybe.map([](kj::Own& conn) -> kj::Own<_::VatNetworkBase::Connection> { + return kj::mv(conn); + }); +} + +template +kj::Promise> + VatNetwork::baseAccept() { + return accept().then( + [](kj::Own&& connection) -> kj::Own<_::VatNetworkBase::Connection> { + return kj::mv(connection); + }); +} + +template +AnyStruct::Reader VatNetwork< + SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>:: + Connection::baseGetPeerVatId() { + return getPeerVatId(); +} + +template +Capability::Client SturdyRefRestorer::baseRestore(AnyPointer::Reader ref) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return restore(ref.getAs()); +#pragma GCC diagnostic pop +} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + kj::Maybe bootstrap, + kj::Maybe::Client> gateway) + : _::RpcSystemBase(network, kj::mv(bootstrap), kj::mv(gateway)) {} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, + kj::Maybe::Client> gateway) + : _::RpcSystemBase(network, bootstrapFactory, kj::mv(gateway)) {} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + SturdyRefRestorer& restorer) + : _::RpcSystemBase(network, restorer) {} + +template +Capability::Client RpcSystem::bootstrap(typename VatId::Reader vatId) { + return baseBootstrap(_::PointerHelpers::getInternalReader(vatId)); +} + +template +Capability::Client RpcSystem::restore( + typename VatId::Reader hostId, AnyPointer::Reader objectId) { + return baseRestore(_::PointerHelpers::getInternalReader(hostId), objectId); +} + +template +inline void RpcSystem::setFlowLimit(size_t words) { + baseSetFlowLimit(words); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface) { + return RpcSystem(network, kj::mv(bootstrapInterface)); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface, RealmGatewayClient gateway) { + return RpcSystem(network, kj::mv(bootstrapInterface), + gateway.template castAs>()); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory) { + return RpcSystem(network, bootstrapFactory); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway) { + return RpcSystem(network, bootstrapFactory, gateway.template castAs>()); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + SturdyRefRestorer& restorer) { + return RpcSystem(network, restorer); +} + +template +RpcSystem makeRpcClient( + VatNetwork& network) { + return RpcSystem(network, nullptr); +} + +template +RpcSystem makeRpcClient( + VatNetwork& network, + RealmGatewayClient gateway) { + return RpcSystem(network, nullptr, gateway.template castAs>()); +} + +} // namespace capnp + +#endif // CAPNP_RPC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema-lite.h --- a/osx/include/capnp/schema-lite.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema-lite.h Mon May 22 10:01:37 2017 +0100 @@ -1,48 +1,48 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SCHEMA_LITE_H_ -#define CAPNP_SCHEMA_LITE_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include "message.h" - -namespace capnp { - -template -inline schema::Node::Reader schemaProto() { - // Get the schema::Node for this type's schema. This function works even in lite mode. - return readMessageUnchecked(CapnpPrivate::encodedSchema()); -} - -template ::typeId> -inline schema::Node::Reader schemaProto() { - // Get the schema::Node for this type's schema. This function works even in lite mode. - return readMessageUnchecked(schemas::EnumInfo::encodedSchema()); -} - -} // namespace capnp - -#endif // CAPNP_SCHEMA_LITE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_LITE_H_ +#define CAPNP_SCHEMA_LITE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "message.h" + +namespace capnp { + +template +inline schema::Node::Reader schemaProto() { + // Get the schema::Node for this type's schema. This function works even in lite mode. + return readMessageUnchecked(CapnpPrivate::encodedSchema()); +} + +template ::typeId> +inline schema::Node::Reader schemaProto() { + // Get the schema::Node for this type's schema. This function works even in lite mode. + return readMessageUnchecked(schemas::EnumInfo::encodedSchema()); +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_LITE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema-loader.h --- a/osx/include/capnp/schema-loader.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema-loader.h Mon May 22 10:01:37 2017 +0100 @@ -1,173 +1,173 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SCHEMA_LOADER_H_ -#define CAPNP_SCHEMA_LOADER_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "schema.h" -#include -#include - -namespace capnp { - -class SchemaLoader { - // Class which can be used to construct Schema objects from schema::Nodes as defined in - // schema.capnp. - // - // It is a bad idea to use this class on untrusted input with exceptions disabled -- you may - // be exposing yourself to denial-of-service attacks, as attackers can easily construct schemas - // that are subtly inconsistent in a way that causes exceptions to be thrown either by - // SchemaLoader or by the dynamic API when the schemas are subsequently used. If you enable and - // properly catch exceptions, you should be OK -- assuming no bugs in the Cap'n Proto - // implementation, of course. - -public: - class LazyLoadCallback { - public: - virtual void load(const SchemaLoader& loader, uint64_t id) const = 0; - // Request that the schema node with the given ID be loaded into the given SchemaLoader. If - // the callback is able to find a schema for this ID, it should invoke `loadOnce()` on - // `loader` to load it. If no such node exists, it should simply do nothing and return. - // - // The callback is allowed to load schema nodes other than the one requested, e.g. because it - // expects they will be needed soon. - // - // If the `SchemaLoader` is used from multiple threads, the callback must be thread-safe. - // In particular, it's possible for multiple threads to invoke `load()` with the same ID. - // If the callback performs a large amount of work to look up IDs, it should be sure to - // de-dup these requests. - }; - - SchemaLoader(); - - SchemaLoader(const LazyLoadCallback& callback); - // Construct a SchemaLoader which will invoke the given callback when a schema node is requested - // that isn't already loaded. - - ~SchemaLoader() noexcept(false); - KJ_DISALLOW_COPY(SchemaLoader); - - Schema get(uint64_t id, schema::Brand::Reader brand = schema::Brand::Reader(), - Schema scope = Schema()) const; - // Gets the schema for the given ID, throwing an exception if it isn't present. - // - // The returned schema may be invalidated if load() is called with a new schema for the same ID. - // In general, you should not call load() while a schema from this loader is in-use. - // - // `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives - // parameter bindings for the target type's brand parameters that were specified at the reference - // site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains - // parameter references or indicates that some parameters will be inherited, these will be - // interpreted within / inherited from `scope`. - - kj::Maybe tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(), - Schema scope = Schema()) const; - // Like get() but doesn't throw. - - Schema getUnbound(uint64_t id) const; - // Gets a special version of the schema in which all brand parameters are "unbound". This means - // that if you look up a type via the Schema API, and it resolves to a brand parameter, the - // returned Type's getBrandParameter() method will return info about that parameter. Otherwise, - // normally, all brand parameters that aren't otherwise bound are assumed to simply be - // "AnyPointer". - - Type getType(schema::Type::Reader type, Schema scope = Schema()) const; - // Convenience method which interprets a schema::Type to produce a Type object. Implemented in - // terms of get(). - - Schema load(const schema::Node::Reader& reader); - // Loads the given schema node. Validates the node and throws an exception if invalid. This - // makes a copy of the schema, so the object passed in can be destroyed after this returns. - // - // If the node has any dependencies which are not already loaded, they will be initialized as - // stubs -- empty schemas of whichever kind is expected. - // - // If another schema for the given reader has already been seen, the loader will inspect both - // schemas to determine which one is newer, and use that that one. If the two versions are - // found to be incompatible, an exception is thrown. If the two versions differ but are - // compatible and the loader cannot determine which is newer (e.g., the only changes are renames), - // the existing schema will be preferred. Note that in any case, the loader will end up keeping - // around copies of both schemas, so you shouldn't repeatedly reload schemas into the same loader. - // - // The following properties of the schema node are validated: - // - Struct size and preferred list encoding are valid and consistent. - // - Struct members are fields or unions. - // - Union members are fields. - // - Field offsets are in-bounds. - // - Ordinals and codeOrders are sequential starting from zero. - // - Values are of the right union case to match their types. - // - // You should assume anything not listed above is NOT validated. In particular, things that are - // not validated now, but could be in the future, include but are not limited to: - // - Names. - // - Annotation values. (This is hard because the annotation declaration is not always - // available.) - // - Content of default/constant values of pointer type. (Validating these would require knowing - // their schema, but even if the schemas are available at validation time, they could be - // updated by a subsequent load(), invalidating existing values. Instead, these values are - // validated at the time they are used, as usual for Cap'n Proto objects.) - // - // Also note that unknown types are not considered invalid. Instead, the dynamic API returns - // a DynamicValue with type UNKNOWN for these. - - Schema loadOnce(const schema::Node::Reader& reader) const; - // Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast, - // `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe - // to call even while concurrently using schemas from this loader. It should be considered an - // error to call `loadOnce()` with two non-identical schemas that share the same ID, although - // this error may or may not actually be detected by the implementation. - - template - void loadCompiledTypeAndDependencies(); - // Load the schema for the given compiled-in type and all of its dependencies. - // - // If you want to be able to cast a DynamicValue built from this SchemaLoader to the compiled-in - // type using as(), you must call this method before constructing the DynamicValue. Otherwise, - // as() will throw an exception complaining about type mismatch. - - kj::Array getAllLoaded() const; - // Get a complete list of all loaded schema nodes. It is particularly useful to call this after - // loadCompiledTypeAndDependencies() in order to get a flat list of all of T's transitive - // dependencies. - -private: - class Validator; - class CompatibilityChecker; - class Impl; - class InitializerImpl; - class BrandedInitializerImpl; - kj::MutexGuarded> impl; - - void loadNative(const _::RawSchema* nativeSchema); -}; - -template -inline void SchemaLoader::loadCompiledTypeAndDependencies() { - loadNative(&_::rawSchema()); -} - -} // namespace capnp - -#endif // CAPNP_SCHEMA_LOADER_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_LOADER_H_ +#define CAPNP_SCHEMA_LOADER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema.h" +#include +#include + +namespace capnp { + +class SchemaLoader { + // Class which can be used to construct Schema objects from schema::Nodes as defined in + // schema.capnp. + // + // It is a bad idea to use this class on untrusted input with exceptions disabled -- you may + // be exposing yourself to denial-of-service attacks, as attackers can easily construct schemas + // that are subtly inconsistent in a way that causes exceptions to be thrown either by + // SchemaLoader or by the dynamic API when the schemas are subsequently used. If you enable and + // properly catch exceptions, you should be OK -- assuming no bugs in the Cap'n Proto + // implementation, of course. + +public: + class LazyLoadCallback { + public: + virtual void load(const SchemaLoader& loader, uint64_t id) const = 0; + // Request that the schema node with the given ID be loaded into the given SchemaLoader. If + // the callback is able to find a schema for this ID, it should invoke `loadOnce()` on + // `loader` to load it. If no such node exists, it should simply do nothing and return. + // + // The callback is allowed to load schema nodes other than the one requested, e.g. because it + // expects they will be needed soon. + // + // If the `SchemaLoader` is used from multiple threads, the callback must be thread-safe. + // In particular, it's possible for multiple threads to invoke `load()` with the same ID. + // If the callback performs a large amount of work to look up IDs, it should be sure to + // de-dup these requests. + }; + + SchemaLoader(); + + SchemaLoader(const LazyLoadCallback& callback); + // Construct a SchemaLoader which will invoke the given callback when a schema node is requested + // that isn't already loaded. + + ~SchemaLoader() noexcept(false); + KJ_DISALLOW_COPY(SchemaLoader); + + Schema get(uint64_t id, schema::Brand::Reader brand = schema::Brand::Reader(), + Schema scope = Schema()) const; + // Gets the schema for the given ID, throwing an exception if it isn't present. + // + // The returned schema may be invalidated if load() is called with a new schema for the same ID. + // In general, you should not call load() while a schema from this loader is in-use. + // + // `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives + // parameter bindings for the target type's brand parameters that were specified at the reference + // site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains + // parameter references or indicates that some parameters will be inherited, these will be + // interpreted within / inherited from `scope`. + + kj::Maybe tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(), + Schema scope = Schema()) const; + // Like get() but doesn't throw. + + Schema getUnbound(uint64_t id) const; + // Gets a special version of the schema in which all brand parameters are "unbound". This means + // that if you look up a type via the Schema API, and it resolves to a brand parameter, the + // returned Type's getBrandParameter() method will return info about that parameter. Otherwise, + // normally, all brand parameters that aren't otherwise bound are assumed to simply be + // "AnyPointer". + + Type getType(schema::Type::Reader type, Schema scope = Schema()) const; + // Convenience method which interprets a schema::Type to produce a Type object. Implemented in + // terms of get(). + + Schema load(const schema::Node::Reader& reader); + // Loads the given schema node. Validates the node and throws an exception if invalid. This + // makes a copy of the schema, so the object passed in can be destroyed after this returns. + // + // If the node has any dependencies which are not already loaded, they will be initialized as + // stubs -- empty schemas of whichever kind is expected. + // + // If another schema for the given reader has already been seen, the loader will inspect both + // schemas to determine which one is newer, and use that that one. If the two versions are + // found to be incompatible, an exception is thrown. If the two versions differ but are + // compatible and the loader cannot determine which is newer (e.g., the only changes are renames), + // the existing schema will be preferred. Note that in any case, the loader will end up keeping + // around copies of both schemas, so you shouldn't repeatedly reload schemas into the same loader. + // + // The following properties of the schema node are validated: + // - Struct size and preferred list encoding are valid and consistent. + // - Struct members are fields or unions. + // - Union members are fields. + // - Field offsets are in-bounds. + // - Ordinals and codeOrders are sequential starting from zero. + // - Values are of the right union case to match their types. + // + // You should assume anything not listed above is NOT validated. In particular, things that are + // not validated now, but could be in the future, include but are not limited to: + // - Names. + // - Annotation values. (This is hard because the annotation declaration is not always + // available.) + // - Content of default/constant values of pointer type. (Validating these would require knowing + // their schema, but even if the schemas are available at validation time, they could be + // updated by a subsequent load(), invalidating existing values. Instead, these values are + // validated at the time they are used, as usual for Cap'n Proto objects.) + // + // Also note that unknown types are not considered invalid. Instead, the dynamic API returns + // a DynamicValue with type UNKNOWN for these. + + Schema loadOnce(const schema::Node::Reader& reader) const; + // Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast, + // `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe + // to call even while concurrently using schemas from this loader. It should be considered an + // error to call `loadOnce()` with two non-identical schemas that share the same ID, although + // this error may or may not actually be detected by the implementation. + + template + void loadCompiledTypeAndDependencies(); + // Load the schema for the given compiled-in type and all of its dependencies. + // + // If you want to be able to cast a DynamicValue built from this SchemaLoader to the compiled-in + // type using as(), you must call this method before constructing the DynamicValue. Otherwise, + // as() will throw an exception complaining about type mismatch. + + kj::Array getAllLoaded() const; + // Get a complete list of all loaded schema nodes. It is particularly useful to call this after + // loadCompiledTypeAndDependencies() in order to get a flat list of all of T's transitive + // dependencies. + +private: + class Validator; + class CompatibilityChecker; + class Impl; + class InitializerImpl; + class BrandedInitializerImpl; + kj::MutexGuarded> impl; + + void loadNative(const _::RawSchema* nativeSchema); +}; + +template +inline void SchemaLoader::loadCompiledTypeAndDependencies() { + loadNative(&_::rawSchema()); +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_LOADER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema-parser.h --- a/osx/include/capnp/schema-parser.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema-parser.h Mon May 22 10:01:37 2017 +0100 @@ -1,207 +1,207 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SCHEMA_PARSER_H_ -#define CAPNP_SCHEMA_PARSER_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "schema-loader.h" -#include - -namespace capnp { - -class ParsedSchema; -class SchemaFile; - -class SchemaParser { - // Parses `.capnp` files to produce `Schema` objects. - // - // This class is thread-safe, hence all its methods are const. - -public: - SchemaParser(); - ~SchemaParser() noexcept(false); - - ParsedSchema parseDiskFile(kj::StringPtr displayName, kj::StringPtr diskPath, - kj::ArrayPtr importPath) const; - // Parse a file located on disk. Throws an exception if the file dosen't exist. - // - // Parameters: - // * `displayName`: The name that will appear in the file's schema node. (If the file has - // already been parsed, this will be ignored and the display name from the first time it was - // parsed will be kept.) - // * `diskPath`: The path to the file on disk. - // * `importPath`: Directories to search when resolving absolute imports within this file - // (imports that start with a `/`). Must remain valid until the SchemaParser is destroyed. - // (If the file has already been parsed, this will be ignored and the import path from the - // first time it was parsed will be kept.) - // - // This method is a shortcut, equivalent to: - // parser.parseFile(SchemaFile::newDiskFile(displayName, diskPath, importPath))`; - // - // This method throws an exception if any errors are encountered in the file or in anything the - // file depends on. Note that merely importing another file does not count as a dependency on - // anything in the imported file -- only the imported types which are actually used are - // "dependencies". - - ParsedSchema parseFile(kj::Own&& file) const; - // Advanced interface for parsing a file that may or may not be located in any global namespace. - // Most users will prefer `parseDiskFile()`. - // - // If the file has already been parsed (that is, a SchemaFile that compares equal to this one - // was parsed previously), the existing schema will be returned again. - // - // This method reports errors by calling SchemaFile::reportError() on the file where the error - // is located. If that call does not throw an exception, `parseFile()` may in fact return - // normally. In this case, the result is a best-effort attempt to compile the schema, but it - // may be invalid or corrupt, and using it for anything may cause exceptions to be thrown. - - template - inline void loadCompiledTypeAndDependencies() { - // See SchemaLoader::loadCompiledTypeAndDependencies(). - getLoader().loadCompiledTypeAndDependencies(); - } - -private: - struct Impl; - class ModuleImpl; - kj::Own impl; - mutable bool hadErrors = false; - - ModuleImpl& getModuleImpl(kj::Own&& file) const; - SchemaLoader& getLoader(); - - friend class ParsedSchema; -}; - -class ParsedSchema: public Schema { - // ParsedSchema is an extension of Schema which also has the ability to look up nested nodes - // by name. See `SchemaParser`. - -public: - inline ParsedSchema(): parser(nullptr) {} - - kj::Maybe findNested(kj::StringPtr name) const; - // Gets the nested node with the given name, or returns null if there is no such nested - // declaration. - - ParsedSchema getNested(kj::StringPtr name) const; - // Gets the nested node with the given name, or throws an exception if there is no such nested - // declaration. - -private: - inline ParsedSchema(Schema inner, const SchemaParser& parser): Schema(inner), parser(&parser) {} - - const SchemaParser* parser; - friend class SchemaParser; -}; - -// ======================================================================================= -// Advanced API - -class SchemaFile { - // Abstract interface representing a schema file. You can implement this yourself in order to - // gain more control over how the compiler resolves imports and reads files. For the - // common case of files on disk or other global filesystem-like namespaces, use - // `SchemaFile::newDiskFile()`. - -public: - class FileReader { - public: - virtual bool exists(kj::StringPtr path) const = 0; - virtual kj::Array read(kj::StringPtr path) const = 0; - }; - - class DiskFileReader final: public FileReader { - // Implementation of FileReader that uses the local disk. Files are read using mmap() if - // possible. - - public: - static const DiskFileReader instance; - - bool exists(kj::StringPtr path) const override; - kj::Array read(kj::StringPtr path) const override; - }; - - static kj::Own newDiskFile( - kj::StringPtr displayName, kj::StringPtr diskPath, - kj::ArrayPtr importPath, - const FileReader& fileReader = DiskFileReader::instance); - // Construct a SchemaFile representing a file on disk (or located in the filesystem-like - // namespace represented by `fileReader`). - // - // Parameters: - // * `displayName`: The name that will appear in the file's schema node. - // * `diskPath`: The path to the file on disk. - // * `importPath`: Directories to search when resolving absolute imports within this file - // (imports that start with a `/`). The array content must remain valid as long as the - // SchemaFile exists (which is at least as long as the SchemaParser that parses it exists). - // * `fileReader`: Allows you to use a filesystem other than the actual local disk. Although, - // if you find yourself using this, it may make more sense for you to implement SchemaFile - // yourself. - // - // The SchemaFile compares equal to any other SchemaFile that has exactly the same disk path, - // after canonicalization. - // - // The SchemaFile will throw an exception if any errors are reported. - - // ----------------------------------------------------------------- - // For more control, you can implement this interface. - - virtual kj::StringPtr getDisplayName() const = 0; - // Get the file's name, as it should appear in the schema. - - virtual kj::Array readContent() const = 0; - // Read the file's entire content and return it as a byte array. - - virtual kj::Maybe> import(kj::StringPtr path) const = 0; - // Resolve an import, relative to this file. - // - // `path` is exactly what appears between quotes after the `import` keyword in the source code. - // It is entirely up to the `SchemaFile` to decide how to map this to another file. Typically, - // a leading '/' means that the file is an "absolute" path and is searched for in some list of - // schema file repositories. On the other hand, a path that doesn't start with '/' is relative - // to the importing file. - - virtual bool operator==(const SchemaFile& other) const = 0; - virtual bool operator!=(const SchemaFile& other) const = 0; - virtual size_t hashCode() const = 0; - // Compare two SchemaFiles to see if they refer to the same underlying file. This is an - // optimization used to avoid the need to re-parse a file to check its ID. - - struct SourcePos { - uint byte; - uint line; - uint column; - }; - virtual void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const = 0; - // Report that the file contains an error at the given interval. - -private: - class DiskSchemaFile; -}; - -} // namespace capnp - -#endif // CAPNP_SCHEMA_PARSER_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_PARSER_H_ +#define CAPNP_SCHEMA_PARSER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema-loader.h" +#include + +namespace capnp { + +class ParsedSchema; +class SchemaFile; + +class SchemaParser { + // Parses `.capnp` files to produce `Schema` objects. + // + // This class is thread-safe, hence all its methods are const. + +public: + SchemaParser(); + ~SchemaParser() noexcept(false); + + ParsedSchema parseDiskFile(kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath) const; + // Parse a file located on disk. Throws an exception if the file dosen't exist. + // + // Parameters: + // * `displayName`: The name that will appear in the file's schema node. (If the file has + // already been parsed, this will be ignored and the display name from the first time it was + // parsed will be kept.) + // * `diskPath`: The path to the file on disk. + // * `importPath`: Directories to search when resolving absolute imports within this file + // (imports that start with a `/`). Must remain valid until the SchemaParser is destroyed. + // (If the file has already been parsed, this will be ignored and the import path from the + // first time it was parsed will be kept.) + // + // This method is a shortcut, equivalent to: + // parser.parseFile(SchemaFile::newDiskFile(displayName, diskPath, importPath))`; + // + // This method throws an exception if any errors are encountered in the file or in anything the + // file depends on. Note that merely importing another file does not count as a dependency on + // anything in the imported file -- only the imported types which are actually used are + // "dependencies". + + ParsedSchema parseFile(kj::Own&& file) const; + // Advanced interface for parsing a file that may or may not be located in any global namespace. + // Most users will prefer `parseDiskFile()`. + // + // If the file has already been parsed (that is, a SchemaFile that compares equal to this one + // was parsed previously), the existing schema will be returned again. + // + // This method reports errors by calling SchemaFile::reportError() on the file where the error + // is located. If that call does not throw an exception, `parseFile()` may in fact return + // normally. In this case, the result is a best-effort attempt to compile the schema, but it + // may be invalid or corrupt, and using it for anything may cause exceptions to be thrown. + + template + inline void loadCompiledTypeAndDependencies() { + // See SchemaLoader::loadCompiledTypeAndDependencies(). + getLoader().loadCompiledTypeAndDependencies(); + } + +private: + struct Impl; + class ModuleImpl; + kj::Own impl; + mutable bool hadErrors = false; + + ModuleImpl& getModuleImpl(kj::Own&& file) const; + SchemaLoader& getLoader(); + + friend class ParsedSchema; +}; + +class ParsedSchema: public Schema { + // ParsedSchema is an extension of Schema which also has the ability to look up nested nodes + // by name. See `SchemaParser`. + +public: + inline ParsedSchema(): parser(nullptr) {} + + kj::Maybe findNested(kj::StringPtr name) const; + // Gets the nested node with the given name, or returns null if there is no such nested + // declaration. + + ParsedSchema getNested(kj::StringPtr name) const; + // Gets the nested node with the given name, or throws an exception if there is no such nested + // declaration. + +private: + inline ParsedSchema(Schema inner, const SchemaParser& parser): Schema(inner), parser(&parser) {} + + const SchemaParser* parser; + friend class SchemaParser; +}; + +// ======================================================================================= +// Advanced API + +class SchemaFile { + // Abstract interface representing a schema file. You can implement this yourself in order to + // gain more control over how the compiler resolves imports and reads files. For the + // common case of files on disk or other global filesystem-like namespaces, use + // `SchemaFile::newDiskFile()`. + +public: + class FileReader { + public: + virtual bool exists(kj::StringPtr path) const = 0; + virtual kj::Array read(kj::StringPtr path) const = 0; + }; + + class DiskFileReader final: public FileReader { + // Implementation of FileReader that uses the local disk. Files are read using mmap() if + // possible. + + public: + static const DiskFileReader instance; + + bool exists(kj::StringPtr path) const override; + kj::Array read(kj::StringPtr path) const override; + }; + + static kj::Own newDiskFile( + kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath, + const FileReader& fileReader = DiskFileReader::instance); + // Construct a SchemaFile representing a file on disk (or located in the filesystem-like + // namespace represented by `fileReader`). + // + // Parameters: + // * `displayName`: The name that will appear in the file's schema node. + // * `diskPath`: The path to the file on disk. + // * `importPath`: Directories to search when resolving absolute imports within this file + // (imports that start with a `/`). The array content must remain valid as long as the + // SchemaFile exists (which is at least as long as the SchemaParser that parses it exists). + // * `fileReader`: Allows you to use a filesystem other than the actual local disk. Although, + // if you find yourself using this, it may make more sense for you to implement SchemaFile + // yourself. + // + // The SchemaFile compares equal to any other SchemaFile that has exactly the same disk path, + // after canonicalization. + // + // The SchemaFile will throw an exception if any errors are reported. + + // ----------------------------------------------------------------- + // For more control, you can implement this interface. + + virtual kj::StringPtr getDisplayName() const = 0; + // Get the file's name, as it should appear in the schema. + + virtual kj::Array readContent() const = 0; + // Read the file's entire content and return it as a byte array. + + virtual kj::Maybe> import(kj::StringPtr path) const = 0; + // Resolve an import, relative to this file. + // + // `path` is exactly what appears between quotes after the `import` keyword in the source code. + // It is entirely up to the `SchemaFile` to decide how to map this to another file. Typically, + // a leading '/' means that the file is an "absolute" path and is searched for in some list of + // schema file repositories. On the other hand, a path that doesn't start with '/' is relative + // to the importing file. + + virtual bool operator==(const SchemaFile& other) const = 0; + virtual bool operator!=(const SchemaFile& other) const = 0; + virtual size_t hashCode() const = 0; + // Compare two SchemaFiles to see if they refer to the same underlying file. This is an + // optimization used to avoid the need to re-parse a file to check its ID. + + struct SourcePos { + uint byte; + uint line; + uint column; + }; + virtual void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const = 0; + // Report that the file contains an error at the given interval. + +private: + class DiskSchemaFile; +}; + +} // namespace capnp + +#endif // CAPNP_SCHEMA_PARSER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema.capnp --- a/osx/include/capnp/schema.capnp Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema.capnp Mon May 22 10:01:37 2017 +0100 @@ -1,484 +1,498 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -using Cxx = import "/capnp/c++.capnp"; - -@0xa93fc509624c72d9; -$Cxx.namespace("capnp::schema"); - -using Id = UInt64; -# The globally-unique ID of a file, type, or annotation. - -struct Node { - id @0 :Id; - - displayName @1 :Text; - # Name to present to humans to identify this Node. You should not attempt to parse this. Its - # format could change. It is not guaranteed to be unique. - # - # (On Zooko's triangle, this is the node's nickname.) - - displayNamePrefixLength @2 :UInt32; - # If you want a shorter version of `displayName` (just naming this node, without its surrounding - # scope), chop off this many characters from the beginning of `displayName`. - - scopeId @3 :Id; - # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back - # at this node, but robust code should avoid relying on this (and, in fact, group nodes are not - # listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is - # zero if the node has no parent, which is normally only the case with files, but should be - # allowed for any kind of node (in order to make runtime type generation easier). - - parameters @32 :List(Parameter); - # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. - - isGeneric @33 :Bool; - # True if this node is generic, meaning that it or one of its parent scopes has a non-empty - # `parameters`. - - struct Parameter { - # Information about one of the node's parameters. - - name @0 :Text; - } - - nestedNodes @4 :List(NestedNode); - # List of nodes nested within this node, along with the names under which they were declared. - - struct NestedNode { - name @0 :Text; - # Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically. - # - # (On Zooko's triangle, this is the node's petname according to its parent scope.) - - id @1 :Id; - # ID of the nested node. Typically, the target node's scopeId points back to this node, but - # robust code should avoid relying on this. - } - - annotations @5 :List(Annotation); - # Annotations applied to this node. - - union { - # Info specific to each kind of node. - - file @6 :Void; - - struct :group { - dataWordCount @7 :UInt16; - # Size of the data section, in words. - - pointerCount @8 :UInt16; - # Size of the pointer section, in pointers (which are one word each). - - preferredListEncoding @9 :ElementSize; - # The preferred element size to use when encoding a list of this struct. If this is anything - # other than `inlineComposite` then the struct is one word or less in size and is a candidate - # for list packing optimization. - - isGroup @10 :Bool; - # If true, then this "struct" node is actually not an independent node, but merely represents - # some named union or group within a particular parent struct. This node's scopeId refers - # to the parent struct, which may itself be a union/group in yet another struct. - # - # All group nodes share the same dataWordCount and pointerCount as the top-level - # struct, and their fields live in the same ordinal and offset spaces as all other fields in - # the struct. - # - # Note that a named union is considered a special kind of group -- in fact, a named union - # is exactly equivalent to a group that contains nothing but an unnamed union. - - discriminantCount @11 :UInt16; - # Number of fields in this struct which are members of an anonymous union, and thus may - # overlap. If this is non-zero, then a 16-bit discriminant is present indicating which - # of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be - # two or more. - # - # Note that the fields of an unnamed union are considered fields of the scope containing the - # union -- an unnamed union is not its own group. So, a top-level struct may contain a - # non-zero discriminant count. Named unions, on the other hand, are equivalent to groups - # containing unnamed unions. So, a named union has its own independent schema node, with - # `isGroup` = true. - - discriminantOffset @12 :UInt32; - # If `discriminantCount` is non-zero, this is the offset of the union discriminant, in - # multiples of 16 bits. - - fields @13 :List(Field); - # Fields defined within this scope (either the struct's top-level fields, or the fields of - # a particular group; see `isGroup`). - # - # The fields are sorted by ordinal number, but note that because groups share the same - # ordinal space, the field's index in this list is not necessarily exactly its ordinal. - # On the other hand, the field's position in this list does remain the same even as the - # protocol evolves, since it is not possible to insert or remove an earlier ordinal. - # Therefore, for most use cases, if you want to identify a field by number, it may make the - # most sense to use the field's index in this list rather than its ordinal. - } - - enum :group { - enumerants@14 :List(Enumerant); - # Enumerants ordered by numeric value (ordinal). - } - - interface :group { - methods @15 :List(Method); - # Methods ordered by ordinal. - - superclasses @31 :List(Superclass); - # Superclasses of this interface. - } - - const :group { - type @16 :Type; - value @17 :Value; - } - - annotation :group { - type @18 :Type; - - targetsFile @19 :Bool; - targetsConst @20 :Bool; - targetsEnum @21 :Bool; - targetsEnumerant @22 :Bool; - targetsStruct @23 :Bool; - targetsField @24 :Bool; - targetsUnion @25 :Bool; - targetsGroup @26 :Bool; - targetsInterface @27 :Bool; - targetsMethod @28 :Bool; - targetsParam @29 :Bool; - targetsAnnotation @30 :Bool; - } - } -} - -struct Field { - # Schema for a field of a struct. - - name @0 :Text; - - codeOrder @1 :UInt16; - # Indicates where this member appeared in the code, relative to other members. - # Code ordering may have semantic relevance -- programmers tend to place related fields - # together. So, using code ordering makes sense in human-readable formats where ordering is - # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum - # value is count(members) - 1. Fields that are members of a union are only ordered relative to - # the other members of that union, so the maximum value there is count(union.members). - - annotations @2 :List(Annotation); - - const noDiscriminant :UInt16 = 0xffff; - - discriminantValue @3 :UInt16 = Field.noDiscriminant; - # If the field is in a union, this is the value which the union's discriminant should take when - # the field is active. If the field is not in a union, this is 0xffff. - - union { - slot :group { - # A regular, non-group, non-fixed-list field. - - offset @4 :UInt32; - # Offset, in units of the field's size, from the beginning of the section in which the field - # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the - # beginning of the data section. - - type @5 :Type; - defaultValue @6 :Value; - - hadExplicitDefault @10 :Bool; - # Whether the default value was specified explicitly. Non-explicit default values are always - # zero or empty values. Usually, whether the default value was explicit shouldn't matter. - # The main use case for this flag is for structs representing method parameters: - # explicitly-defaulted parameters may be allowed to be omitted when calling the method. - } - - group :group { - # A group. - - typeId @7 :Id; - # The ID of the group's node. - } - } - - ordinal :union { - implicit @8 :Void; - explicit @9 :UInt16; - # The original ordinal number given to the field. You probably should NOT use this; if you need - # a numeric identifier for a field, use its position within the field array for its scope. - # The ordinal is given here mainly just so that the original schema text can be reproduced given - # the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job. - } -} - -struct Enumerant { - # Schema for member of an enum. - - name @0 :Text; - - codeOrder @1 :UInt16; - # Specifies order in which the enumerants were declared in the code. - # Like Struct.Field.codeOrder. - - annotations @2 :List(Annotation); -} - -struct Superclass { - id @0 :Id; - brand @1 :Brand; -} - -struct Method { - # Schema for method of an interface. - - name @0 :Text; - - codeOrder @1 :UInt16; - # Specifies order in which the methods were declared in the code. - # Like Struct.Field.codeOrder. - - implicitParameters @7 :List(Node.Parameter); - # The parameters listed in [] (typically, type / generic parameters), whose bindings are intended - # to be inferred rather than specified explicitly, although not all languages support this. - - paramStructType @2 :Id; - # ID of the parameter struct type. If a named parameter list was specified in the method - # declaration (rather than a single struct parameter type) then a corresponding struct type is - # auto-generated. Such an auto-generated type will not be listed in the interface's - # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. - # (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes - # this a situation where you can't just climb the scope chain to find where a particular - # generic parameter was introduced. Making the `scopeId` zero was a mistake.) - - paramBrand @5 :Brand; - # Brand of param struct type. - - resultStructType @3 :Id; - # ID of the return struct type; similar to `paramStructType`. - - resultBrand @6 :Brand; - # Brand of result struct type. - - annotations @4 :List(Annotation); -} - -struct Type { - # Represents a type expression. - - union { - # The ordinals intentionally match those of Value. - - void @0 :Void; - bool @1 :Void; - int8 @2 :Void; - int16 @3 :Void; - int32 @4 :Void; - int64 @5 :Void; - uint8 @6 :Void; - uint16 @7 :Void; - uint32 @8 :Void; - uint64 @9 :Void; - float32 @10 :Void; - float64 @11 :Void; - text @12 :Void; - data @13 :Void; - - list :group { - elementType @14 :Type; - } - - enum :group { - typeId @15 :Id; - brand @21 :Brand; - } - struct :group { - typeId @16 :Id; - brand @22 :Brand; - } - interface :group { - typeId @17 :Id; - brand @23 :Brand; - } - - anyPointer :union { - unconstrained :union { - # A regular AnyPointer. - # - # The name "unconstained" means as opposed to constraining it to match a type parameter. - # In retrospect this name is probably a poor choice given that it may still be constrained - # to be a struct, list, or capability. - - anyKind @18 :Void; # truly AnyPointer - struct @25 :Void; # AnyStruct - list @26 :Void; # AnyList - capability @27 :Void; # Capability - } - - parameter :group { - # This is actually a reference to a type parameter defined within this scope. - - scopeId @19 :Id; - # ID of the generic type whose parameter we're referencing. This should be a parent of the - # current scope. - - parameterIndex @20 :UInt16; - # Index of the parameter within the generic type's parameter list. - } - - implicitMethodParameter :group { - # This is actually a reference to an implicit (generic) parameter of a method. The only - # legal context for this type to appear is inside Method.paramBrand or Method.resultBrand. - - parameterIndex @24 :UInt16; - } - } - } -} - -struct Brand { - # Specifies bindings for parameters of generics. Since these bindings turn a generic into a - # non-generic, we call it the "brand". - - scopes @0 :List(Scope); - # For each of the target type and each of its parent scopes, a parameterization may be included - # in this list. If no parameterization is included for a particular relevant scope, then either - # that scope has no parameters or all parameters should be considered to be `AnyPointer`. - - struct Scope { - scopeId @0 :Id; - # ID of the scope to which these params apply. - - union { - bind @1 :List(Binding); - # List of parameter bindings. - - inherit @2 :Void; - # The place where this Brand appears is actually within this scope or a sub-scope, - # and the bindings for this scope should be inherited from the reference point. - } - } - - struct Binding { - union { - unbound @0 :Void; - type @1 :Type; - - # TODO(someday): Allow non-type parameters? Unsure if useful. - } - } -} - -struct Value { - # Represents a value, e.g. a field default value, constant value, or annotation value. - - union { - # The ordinals intentionally match those of Type. - - void @0 :Void; - bool @1 :Bool; - int8 @2 :Int8; - int16 @3 :Int16; - int32 @4 :Int32; - int64 @5 :Int64; - uint8 @6 :UInt8; - uint16 @7 :UInt16; - uint32 @8 :UInt32; - uint64 @9 :UInt64; - float32 @10 :Float32; - float64 @11 :Float64; - text @12 :Text; - data @13 :Data; - - list @14 :AnyPointer; - - enum @15 :UInt16; - struct @16 :AnyPointer; - - interface @17 :Void; - # The only interface value that can be represented statically is "null", whose methods always - # throw exceptions. - - anyPointer @18 :AnyPointer; - } -} - -struct Annotation { - # Describes an annotation applied to a declaration. Note AnnotationNode describes the - # annotation's declaration, while this describes a use of the annotation. - - id @0 :Id; - # ID of the annotation node. - - brand @2 :Brand; - # Brand of the annotation. - # - # Note that the annotation itself is not allowed to be parameterized, but its scope might be. - - value @1 :Value; -} - -enum ElementSize { - # Possible element sizes for encoded lists. These correspond exactly to the possible values of - # the 3-bit element size component of a list pointer. - - empty @0; # aka "void", but that's a keyword. - bit @1; - byte @2; - twoBytes @3; - fourBytes @4; - eightBytes @5; - pointer @6; - inlineComposite @7; -} - -struct CodeGeneratorRequest { - nodes @0 :List(Node); - # All nodes parsed by the compiler, including for the files on the command line and their - # imports. - - requestedFiles @1 :List(RequestedFile); - # Files which were listed on the command line. - - struct RequestedFile { - id @0 :Id; - # ID of the file. - - filename @1 :Text; - # Name of the file as it appeared on the command-line (minus the src-prefix). You may use - # this to decide where to write the output. - - imports @2 :List(Import); - # List of all imported paths seen in this file. - - struct Import { - id @0 :Id; - # ID of the imported file. - - name @1 :Text; - # Name which *this* file used to refer to the foreign file. This may be a relative name. - # This information is provided because it might be useful for code generation, e.g. to - # generate #include directives in C++. We don't put this in Node.file because this - # information is only meaningful at compile time anyway. - # - # (On Zooko's triangle, this is the import's petname according to the importing file.) - } - } -} +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +using Cxx = import "/capnp/c++.capnp"; + +@0xa93fc509624c72d9; +$Cxx.namespace("capnp::schema"); + +using Id = UInt64; +# The globally-unique ID of a file, type, or annotation. + +struct Node { + id @0 :Id; + + displayName @1 :Text; + # Name to present to humans to identify this Node. You should not attempt to parse this. Its + # format could change. It is not guaranteed to be unique. + # + # (On Zooko's triangle, this is the node's nickname.) + + displayNamePrefixLength @2 :UInt32; + # If you want a shorter version of `displayName` (just naming this node, without its surrounding + # scope), chop off this many characters from the beginning of `displayName`. + + scopeId @3 :Id; + # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back + # at this node, but robust code should avoid relying on this (and, in fact, group nodes are not + # listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is + # zero if the node has no parent, which is normally only the case with files, but should be + # allowed for any kind of node (in order to make runtime type generation easier). + + parameters @32 :List(Parameter); + # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. + + isGeneric @33 :Bool; + # True if this node is generic, meaning that it or one of its parent scopes has a non-empty + # `parameters`. + + struct Parameter { + # Information about one of the node's parameters. + + name @0 :Text; + } + + nestedNodes @4 :List(NestedNode); + # List of nodes nested within this node, along with the names under which they were declared. + + struct NestedNode { + name @0 :Text; + # Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically. + # + # (On Zooko's triangle, this is the node's petname according to its parent scope.) + + id @1 :Id; + # ID of the nested node. Typically, the target node's scopeId points back to this node, but + # robust code should avoid relying on this. + } + + annotations @5 :List(Annotation); + # Annotations applied to this node. + + union { + # Info specific to each kind of node. + + file @6 :Void; + + struct :group { + dataWordCount @7 :UInt16; + # Size of the data section, in words. + + pointerCount @8 :UInt16; + # Size of the pointer section, in pointers (which are one word each). + + preferredListEncoding @9 :ElementSize; + # The preferred element size to use when encoding a list of this struct. If this is anything + # other than `inlineComposite` then the struct is one word or less in size and is a candidate + # for list packing optimization. + + isGroup @10 :Bool; + # If true, then this "struct" node is actually not an independent node, but merely represents + # some named union or group within a particular parent struct. This node's scopeId refers + # to the parent struct, which may itself be a union/group in yet another struct. + # + # All group nodes share the same dataWordCount and pointerCount as the top-level + # struct, and their fields live in the same ordinal and offset spaces as all other fields in + # the struct. + # + # Note that a named union is considered a special kind of group -- in fact, a named union + # is exactly equivalent to a group that contains nothing but an unnamed union. + + discriminantCount @11 :UInt16; + # Number of fields in this struct which are members of an anonymous union, and thus may + # overlap. If this is non-zero, then a 16-bit discriminant is present indicating which + # of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be + # two or more. + # + # Note that the fields of an unnamed union are considered fields of the scope containing the + # union -- an unnamed union is not its own group. So, a top-level struct may contain a + # non-zero discriminant count. Named unions, on the other hand, are equivalent to groups + # containing unnamed unions. So, a named union has its own independent schema node, with + # `isGroup` = true. + + discriminantOffset @12 :UInt32; + # If `discriminantCount` is non-zero, this is the offset of the union discriminant, in + # multiples of 16 bits. + + fields @13 :List(Field); + # Fields defined within this scope (either the struct's top-level fields, or the fields of + # a particular group; see `isGroup`). + # + # The fields are sorted by ordinal number, but note that because groups share the same + # ordinal space, the field's index in this list is not necessarily exactly its ordinal. + # On the other hand, the field's position in this list does remain the same even as the + # protocol evolves, since it is not possible to insert or remove an earlier ordinal. + # Therefore, for most use cases, if you want to identify a field by number, it may make the + # most sense to use the field's index in this list rather than its ordinal. + } + + enum :group { + enumerants@14 :List(Enumerant); + # Enumerants ordered by numeric value (ordinal). + } + + interface :group { + methods @15 :List(Method); + # Methods ordered by ordinal. + + superclasses @31 :List(Superclass); + # Superclasses of this interface. + } + + const :group { + type @16 :Type; + value @17 :Value; + } + + annotation :group { + type @18 :Type; + + targetsFile @19 :Bool; + targetsConst @20 :Bool; + targetsEnum @21 :Bool; + targetsEnumerant @22 :Bool; + targetsStruct @23 :Bool; + targetsField @24 :Bool; + targetsUnion @25 :Bool; + targetsGroup @26 :Bool; + targetsInterface @27 :Bool; + targetsMethod @28 :Bool; + targetsParam @29 :Bool; + targetsAnnotation @30 :Bool; + } + } +} + +struct Field { + # Schema for a field of a struct. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Indicates where this member appeared in the code, relative to other members. + # Code ordering may have semantic relevance -- programmers tend to place related fields + # together. So, using code ordering makes sense in human-readable formats where ordering is + # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum + # value is count(members) - 1. Fields that are members of a union are only ordered relative to + # the other members of that union, so the maximum value there is count(union.members). + + annotations @2 :List(Annotation); + + const noDiscriminant :UInt16 = 0xffff; + + discriminantValue @3 :UInt16 = Field.noDiscriminant; + # If the field is in a union, this is the value which the union's discriminant should take when + # the field is active. If the field is not in a union, this is 0xffff. + + union { + slot :group { + # A regular, non-group, non-fixed-list field. + + offset @4 :UInt32; + # Offset, in units of the field's size, from the beginning of the section in which the field + # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the + # beginning of the data section. + + type @5 :Type; + defaultValue @6 :Value; + + hadExplicitDefault @10 :Bool; + # Whether the default value was specified explicitly. Non-explicit default values are always + # zero or empty values. Usually, whether the default value was explicit shouldn't matter. + # The main use case for this flag is for structs representing method parameters: + # explicitly-defaulted parameters may be allowed to be omitted when calling the method. + } + + group :group { + # A group. + + typeId @7 :Id; + # The ID of the group's node. + } + } + + ordinal :union { + implicit @8 :Void; + explicit @9 :UInt16; + # The original ordinal number given to the field. You probably should NOT use this; if you need + # a numeric identifier for a field, use its position within the field array for its scope. + # The ordinal is given here mainly just so that the original schema text can be reproduced given + # the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job. + } +} + +struct Enumerant { + # Schema for member of an enum. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the enumerants were declared in the code. + # Like Struct.Field.codeOrder. + + annotations @2 :List(Annotation); +} + +struct Superclass { + id @0 :Id; + brand @1 :Brand; +} + +struct Method { + # Schema for method of an interface. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the methods were declared in the code. + # Like Struct.Field.codeOrder. + + implicitParameters @7 :List(Node.Parameter); + # The parameters listed in [] (typically, type / generic parameters), whose bindings are intended + # to be inferred rather than specified explicitly, although not all languages support this. + + paramStructType @2 :Id; + # ID of the parameter struct type. If a named parameter list was specified in the method + # declaration (rather than a single struct parameter type) then a corresponding struct type is + # auto-generated. Such an auto-generated type will not be listed in the interface's + # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. + # (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes + # this a situation where you can't just climb the scope chain to find where a particular + # generic parameter was introduced. Making the `scopeId` zero was a mistake.) + + paramBrand @5 :Brand; + # Brand of param struct type. + + resultStructType @3 :Id; + # ID of the return struct type; similar to `paramStructType`. + + resultBrand @6 :Brand; + # Brand of result struct type. + + annotations @4 :List(Annotation); +} + +struct Type { + # Represents a type expression. + + union { + # The ordinals intentionally match those of Value. + + void @0 :Void; + bool @1 :Void; + int8 @2 :Void; + int16 @3 :Void; + int32 @4 :Void; + int64 @5 :Void; + uint8 @6 :Void; + uint16 @7 :Void; + uint32 @8 :Void; + uint64 @9 :Void; + float32 @10 :Void; + float64 @11 :Void; + text @12 :Void; + data @13 :Void; + + list :group { + elementType @14 :Type; + } + + enum :group { + typeId @15 :Id; + brand @21 :Brand; + } + struct :group { + typeId @16 :Id; + brand @22 :Brand; + } + interface :group { + typeId @17 :Id; + brand @23 :Brand; + } + + anyPointer :union { + unconstrained :union { + # A regular AnyPointer. + # + # The name "unconstrained" means as opposed to constraining it to match a type parameter. + # In retrospect this name is probably a poor choice given that it may still be constrained + # to be a struct, list, or capability. + + anyKind @18 :Void; # truly AnyPointer + struct @25 :Void; # AnyStruct + list @26 :Void; # AnyList + capability @27 :Void; # Capability + } + + parameter :group { + # This is actually a reference to a type parameter defined within this scope. + + scopeId @19 :Id; + # ID of the generic type whose parameter we're referencing. This should be a parent of the + # current scope. + + parameterIndex @20 :UInt16; + # Index of the parameter within the generic type's parameter list. + } + + implicitMethodParameter :group { + # This is actually a reference to an implicit (generic) parameter of a method. The only + # legal context for this type to appear is inside Method.paramBrand or Method.resultBrand. + + parameterIndex @24 :UInt16; + } + } + } +} + +struct Brand { + # Specifies bindings for parameters of generics. Since these bindings turn a generic into a + # non-generic, we call it the "brand". + + scopes @0 :List(Scope); + # For each of the target type and each of its parent scopes, a parameterization may be included + # in this list. If no parameterization is included for a particular relevant scope, then either + # that scope has no parameters or all parameters should be considered to be `AnyPointer`. + + struct Scope { + scopeId @0 :Id; + # ID of the scope to which these params apply. + + union { + bind @1 :List(Binding); + # List of parameter bindings. + + inherit @2 :Void; + # The place where this Brand appears is actually within this scope or a sub-scope, + # and the bindings for this scope should be inherited from the reference point. + } + } + + struct Binding { + union { + unbound @0 :Void; + type @1 :Type; + + # TODO(someday): Allow non-type parameters? Unsure if useful. + } + } +} + +struct Value { + # Represents a value, e.g. a field default value, constant value, or annotation value. + + union { + # The ordinals intentionally match those of Type. + + void @0 :Void; + bool @1 :Bool; + int8 @2 :Int8; + int16 @3 :Int16; + int32 @4 :Int32; + int64 @5 :Int64; + uint8 @6 :UInt8; + uint16 @7 :UInt16; + uint32 @8 :UInt32; + uint64 @9 :UInt64; + float32 @10 :Float32; + float64 @11 :Float64; + text @12 :Text; + data @13 :Data; + + list @14 :AnyPointer; + + enum @15 :UInt16; + struct @16 :AnyPointer; + + interface @17 :Void; + # The only interface value that can be represented statically is "null", whose methods always + # throw exceptions. + + anyPointer @18 :AnyPointer; + } +} + +struct Annotation { + # Describes an annotation applied to a declaration. Note AnnotationNode describes the + # annotation's declaration, while this describes a use of the annotation. + + id @0 :Id; + # ID of the annotation node. + + brand @2 :Brand; + # Brand of the annotation. + # + # Note that the annotation itself is not allowed to be parameterized, but its scope might be. + + value @1 :Value; +} + +enum ElementSize { + # Possible element sizes for encoded lists. These correspond exactly to the possible values of + # the 3-bit element size component of a list pointer. + + empty @0; # aka "void", but that's a keyword. + bit @1; + byte @2; + twoBytes @3; + fourBytes @4; + eightBytes @5; + pointer @6; + inlineComposite @7; +} + +struct CapnpVersion { + major @0 :UInt16; + minor @1 :UInt8; + micro @2 :UInt8; +} + +struct CodeGeneratorRequest { + capnpVersion @2 :CapnpVersion; + # Version of the `capnp` executable. Generally, code generators should ignore this, but the code + # generators that ship with `capnp` itself will print a warning if this mismatches since that + # probably indicates something is misconfigured. + # + # The first version of 'capnp' to set this was 0.6.0. So, if it's missing, the compiler version + # is older than that. + + nodes @0 :List(Node); + # All nodes parsed by the compiler, including for the files on the command line and their + # imports. + + requestedFiles @1 :List(RequestedFile); + # Files which were listed on the command line. + + struct RequestedFile { + id @0 :Id; + # ID of the file. + + filename @1 :Text; + # Name of the file as it appeared on the command-line (minus the src-prefix). You may use + # this to decide where to write the output. + + imports @2 :List(Import); + # List of all imported paths seen in this file. + + struct Import { + id @0 :Id; + # ID of the imported file. + + name @1 :Text; + # Name which *this* file used to refer to the foreign file. This may be a relative name. + # This information is provided because it might be useful for code generation, e.g. to + # generate #include directives in C++. We don't put this in Node.file because this + # information is only meaningful at compile time anyway. + # + # (On Zooko's triangle, this is the import's petname according to the importing file.) + } + } +} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema.capnp.h --- a/osx/include/capnp/schema.capnp.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -1,7561 +1,7861 @@ -// Generated by Cap'n Proto compiler, DO NOT EDIT -// source: schema.capnp - -#ifndef CAPNP_INCLUDED_a93fc509624c72d9_ -#define CAPNP_INCLUDED_a93fc509624c72d9_ - -#include - -#if CAPNP_VERSION != 6000 -#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." -#endif - - -namespace capnp { -namespace schemas { - -CAPNP_DECLARE_SCHEMA(e682ab4cf923a417); -CAPNP_DECLARE_SCHEMA(b9521bccf10fa3b1); -CAPNP_DECLARE_SCHEMA(debf55bbfa0fc242); -CAPNP_DECLARE_SCHEMA(9ea0b19b37fb4435); -CAPNP_DECLARE_SCHEMA(b54ab3364333f598); -CAPNP_DECLARE_SCHEMA(e82753cff0c2218f); -CAPNP_DECLARE_SCHEMA(b18aa5ac7a0d9420); -CAPNP_DECLARE_SCHEMA(ec1619d4400a0290); -CAPNP_DECLARE_SCHEMA(9aad50a41f4af45f); -CAPNP_DECLARE_SCHEMA(97b14cbe7cfec712); -CAPNP_DECLARE_SCHEMA(c42305476bb4746f); -CAPNP_DECLARE_SCHEMA(cafccddb68db1d11); -CAPNP_DECLARE_SCHEMA(bb90d5c287870be6); -CAPNP_DECLARE_SCHEMA(978a7cebdc549a4d); -CAPNP_DECLARE_SCHEMA(a9962a9ed0a4d7f8); -CAPNP_DECLARE_SCHEMA(9500cce23b334d80); -CAPNP_DECLARE_SCHEMA(d07378ede1f9cc60); -CAPNP_DECLARE_SCHEMA(87e739250a60ea97); -CAPNP_DECLARE_SCHEMA(9e0e78711a7f87a9); -CAPNP_DECLARE_SCHEMA(ac3a6f60ef4cc6d3); -CAPNP_DECLARE_SCHEMA(ed8bca69f7fb0cbf); -CAPNP_DECLARE_SCHEMA(c2573fe8a23e49f1); -CAPNP_DECLARE_SCHEMA(8e3b5f79fe593656); -CAPNP_DECLARE_SCHEMA(9dd1f724f4614a85); -CAPNP_DECLARE_SCHEMA(baefc9120c56e274); -CAPNP_DECLARE_SCHEMA(903455f06065422b); -CAPNP_DECLARE_SCHEMA(abd73485a9636bc9); -CAPNP_DECLARE_SCHEMA(c863cd16969ee7fc); -CAPNP_DECLARE_SCHEMA(ce23dcd2d7b00c9b); -CAPNP_DECLARE_SCHEMA(f1c8950dab257542); -CAPNP_DECLARE_SCHEMA(d1958f7dba521926); -enum class ElementSize_d1958f7dba521926: uint16_t { - EMPTY, - BIT, - BYTE, - TWO_BYTES, - FOUR_BYTES, - EIGHT_BYTES, - POINTER, - INLINE_COMPOSITE, -}; -CAPNP_DECLARE_ENUM(ElementSize, d1958f7dba521926); -CAPNP_DECLARE_SCHEMA(bfc546f6210ad7ce); -CAPNP_DECLARE_SCHEMA(cfea0eb02e810062); -CAPNP_DECLARE_SCHEMA(ae504193122357e5); - -} // namespace schemas -} // namespace capnp - -namespace capnp { -namespace schema { - -struct Node { - Node() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - FILE, - STRUCT, - ENUM, - INTERFACE, - CONST, - ANNOTATION, - }; - struct Parameter; - struct NestedNode; - struct Struct; - struct Enum; - struct Interface; - struct Const; - struct Annotation; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(e682ab4cf923a417, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Parameter { - Parameter() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b9521bccf10fa3b1, 0, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::NestedNode { - NestedNode() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(debf55bbfa0fc242, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Struct { - Struct() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9ea0b19b37fb4435, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Enum { - Enum() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b54ab3364333f598, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Interface { - Interface() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(e82753cff0c2218f, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Const { - Const() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(b18aa5ac7a0d9420, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Node::Annotation { - Annotation() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ec1619d4400a0290, 5, 6) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Field { - Field() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - SLOT, - GROUP, - }; - static constexpr ::uint16_t NO_DISCRIMINANT = 65535u; - struct Slot; - struct Group; - struct Ordinal; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9aad50a41f4af45f, 3, 4) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Field::Slot { - Slot() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(c42305476bb4746f, 3, 4) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Field::Group { - Group() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(cafccddb68db1d11, 3, 4) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Field::Ordinal { - Ordinal() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - IMPLICIT, - EXPLICIT, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(bb90d5c287870be6, 3, 4) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Enumerant { - Enumerant() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(978a7cebdc549a4d, 1, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Superclass { - Superclass() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(a9962a9ed0a4d7f8, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Method { - Method() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9500cce23b334d80, 3, 5) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type { - Type() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - VOID, - BOOL, - INT8, - INT16, - INT32, - INT64, - UINT8, - UINT16, - UINT32, - UINT64, - FLOAT32, - FLOAT64, - TEXT, - DATA, - LIST, - ENUM, - STRUCT, - INTERFACE, - ANY_POINTER, - }; - struct List; - struct Enum; - struct Struct; - struct Interface; - struct AnyPointer; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(d07378ede1f9cc60, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::List { - List() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(87e739250a60ea97, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::Enum { - Enum() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9e0e78711a7f87a9, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::Struct { - Struct() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ac3a6f60ef4cc6d3, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::Interface { - Interface() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ed8bca69f7fb0cbf, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::AnyPointer { - AnyPointer() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - UNCONSTRAINED, - PARAMETER, - IMPLICIT_METHOD_PARAMETER, - }; - struct Unconstrained; - struct Parameter; - struct ImplicitMethodParameter; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(c2573fe8a23e49f1, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::AnyPointer::Unconstrained { - Unconstrained() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - ANY_KIND, - STRUCT, - LIST, - CAPABILITY, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(8e3b5f79fe593656, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::AnyPointer::Parameter { - Parameter() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(9dd1f724f4614a85, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Type::AnyPointer::ImplicitMethodParameter { - ImplicitMethodParameter() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(baefc9120c56e274, 3, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Brand { - Brand() = delete; - - class Reader; - class Builder; - class Pipeline; - struct Scope; - struct Binding; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(903455f06065422b, 0, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Brand::Scope { - Scope() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - BIND, - INHERIT, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(abd73485a9636bc9, 2, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Brand::Binding { - Binding() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - UNBOUND, - TYPE, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(c863cd16969ee7fc, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Value { - Value() = delete; - - class Reader; - class Builder; - class Pipeline; - enum Which: uint16_t { - VOID, - BOOL, - INT8, - INT16, - INT32, - INT64, - UINT8, - UINT16, - UINT32, - UINT64, - FLOAT32, - FLOAT64, - TEXT, - DATA, - LIST, - ENUM, - STRUCT, - INTERFACE, - ANY_POINTER, - }; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ce23dcd2d7b00c9b, 2, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct Annotation { - Annotation() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(f1c8950dab257542, 1, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -typedef ::capnp::schemas::ElementSize_d1958f7dba521926 ElementSize; - -struct CodeGeneratorRequest { - CodeGeneratorRequest() = delete; - - class Reader; - class Builder; - class Pipeline; - struct RequestedFile; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(bfc546f6210ad7ce, 0, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct CodeGeneratorRequest::RequestedFile { - RequestedFile() = delete; - - class Reader; - class Builder; - class Pipeline; - struct Import; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(cfea0eb02e810062, 1, 2) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -struct CodeGeneratorRequest::RequestedFile::Import { - Import() = delete; - - class Reader; - class Builder; - class Pipeline; - - struct _capnpPrivate { - CAPNP_DECLARE_STRUCT_HEADER(ae504193122357e5, 1, 1) - #if !CAPNP_LITE - static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand; - #endif // !CAPNP_LITE - }; -}; - -// ======================================================================================= - -class Node::Reader { -public: - typedef Node Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline ::uint64_t getId() const; - - inline bool hasDisplayName() const; - inline ::capnp::Text::Reader getDisplayName() const; - - inline ::uint32_t getDisplayNamePrefixLength() const; - - inline ::uint64_t getScopeId() const; - - inline bool hasNestedNodes() const; - inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader getNestedNodes() const; - - inline bool hasAnnotations() const; - inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; - - inline bool isFile() const; - inline ::capnp::Void getFile() const; - - inline bool isStruct() const; - inline typename Struct::Reader getStruct() const; - - inline bool isEnum() const; - inline typename Enum::Reader getEnum() const; - - inline bool isInterface() const; - inline typename Interface::Reader getInterface() const; - - inline bool isConst() const; - inline typename Const::Reader getConst() const; - - inline bool isAnnotation() const; - inline typename Annotation::Reader getAnnotation() const; - - inline bool hasParameters() const; - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getParameters() const; - - inline bool getIsGeneric() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Builder { -public: - typedef Node Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - - inline bool hasDisplayName(); - inline ::capnp::Text::Builder getDisplayName(); - inline void setDisplayName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initDisplayName(unsigned int size); - inline void adoptDisplayName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownDisplayName(); - - inline ::uint32_t getDisplayNamePrefixLength(); - inline void setDisplayNamePrefixLength( ::uint32_t value); - - inline ::uint64_t getScopeId(); - inline void setScopeId( ::uint64_t value); - - inline bool hasNestedNodes(); - inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder getNestedNodes(); - inline void setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value); - inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder initNestedNodes(unsigned int size); - inline void adoptNestedNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> disownNestedNodes(); - - inline bool hasAnnotations(); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); - inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); - inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); - - inline bool isFile(); - inline ::capnp::Void getFile(); - inline void setFile( ::capnp::Void value = ::capnp::VOID); - - inline bool isStruct(); - inline typename Struct::Builder getStruct(); - inline typename Struct::Builder initStruct(); - - inline bool isEnum(); - inline typename Enum::Builder getEnum(); - inline typename Enum::Builder initEnum(); - - inline bool isInterface(); - inline typename Interface::Builder getInterface(); - inline typename Interface::Builder initInterface(); - - inline bool isConst(); - inline typename Const::Builder getConst(); - inline typename Const::Builder initConst(); - - inline bool isAnnotation(); - inline typename Annotation::Builder getAnnotation(); - inline typename Annotation::Builder initAnnotation(); - - inline bool hasParameters(); - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getParameters(); - inline void setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initParameters(unsigned int size); - inline void adoptParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownParameters(); - - inline bool getIsGeneric(); - inline void setIsGeneric(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Pipeline { -public: - typedef Node Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Parameter::Reader { -public: - typedef Parameter Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Parameter::Builder { -public: - typedef Parameter Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Parameter::Pipeline { -public: - typedef Parameter Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::NestedNode::Reader { -public: - typedef NestedNode Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - - inline ::uint64_t getId() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::NestedNode::Builder { -public: - typedef NestedNode Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::NestedNode::Pipeline { -public: - typedef NestedNode Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Struct::Reader { -public: - typedef Struct Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint16_t getDataWordCount() const; - - inline ::uint16_t getPointerCount() const; - - inline ::capnp::schema::ElementSize getPreferredListEncoding() const; - - inline bool getIsGroup() const; - - inline ::uint16_t getDiscriminantCount() const; - - inline ::uint32_t getDiscriminantOffset() const; - - inline bool hasFields() const; - inline ::capnp::List< ::capnp::schema::Field>::Reader getFields() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Struct::Builder { -public: - typedef Struct Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint16_t getDataWordCount(); - inline void setDataWordCount( ::uint16_t value); - - inline ::uint16_t getPointerCount(); - inline void setPointerCount( ::uint16_t value); - - inline ::capnp::schema::ElementSize getPreferredListEncoding(); - inline void setPreferredListEncoding( ::capnp::schema::ElementSize value); - - inline bool getIsGroup(); - inline void setIsGroup(bool value); - - inline ::uint16_t getDiscriminantCount(); - inline void setDiscriminantCount( ::uint16_t value); - - inline ::uint32_t getDiscriminantOffset(); - inline void setDiscriminantOffset( ::uint32_t value); - - inline bool hasFields(); - inline ::capnp::List< ::capnp::schema::Field>::Builder getFields(); - inline void setFields( ::capnp::List< ::capnp::schema::Field>::Reader value); - inline ::capnp::List< ::capnp::schema::Field>::Builder initFields(unsigned int size); - inline void adoptFields(::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> disownFields(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Struct::Pipeline { -public: - typedef Struct Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Enum::Reader { -public: - typedef Enum Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasEnumerants() const; - inline ::capnp::List< ::capnp::schema::Enumerant>::Reader getEnumerants() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Enum::Builder { -public: - typedef Enum Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasEnumerants(); - inline ::capnp::List< ::capnp::schema::Enumerant>::Builder getEnumerants(); - inline void setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value); - inline ::capnp::List< ::capnp::schema::Enumerant>::Builder initEnumerants(unsigned int size); - inline void adoptEnumerants(::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> disownEnumerants(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Enum::Pipeline { -public: - typedef Enum Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Interface::Reader { -public: - typedef Interface Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasMethods() const; - inline ::capnp::List< ::capnp::schema::Method>::Reader getMethods() const; - - inline bool hasSuperclasses() const; - inline ::capnp::List< ::capnp::schema::Superclass>::Reader getSuperclasses() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Interface::Builder { -public: - typedef Interface Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasMethods(); - inline ::capnp::List< ::capnp::schema::Method>::Builder getMethods(); - inline void setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value); - inline ::capnp::List< ::capnp::schema::Method>::Builder initMethods(unsigned int size); - inline void adoptMethods(::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> disownMethods(); - - inline bool hasSuperclasses(); - inline ::capnp::List< ::capnp::schema::Superclass>::Builder getSuperclasses(); - inline void setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value); - inline ::capnp::List< ::capnp::schema::Superclass>::Builder initSuperclasses(unsigned int size); - inline void adoptSuperclasses(::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> disownSuperclasses(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Interface::Pipeline { -public: - typedef Interface Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Const::Reader { -public: - typedef Const Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasType() const; - inline ::capnp::schema::Type::Reader getType() const; - - inline bool hasValue() const; - inline ::capnp::schema::Value::Reader getValue() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Const::Builder { -public: - typedef Const Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasType(); - inline ::capnp::schema::Type::Builder getType(); - inline void setType( ::capnp::schema::Type::Reader value); - inline ::capnp::schema::Type::Builder initType(); - inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); - inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); - - inline bool hasValue(); - inline ::capnp::schema::Value::Builder getValue(); - inline void setValue( ::capnp::schema::Value::Reader value); - inline ::capnp::schema::Value::Builder initValue(); - inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); - inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Const::Pipeline { -public: - typedef Const Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Type::Pipeline getType(); - inline ::capnp::schema::Value::Pipeline getValue(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Node::Annotation::Reader { -public: - typedef Annotation Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasType() const; - inline ::capnp::schema::Type::Reader getType() const; - - inline bool getTargetsFile() const; - - inline bool getTargetsConst() const; - - inline bool getTargetsEnum() const; - - inline bool getTargetsEnumerant() const; - - inline bool getTargetsStruct() const; - - inline bool getTargetsField() const; - - inline bool getTargetsUnion() const; - - inline bool getTargetsGroup() const; - - inline bool getTargetsInterface() const; - - inline bool getTargetsMethod() const; - - inline bool getTargetsParam() const; - - inline bool getTargetsAnnotation() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Node::Annotation::Builder { -public: - typedef Annotation Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasType(); - inline ::capnp::schema::Type::Builder getType(); - inline void setType( ::capnp::schema::Type::Reader value); - inline ::capnp::schema::Type::Builder initType(); - inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); - inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); - - inline bool getTargetsFile(); - inline void setTargetsFile(bool value); - - inline bool getTargetsConst(); - inline void setTargetsConst(bool value); - - inline bool getTargetsEnum(); - inline void setTargetsEnum(bool value); - - inline bool getTargetsEnumerant(); - inline void setTargetsEnumerant(bool value); - - inline bool getTargetsStruct(); - inline void setTargetsStruct(bool value); - - inline bool getTargetsField(); - inline void setTargetsField(bool value); - - inline bool getTargetsUnion(); - inline void setTargetsUnion(bool value); - - inline bool getTargetsGroup(); - inline void setTargetsGroup(bool value); - - inline bool getTargetsInterface(); - inline void setTargetsInterface(bool value); - - inline bool getTargetsMethod(); - inline void setTargetsMethod(bool value); - - inline bool getTargetsParam(); - inline void setTargetsParam(bool value); - - inline bool getTargetsAnnotation(); - inline void setTargetsAnnotation(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Node::Annotation::Pipeline { -public: - typedef Annotation Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Type::Pipeline getType(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Field::Reader { -public: - typedef Field Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - - inline ::uint16_t getCodeOrder() const; - - inline bool hasAnnotations() const; - inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; - - inline ::uint16_t getDiscriminantValue() const; - - inline bool isSlot() const; - inline typename Slot::Reader getSlot() const; - - inline bool isGroup() const; - inline typename Group::Reader getGroup() const; - - inline typename Ordinal::Reader getOrdinal() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Field::Builder { -public: - typedef Field Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - - inline ::uint16_t getCodeOrder(); - inline void setCodeOrder( ::uint16_t value); - - inline bool hasAnnotations(); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); - inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); - inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); - - inline ::uint16_t getDiscriminantValue(); - inline void setDiscriminantValue( ::uint16_t value); - - inline bool isSlot(); - inline typename Slot::Builder getSlot(); - inline typename Slot::Builder initSlot(); - - inline bool isGroup(); - inline typename Group::Builder getGroup(); - inline typename Group::Builder initGroup(); - - inline typename Ordinal::Builder getOrdinal(); - inline typename Ordinal::Builder initOrdinal(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Field::Pipeline { -public: - typedef Field Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline typename Ordinal::Pipeline getOrdinal(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Field::Slot::Reader { -public: - typedef Slot Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint32_t getOffset() const; - - inline bool hasType() const; - inline ::capnp::schema::Type::Reader getType() const; - - inline bool hasDefaultValue() const; - inline ::capnp::schema::Value::Reader getDefaultValue() const; - - inline bool getHadExplicitDefault() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Field::Slot::Builder { -public: - typedef Slot Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint32_t getOffset(); - inline void setOffset( ::uint32_t value); - - inline bool hasType(); - inline ::capnp::schema::Type::Builder getType(); - inline void setType( ::capnp::schema::Type::Reader value); - inline ::capnp::schema::Type::Builder initType(); - inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); - inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); - - inline bool hasDefaultValue(); - inline ::capnp::schema::Value::Builder getDefaultValue(); - inline void setDefaultValue( ::capnp::schema::Value::Reader value); - inline ::capnp::schema::Value::Builder initDefaultValue(); - inline void adoptDefaultValue(::capnp::Orphan< ::capnp::schema::Value>&& value); - inline ::capnp::Orphan< ::capnp::schema::Value> disownDefaultValue(); - - inline bool getHadExplicitDefault(); - inline void setHadExplicitDefault(bool value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Field::Slot::Pipeline { -public: - typedef Slot Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Type::Pipeline getType(); - inline ::capnp::schema::Value::Pipeline getDefaultValue(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Field::Group::Reader { -public: - typedef Group Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Field::Group::Builder { -public: - typedef Group Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId(); - inline void setTypeId( ::uint64_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Field::Group::Pipeline { -public: - typedef Group Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Field::Ordinal::Reader { -public: - typedef Ordinal Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isImplicit() const; - inline ::capnp::Void getImplicit() const; - - inline bool isExplicit() const; - inline ::uint16_t getExplicit() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Field::Ordinal::Builder { -public: - typedef Ordinal Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isImplicit(); - inline ::capnp::Void getImplicit(); - inline void setImplicit( ::capnp::Void value = ::capnp::VOID); - - inline bool isExplicit(); - inline ::uint16_t getExplicit(); - inline void setExplicit( ::uint16_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Field::Ordinal::Pipeline { -public: - typedef Ordinal Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Enumerant::Reader { -public: - typedef Enumerant Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - - inline ::uint16_t getCodeOrder() const; - - inline bool hasAnnotations() const; - inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Enumerant::Builder { -public: - typedef Enumerant Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - - inline ::uint16_t getCodeOrder(); - inline void setCodeOrder( ::uint16_t value); - - inline bool hasAnnotations(); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); - inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); - inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Enumerant::Pipeline { -public: - typedef Enumerant Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Superclass::Reader { -public: - typedef Superclass Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getId() const; - - inline bool hasBrand() const; - inline ::capnp::schema::Brand::Reader getBrand() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Superclass::Builder { -public: - typedef Superclass Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - - inline bool hasBrand(); - inline ::capnp::schema::Brand::Builder getBrand(); - inline void setBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initBrand(); - inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Superclass::Pipeline { -public: - typedef Superclass Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Brand::Pipeline getBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Method::Reader { -public: - typedef Method Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - - inline ::uint16_t getCodeOrder() const; - - inline ::uint64_t getParamStructType() const; - - inline ::uint64_t getResultStructType() const; - - inline bool hasAnnotations() const; - inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; - - inline bool hasParamBrand() const; - inline ::capnp::schema::Brand::Reader getParamBrand() const; - - inline bool hasResultBrand() const; - inline ::capnp::schema::Brand::Reader getResultBrand() const; - - inline bool hasImplicitParameters() const; - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getImplicitParameters() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Method::Builder { -public: - typedef Method Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - - inline ::uint16_t getCodeOrder(); - inline void setCodeOrder( ::uint16_t value); - - inline ::uint64_t getParamStructType(); - inline void setParamStructType( ::uint64_t value); - - inline ::uint64_t getResultStructType(); - inline void setResultStructType( ::uint64_t value); - - inline bool hasAnnotations(); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); - inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); - inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); - inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); - - inline bool hasParamBrand(); - inline ::capnp::schema::Brand::Builder getParamBrand(); - inline void setParamBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initParamBrand(); - inline void adoptParamBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownParamBrand(); - - inline bool hasResultBrand(); - inline ::capnp::schema::Brand::Builder getResultBrand(); - inline void setResultBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initResultBrand(); - inline void adoptResultBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownResultBrand(); - - inline bool hasImplicitParameters(); - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getImplicitParameters(); - inline void setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); - inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initImplicitParameters(unsigned int size); - inline void adoptImplicitParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownImplicitParameters(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Method::Pipeline { -public: - typedef Method Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Brand::Pipeline getParamBrand(); - inline ::capnp::schema::Brand::Pipeline getResultBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::Reader { -public: - typedef Type Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isVoid() const; - inline ::capnp::Void getVoid() const; - - inline bool isBool() const; - inline ::capnp::Void getBool() const; - - inline bool isInt8() const; - inline ::capnp::Void getInt8() const; - - inline bool isInt16() const; - inline ::capnp::Void getInt16() const; - - inline bool isInt32() const; - inline ::capnp::Void getInt32() const; - - inline bool isInt64() const; - inline ::capnp::Void getInt64() const; - - inline bool isUint8() const; - inline ::capnp::Void getUint8() const; - - inline bool isUint16() const; - inline ::capnp::Void getUint16() const; - - inline bool isUint32() const; - inline ::capnp::Void getUint32() const; - - inline bool isUint64() const; - inline ::capnp::Void getUint64() const; - - inline bool isFloat32() const; - inline ::capnp::Void getFloat32() const; - - inline bool isFloat64() const; - inline ::capnp::Void getFloat64() const; - - inline bool isText() const; - inline ::capnp::Void getText() const; - - inline bool isData() const; - inline ::capnp::Void getData() const; - - inline bool isList() const; - inline typename List::Reader getList() const; - - inline bool isEnum() const; - inline typename Enum::Reader getEnum() const; - - inline bool isStruct() const; - inline typename Struct::Reader getStruct() const; - - inline bool isInterface() const; - inline typename Interface::Reader getInterface() const; - - inline bool isAnyPointer() const; - inline typename AnyPointer::Reader getAnyPointer() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::Builder { -public: - typedef Type Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isVoid(); - inline ::capnp::Void getVoid(); - inline void setVoid( ::capnp::Void value = ::capnp::VOID); - - inline bool isBool(); - inline ::capnp::Void getBool(); - inline void setBool( ::capnp::Void value = ::capnp::VOID); - - inline bool isInt8(); - inline ::capnp::Void getInt8(); - inline void setInt8( ::capnp::Void value = ::capnp::VOID); - - inline bool isInt16(); - inline ::capnp::Void getInt16(); - inline void setInt16( ::capnp::Void value = ::capnp::VOID); - - inline bool isInt32(); - inline ::capnp::Void getInt32(); - inline void setInt32( ::capnp::Void value = ::capnp::VOID); - - inline bool isInt64(); - inline ::capnp::Void getInt64(); - inline void setInt64( ::capnp::Void value = ::capnp::VOID); - - inline bool isUint8(); - inline ::capnp::Void getUint8(); - inline void setUint8( ::capnp::Void value = ::capnp::VOID); - - inline bool isUint16(); - inline ::capnp::Void getUint16(); - inline void setUint16( ::capnp::Void value = ::capnp::VOID); - - inline bool isUint32(); - inline ::capnp::Void getUint32(); - inline void setUint32( ::capnp::Void value = ::capnp::VOID); - - inline bool isUint64(); - inline ::capnp::Void getUint64(); - inline void setUint64( ::capnp::Void value = ::capnp::VOID); - - inline bool isFloat32(); - inline ::capnp::Void getFloat32(); - inline void setFloat32( ::capnp::Void value = ::capnp::VOID); - - inline bool isFloat64(); - inline ::capnp::Void getFloat64(); - inline void setFloat64( ::capnp::Void value = ::capnp::VOID); - - inline bool isText(); - inline ::capnp::Void getText(); - inline void setText( ::capnp::Void value = ::capnp::VOID); - - inline bool isData(); - inline ::capnp::Void getData(); - inline void setData( ::capnp::Void value = ::capnp::VOID); - - inline bool isList(); - inline typename List::Builder getList(); - inline typename List::Builder initList(); - - inline bool isEnum(); - inline typename Enum::Builder getEnum(); - inline typename Enum::Builder initEnum(); - - inline bool isStruct(); - inline typename Struct::Builder getStruct(); - inline typename Struct::Builder initStruct(); - - inline bool isInterface(); - inline typename Interface::Builder getInterface(); - inline typename Interface::Builder initInterface(); - - inline bool isAnyPointer(); - inline typename AnyPointer::Builder getAnyPointer(); - inline typename AnyPointer::Builder initAnyPointer(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::Pipeline { -public: - typedef Type Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::List::Reader { -public: - typedef List Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasElementType() const; - inline ::capnp::schema::Type::Reader getElementType() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::List::Builder { -public: - typedef List Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasElementType(); - inline ::capnp::schema::Type::Builder getElementType(); - inline void setElementType( ::capnp::schema::Type::Reader value); - inline ::capnp::schema::Type::Builder initElementType(); - inline void adoptElementType(::capnp::Orphan< ::capnp::schema::Type>&& value); - inline ::capnp::Orphan< ::capnp::schema::Type> disownElementType(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::List::Pipeline { -public: - typedef List Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Type::Pipeline getElementType(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::Enum::Reader { -public: - typedef Enum Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId() const; - - inline bool hasBrand() const; - inline ::capnp::schema::Brand::Reader getBrand() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::Enum::Builder { -public: - typedef Enum Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId(); - inline void setTypeId( ::uint64_t value); - - inline bool hasBrand(); - inline ::capnp::schema::Brand::Builder getBrand(); - inline void setBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initBrand(); - inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::Enum::Pipeline { -public: - typedef Enum Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Brand::Pipeline getBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::Struct::Reader { -public: - typedef Struct Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId() const; - - inline bool hasBrand() const; - inline ::capnp::schema::Brand::Reader getBrand() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::Struct::Builder { -public: - typedef Struct Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId(); - inline void setTypeId( ::uint64_t value); - - inline bool hasBrand(); - inline ::capnp::schema::Brand::Builder getBrand(); - inline void setBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initBrand(); - inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::Struct::Pipeline { -public: - typedef Struct Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Brand::Pipeline getBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::Interface::Reader { -public: - typedef Interface Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId() const; - - inline bool hasBrand() const; - inline ::capnp::schema::Brand::Reader getBrand() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::Interface::Builder { -public: - typedef Interface Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getTypeId(); - inline void setTypeId( ::uint64_t value); - - inline bool hasBrand(); - inline ::capnp::schema::Brand::Builder getBrand(); - inline void setBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initBrand(); - inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::Interface::Pipeline { -public: - typedef Interface Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Brand::Pipeline getBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::AnyPointer::Reader { -public: - typedef AnyPointer Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isUnconstrained() const; - inline typename Unconstrained::Reader getUnconstrained() const; - - inline bool isParameter() const; - inline typename Parameter::Reader getParameter() const; - - inline bool isImplicitMethodParameter() const; - inline typename ImplicitMethodParameter::Reader getImplicitMethodParameter() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::AnyPointer::Builder { -public: - typedef AnyPointer Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isUnconstrained(); - inline typename Unconstrained::Builder getUnconstrained(); - inline typename Unconstrained::Builder initUnconstrained(); - - inline bool isParameter(); - inline typename Parameter::Builder getParameter(); - inline typename Parameter::Builder initParameter(); - - inline bool isImplicitMethodParameter(); - inline typename ImplicitMethodParameter::Builder getImplicitMethodParameter(); - inline typename ImplicitMethodParameter::Builder initImplicitMethodParameter(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::AnyPointer::Pipeline { -public: - typedef AnyPointer Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::AnyPointer::Unconstrained::Reader { -public: - typedef Unconstrained Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isAnyKind() const; - inline ::capnp::Void getAnyKind() const; - - inline bool isStruct() const; - inline ::capnp::Void getStruct() const; - - inline bool isList() const; - inline ::capnp::Void getList() const; - - inline bool isCapability() const; - inline ::capnp::Void getCapability() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::AnyPointer::Unconstrained::Builder { -public: - typedef Unconstrained Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isAnyKind(); - inline ::capnp::Void getAnyKind(); - inline void setAnyKind( ::capnp::Void value = ::capnp::VOID); - - inline bool isStruct(); - inline ::capnp::Void getStruct(); - inline void setStruct( ::capnp::Void value = ::capnp::VOID); - - inline bool isList(); - inline ::capnp::Void getList(); - inline void setList( ::capnp::Void value = ::capnp::VOID); - - inline bool isCapability(); - inline ::capnp::Void getCapability(); - inline void setCapability( ::capnp::Void value = ::capnp::VOID); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::AnyPointer::Unconstrained::Pipeline { -public: - typedef Unconstrained Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::AnyPointer::Parameter::Reader { -public: - typedef Parameter Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getScopeId() const; - - inline ::uint16_t getParameterIndex() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::AnyPointer::Parameter::Builder { -public: - typedef Parameter Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getScopeId(); - inline void setScopeId( ::uint64_t value); - - inline ::uint16_t getParameterIndex(); - inline void setParameterIndex( ::uint16_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::AnyPointer::Parameter::Pipeline { -public: - typedef Parameter Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Type::AnyPointer::ImplicitMethodParameter::Reader { -public: - typedef ImplicitMethodParameter Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint16_t getParameterIndex() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Type::AnyPointer::ImplicitMethodParameter::Builder { -public: - typedef ImplicitMethodParameter Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint16_t getParameterIndex(); - inline void setParameterIndex( ::uint16_t value); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Type::AnyPointer::ImplicitMethodParameter::Pipeline { -public: - typedef ImplicitMethodParameter Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Brand::Reader { -public: - typedef Brand Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasScopes() const; - inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader getScopes() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Brand::Builder { -public: - typedef Brand Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasScopes(); - inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder getScopes(); - inline void setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value); - inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder initScopes(unsigned int size); - inline void adoptScopes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> disownScopes(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Brand::Pipeline { -public: - typedef Brand Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Brand::Scope::Reader { -public: - typedef Scope Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline ::uint64_t getScopeId() const; - - inline bool isBind() const; - inline bool hasBind() const; - inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader getBind() const; - - inline bool isInherit() const; - inline ::capnp::Void getInherit() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Brand::Scope::Builder { -public: - typedef Scope Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline ::uint64_t getScopeId(); - inline void setScopeId( ::uint64_t value); - - inline bool isBind(); - inline bool hasBind(); - inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder getBind(); - inline void setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value); - inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder initBind(unsigned int size); - inline void adoptBind(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> disownBind(); - - inline bool isInherit(); - inline ::capnp::Void getInherit(); - inline void setInherit( ::capnp::Void value = ::capnp::VOID); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Brand::Scope::Pipeline { -public: - typedef Scope Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Brand::Binding::Reader { -public: - typedef Binding Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isUnbound() const; - inline ::capnp::Void getUnbound() const; - - inline bool isType() const; - inline bool hasType() const; - inline ::capnp::schema::Type::Reader getType() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Brand::Binding::Builder { -public: - typedef Binding Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isUnbound(); - inline ::capnp::Void getUnbound(); - inline void setUnbound( ::capnp::Void value = ::capnp::VOID); - - inline bool isType(); - inline bool hasType(); - inline ::capnp::schema::Type::Builder getType(); - inline void setType( ::capnp::schema::Type::Reader value); - inline ::capnp::schema::Type::Builder initType(); - inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); - inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Brand::Binding::Pipeline { -public: - typedef Binding Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Value::Reader { -public: - typedef Value Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline Which which() const; - inline bool isVoid() const; - inline ::capnp::Void getVoid() const; - - inline bool isBool() const; - inline bool getBool() const; - - inline bool isInt8() const; - inline ::int8_t getInt8() const; - - inline bool isInt16() const; - inline ::int16_t getInt16() const; - - inline bool isInt32() const; - inline ::int32_t getInt32() const; - - inline bool isInt64() const; - inline ::int64_t getInt64() const; - - inline bool isUint8() const; - inline ::uint8_t getUint8() const; - - inline bool isUint16() const; - inline ::uint16_t getUint16() const; - - inline bool isUint32() const; - inline ::uint32_t getUint32() const; - - inline bool isUint64() const; - inline ::uint64_t getUint64() const; - - inline bool isFloat32() const; - inline float getFloat32() const; - - inline bool isFloat64() const; - inline double getFloat64() const; - - inline bool isText() const; - inline bool hasText() const; - inline ::capnp::Text::Reader getText() const; - - inline bool isData() const; - inline bool hasData() const; - inline ::capnp::Data::Reader getData() const; - - inline bool isList() const; - inline bool hasList() const; - inline ::capnp::AnyPointer::Reader getList() const; - - inline bool isEnum() const; - inline ::uint16_t getEnum() const; - - inline bool isStruct() const; - inline bool hasStruct() const; - inline ::capnp::AnyPointer::Reader getStruct() const; - - inline bool isInterface() const; - inline ::capnp::Void getInterface() const; - - inline bool isAnyPointer() const; - inline bool hasAnyPointer() const; - inline ::capnp::AnyPointer::Reader getAnyPointer() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Value::Builder { -public: - typedef Value Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline Which which(); - inline bool isVoid(); - inline ::capnp::Void getVoid(); - inline void setVoid( ::capnp::Void value = ::capnp::VOID); - - inline bool isBool(); - inline bool getBool(); - inline void setBool(bool value); - - inline bool isInt8(); - inline ::int8_t getInt8(); - inline void setInt8( ::int8_t value); - - inline bool isInt16(); - inline ::int16_t getInt16(); - inline void setInt16( ::int16_t value); - - inline bool isInt32(); - inline ::int32_t getInt32(); - inline void setInt32( ::int32_t value); - - inline bool isInt64(); - inline ::int64_t getInt64(); - inline void setInt64( ::int64_t value); - - inline bool isUint8(); - inline ::uint8_t getUint8(); - inline void setUint8( ::uint8_t value); - - inline bool isUint16(); - inline ::uint16_t getUint16(); - inline void setUint16( ::uint16_t value); - - inline bool isUint32(); - inline ::uint32_t getUint32(); - inline void setUint32( ::uint32_t value); - - inline bool isUint64(); - inline ::uint64_t getUint64(); - inline void setUint64( ::uint64_t value); - - inline bool isFloat32(); - inline float getFloat32(); - inline void setFloat32(float value); - - inline bool isFloat64(); - inline double getFloat64(); - inline void setFloat64(double value); - - inline bool isText(); - inline bool hasText(); - inline ::capnp::Text::Builder getText(); - inline void setText( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initText(unsigned int size); - inline void adoptText(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownText(); - - inline bool isData(); - inline bool hasData(); - inline ::capnp::Data::Builder getData(); - inline void setData( ::capnp::Data::Reader value); - inline ::capnp::Data::Builder initData(unsigned int size); - inline void adoptData(::capnp::Orphan< ::capnp::Data>&& value); - inline ::capnp::Orphan< ::capnp::Data> disownData(); - - inline bool isList(); - inline bool hasList(); - inline ::capnp::AnyPointer::Builder getList(); - inline ::capnp::AnyPointer::Builder initList(); - - inline bool isEnum(); - inline ::uint16_t getEnum(); - inline void setEnum( ::uint16_t value); - - inline bool isStruct(); - inline bool hasStruct(); - inline ::capnp::AnyPointer::Builder getStruct(); - inline ::capnp::AnyPointer::Builder initStruct(); - - inline bool isInterface(); - inline ::capnp::Void getInterface(); - inline void setInterface( ::capnp::Void value = ::capnp::VOID); - - inline bool isAnyPointer(); - inline bool hasAnyPointer(); - inline ::capnp::AnyPointer::Builder getAnyPointer(); - inline ::capnp::AnyPointer::Builder initAnyPointer(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Value::Pipeline { -public: - typedef Value Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class Annotation::Reader { -public: - typedef Annotation Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getId() const; - - inline bool hasValue() const; - inline ::capnp::schema::Value::Reader getValue() const; - - inline bool hasBrand() const; - inline ::capnp::schema::Brand::Reader getBrand() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class Annotation::Builder { -public: - typedef Annotation Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - - inline bool hasValue(); - inline ::capnp::schema::Value::Builder getValue(); - inline void setValue( ::capnp::schema::Value::Reader value); - inline ::capnp::schema::Value::Builder initValue(); - inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); - inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); - - inline bool hasBrand(); - inline ::capnp::schema::Brand::Builder getBrand(); - inline void setBrand( ::capnp::schema::Brand::Reader value); - inline ::capnp::schema::Brand::Builder initBrand(); - inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); - inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class Annotation::Pipeline { -public: - typedef Annotation Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - - inline ::capnp::schema::Value::Pipeline getValue(); - inline ::capnp::schema::Brand::Pipeline getBrand(); -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class CodeGeneratorRequest::Reader { -public: - typedef CodeGeneratorRequest Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline bool hasNodes() const; - inline ::capnp::List< ::capnp::schema::Node>::Reader getNodes() const; - - inline bool hasRequestedFiles() const; - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader getRequestedFiles() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class CodeGeneratorRequest::Builder { -public: - typedef CodeGeneratorRequest Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline bool hasNodes(); - inline ::capnp::List< ::capnp::schema::Node>::Builder getNodes(); - inline void setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value); - inline ::capnp::List< ::capnp::schema::Node>::Builder initNodes(unsigned int size); - inline void adoptNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> disownNodes(); - - inline bool hasRequestedFiles(); - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder getRequestedFiles(); - inline void setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value); - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder initRequestedFiles(unsigned int size); - inline void adoptRequestedFiles(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> disownRequestedFiles(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class CodeGeneratorRequest::Pipeline { -public: - typedef CodeGeneratorRequest Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class CodeGeneratorRequest::RequestedFile::Reader { -public: - typedef RequestedFile Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getId() const; - - inline bool hasFilename() const; - inline ::capnp::Text::Reader getFilename() const; - - inline bool hasImports() const; - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader getImports() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class CodeGeneratorRequest::RequestedFile::Builder { -public: - typedef RequestedFile Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - - inline bool hasFilename(); - inline ::capnp::Text::Builder getFilename(); - inline void setFilename( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initFilename(unsigned int size); - inline void adoptFilename(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownFilename(); - - inline bool hasImports(); - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder getImports(); - inline void setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value); - inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder initImports(unsigned int size); - inline void adoptImports(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value); - inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> disownImports(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class CodeGeneratorRequest::RequestedFile::Pipeline { -public: - typedef RequestedFile Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -class CodeGeneratorRequest::RequestedFile::Import::Reader { -public: - typedef Import Reads; - - Reader() = default; - inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} - - inline ::capnp::MessageSize totalSize() const { - return _reader.totalSize().asPublic(); - } - -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { - return ::capnp::_::structString(_reader, *_capnpPrivate::brand); - } -#endif // !CAPNP_LITE - - inline ::uint64_t getId() const; - - inline bool hasName() const; - inline ::capnp::Text::Reader getName() const; - -private: - ::capnp::_::StructReader _reader; - template - friend struct ::capnp::ToDynamic_; - template - friend struct ::capnp::_::PointerHelpers; - template - friend struct ::capnp::List; - friend class ::capnp::MessageBuilder; - friend class ::capnp::Orphanage; -}; - -class CodeGeneratorRequest::RequestedFile::Import::Builder { -public: - typedef Import Builds; - - Builder() = delete; // Deleted to discourage incorrect usage. - // You can explicitly initialize to nullptr instead. - inline Builder(decltype(nullptr)) {} - inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} - inline operator Reader() const { return Reader(_builder.asReader()); } - inline Reader asReader() const { return *this; } - - inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } -#if !CAPNP_LITE - inline ::kj::StringTree toString() const { return asReader().toString(); } -#endif // !CAPNP_LITE - - inline ::uint64_t getId(); - inline void setId( ::uint64_t value); - - inline bool hasName(); - inline ::capnp::Text::Builder getName(); - inline void setName( ::capnp::Text::Reader value); - inline ::capnp::Text::Builder initName(unsigned int size); - inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); - inline ::capnp::Orphan< ::capnp::Text> disownName(); - -private: - ::capnp::_::StructBuilder _builder; - template - friend struct ::capnp::ToDynamic_; - friend class ::capnp::Orphanage; - template - friend struct ::capnp::_::PointerHelpers; -}; - -#if !CAPNP_LITE -class CodeGeneratorRequest::RequestedFile::Import::Pipeline { -public: - typedef Import Pipelines; - - inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} - inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) - : _typeless(kj::mv(typeless)) {} - -private: - ::capnp::AnyPointer::Pipeline _typeless; - friend class ::capnp::PipelineHook; - template - friend struct ::capnp::ToDynamic_; -}; -#endif // !CAPNP_LITE - -// ======================================================================================= - -inline ::capnp::schema::Node::Which Node::Reader::which() const { - return _reader.getDataField(6 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Node::Which Node::Builder::which() { - return _builder.getDataField(6 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Node::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Node::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Node::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Reader::hasDisplayName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Builder::hasDisplayName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Node::Reader::getDisplayName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Node::Builder::getDisplayName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Node::Builder::setDisplayName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Node::Builder::initDisplayName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Node::Builder::adoptDisplayName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Node::Builder::disownDisplayName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint32_t Node::Reader::getDisplayNamePrefixLength() const { - return _reader.getDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Node::Builder::getDisplayNamePrefixLength() { - return _builder.getDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Node::Builder::setDisplayNamePrefixLength( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline ::uint64_t Node::Reader::getScopeId() const { - return _reader.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Node::Builder::getScopeId() { - return _builder.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Node::Builder::setScopeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Reader::hasNestedNodes() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Builder::hasNestedNodes() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader Node::Reader::getNestedNodes() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::getNestedNodes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Node::Builder::setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::initNestedNodes(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void Node::Builder::adoptNestedNodes( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> Node::Builder::disownNestedNodes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline bool Node::Reader::hasAnnotations() const { - return !_reader.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Builder::hasAnnotations() { - return !_builder.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Reader Node::Reader::getAnnotations() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _reader.getPointerField(2 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::getAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -inline void Node::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set( - _builder.getPointerField(2 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::initAnnotations(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init( - _builder.getPointerField(2 * ::capnp::POINTERS), size); -} -inline void Node::Builder::adoptAnnotations( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt( - _builder.getPointerField(2 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Node::Builder::disownAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} - -inline bool Node::Reader::isFile() const { - return which() == Node::FILE; -} -inline bool Node::Builder::isFile() { - return which() == Node::FILE; -} -inline ::capnp::Void Node::Reader::getFile() const { - KJ_IREQUIRE((which() == Node::FILE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Node::Builder::getFile() { - KJ_IREQUIRE((which() == Node::FILE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Node::Builder::setFile( ::capnp::Void value) { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::FILE); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Reader::isStruct() const { - return which() == Node::STRUCT; -} -inline bool Node::Builder::isStruct() { - return which() == Node::STRUCT; -} -inline typename Node::Struct::Reader Node::Reader::getStruct() const { - KJ_IREQUIRE((which() == Node::STRUCT), - "Must check which() before get()ing a union member."); - return typename Node::Struct::Reader(_reader); -} -inline typename Node::Struct::Builder Node::Builder::getStruct() { - KJ_IREQUIRE((which() == Node::STRUCT), - "Must check which() before get()ing a union member."); - return typename Node::Struct::Builder(_builder); -} -inline typename Node::Struct::Builder Node::Builder::initStruct() { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::STRUCT); - _builder.setDataField< ::uint16_t>(7 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(12 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(13 * ::capnp::ELEMENTS, 0); - _builder.setDataField(224 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(15 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint32_t>(8 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - return typename Node::Struct::Builder(_builder); -} -inline bool Node::Reader::isEnum() const { - return which() == Node::ENUM; -} -inline bool Node::Builder::isEnum() { - return which() == Node::ENUM; -} -inline typename Node::Enum::Reader Node::Reader::getEnum() const { - KJ_IREQUIRE((which() == Node::ENUM), - "Must check which() before get()ing a union member."); - return typename Node::Enum::Reader(_reader); -} -inline typename Node::Enum::Builder Node::Builder::getEnum() { - KJ_IREQUIRE((which() == Node::ENUM), - "Must check which() before get()ing a union member."); - return typename Node::Enum::Builder(_builder); -} -inline typename Node::Enum::Builder Node::Builder::initEnum() { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::ENUM); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - return typename Node::Enum::Builder(_builder); -} -inline bool Node::Reader::isInterface() const { - return which() == Node::INTERFACE; -} -inline bool Node::Builder::isInterface() { - return which() == Node::INTERFACE; -} -inline typename Node::Interface::Reader Node::Reader::getInterface() const { - KJ_IREQUIRE((which() == Node::INTERFACE), - "Must check which() before get()ing a union member."); - return typename Node::Interface::Reader(_reader); -} -inline typename Node::Interface::Builder Node::Builder::getInterface() { - KJ_IREQUIRE((which() == Node::INTERFACE), - "Must check which() before get()ing a union member."); - return typename Node::Interface::Builder(_builder); -} -inline typename Node::Interface::Builder Node::Builder::initInterface() { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::INTERFACE); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - _builder.getPointerField(4 * ::capnp::POINTERS).clear(); - return typename Node::Interface::Builder(_builder); -} -inline bool Node::Reader::isConst() const { - return which() == Node::CONST; -} -inline bool Node::Builder::isConst() { - return which() == Node::CONST; -} -inline typename Node::Const::Reader Node::Reader::getConst() const { - KJ_IREQUIRE((which() == Node::CONST), - "Must check which() before get()ing a union member."); - return typename Node::Const::Reader(_reader); -} -inline typename Node::Const::Builder Node::Builder::getConst() { - KJ_IREQUIRE((which() == Node::CONST), - "Must check which() before get()ing a union member."); - return typename Node::Const::Builder(_builder); -} -inline typename Node::Const::Builder Node::Builder::initConst() { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::CONST); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - _builder.getPointerField(4 * ::capnp::POINTERS).clear(); - return typename Node::Const::Builder(_builder); -} -inline bool Node::Reader::isAnnotation() const { - return which() == Node::ANNOTATION; -} -inline bool Node::Builder::isAnnotation() { - return which() == Node::ANNOTATION; -} -inline typename Node::Annotation::Reader Node::Reader::getAnnotation() const { - KJ_IREQUIRE((which() == Node::ANNOTATION), - "Must check which() before get()ing a union member."); - return typename Node::Annotation::Reader(_reader); -} -inline typename Node::Annotation::Builder Node::Builder::getAnnotation() { - KJ_IREQUIRE((which() == Node::ANNOTATION), - "Must check which() before get()ing a union member."); - return typename Node::Annotation::Builder(_builder); -} -inline typename Node::Annotation::Builder Node::Builder::initAnnotation() { - _builder.setDataField( - 6 * ::capnp::ELEMENTS, Node::ANNOTATION); - _builder.setDataField(112 * ::capnp::ELEMENTS, 0); - _builder.setDataField(113 * ::capnp::ELEMENTS, 0); - _builder.setDataField(114 * ::capnp::ELEMENTS, 0); - _builder.setDataField(115 * ::capnp::ELEMENTS, 0); - _builder.setDataField(116 * ::capnp::ELEMENTS, 0); - _builder.setDataField(117 * ::capnp::ELEMENTS, 0); - _builder.setDataField(118 * ::capnp::ELEMENTS, 0); - _builder.setDataField(119 * ::capnp::ELEMENTS, 0); - _builder.setDataField(120 * ::capnp::ELEMENTS, 0); - _builder.setDataField(121 * ::capnp::ELEMENTS, 0); - _builder.setDataField(122 * ::capnp::ELEMENTS, 0); - _builder.setDataField(123 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - return typename Node::Annotation::Builder(_builder); -} -inline bool Node::Reader::hasParameters() const { - return !_reader.getPointerField(5 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Builder::hasParameters() { - return !_builder.getPointerField(5 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Node::Reader::getParameters() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get( - _reader.getPointerField(5 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::getParameters() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get( - _builder.getPointerField(5 * ::capnp::POINTERS)); -} -inline void Node::Builder::setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set( - _builder.getPointerField(5 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::initParameters(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init( - _builder.getPointerField(5 * ::capnp::POINTERS), size); -} -inline void Node::Builder::adoptParameters( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt( - _builder.getPointerField(5 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Node::Builder::disownParameters() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown( - _builder.getPointerField(5 * ::capnp::POINTERS)); -} - -inline bool Node::Reader::getIsGeneric() const { - return _reader.getDataField( - 288 * ::capnp::ELEMENTS); -} - -inline bool Node::Builder::getIsGeneric() { - return _builder.getDataField( - 288 * ::capnp::ELEMENTS); -} -inline void Node::Builder::setIsGeneric(bool value) { - _builder.setDataField( - 288 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Parameter::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Parameter::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Node::Parameter::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Node::Parameter::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Node::Parameter::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Node::Parameter::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Node::Parameter::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Node::Parameter::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Node::NestedNode::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Node::NestedNode::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Node::NestedNode::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Node::NestedNode::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Node::NestedNode::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Node::NestedNode::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Node::NestedNode::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Node::NestedNode::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint64_t Node::NestedNode::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Node::NestedNode::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Node::NestedNode::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Node::Struct::Reader::getDataWordCount() const { - return _reader.getDataField< ::uint16_t>( - 7 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Node::Struct::Builder::getDataWordCount() { - return _builder.getDataField< ::uint16_t>( - 7 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setDataWordCount( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 7 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Node::Struct::Reader::getPointerCount() const { - return _reader.getDataField< ::uint16_t>( - 12 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Node::Struct::Builder::getPointerCount() { - return _builder.getDataField< ::uint16_t>( - 12 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setPointerCount( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 12 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::schema::ElementSize Node::Struct::Reader::getPreferredListEncoding() const { - return _reader.getDataField< ::capnp::schema::ElementSize>( - 13 * ::capnp::ELEMENTS); -} - -inline ::capnp::schema::ElementSize Node::Struct::Builder::getPreferredListEncoding() { - return _builder.getDataField< ::capnp::schema::ElementSize>( - 13 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setPreferredListEncoding( ::capnp::schema::ElementSize value) { - _builder.setDataField< ::capnp::schema::ElementSize>( - 13 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Struct::Reader::getIsGroup() const { - return _reader.getDataField( - 224 * ::capnp::ELEMENTS); -} - -inline bool Node::Struct::Builder::getIsGroup() { - return _builder.getDataField( - 224 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setIsGroup(bool value) { - _builder.setDataField( - 224 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Node::Struct::Reader::getDiscriminantCount() const { - return _reader.getDataField< ::uint16_t>( - 15 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Node::Struct::Builder::getDiscriminantCount() { - return _builder.getDataField< ::uint16_t>( - 15 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setDiscriminantCount( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 15 * ::capnp::ELEMENTS, value); -} - -inline ::uint32_t Node::Struct::Reader::getDiscriminantOffset() const { - return _reader.getDataField< ::uint32_t>( - 8 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Node::Struct::Builder::getDiscriminantOffset() { - return _builder.getDataField< ::uint32_t>( - 8 * ::capnp::ELEMENTS); -} -inline void Node::Struct::Builder::setDiscriminantOffset( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 8 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Struct::Reader::hasFields() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Struct::Builder::hasFields() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Field>::Reader Node::Struct::Reader::getFields() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::getFields() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Node::Struct::Builder::setFields( ::capnp::List< ::capnp::schema::Field>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::initFields(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::init( - _builder.getPointerField(3 * ::capnp::POINTERS), size); -} -inline void Node::Struct::Builder::adoptFields( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> Node::Struct::Builder::disownFields() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Node::Enum::Reader::hasEnumerants() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Enum::Builder::hasEnumerants() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Enumerant>::Reader Node::Enum::Reader::getEnumerants() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::getEnumerants() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Node::Enum::Builder::setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::initEnumerants(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::init( - _builder.getPointerField(3 * ::capnp::POINTERS), size); -} -inline void Node::Enum::Builder::adoptEnumerants( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> Node::Enum::Builder::disownEnumerants() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Node::Interface::Reader::hasMethods() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Interface::Builder::hasMethods() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Method>::Reader Node::Interface::Reader::getMethods() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::getMethods() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Node::Interface::Builder::setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::initMethods(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::init( - _builder.getPointerField(3 * ::capnp::POINTERS), size); -} -inline void Node::Interface::Builder::adoptMethods( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> Node::Interface::Builder::disownMethods() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Node::Interface::Reader::hasSuperclasses() const { - return !_reader.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Interface::Builder::hasSuperclasses() { - return !_builder.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Superclass>::Reader Node::Interface::Reader::getSuperclasses() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get( - _reader.getPointerField(4 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::getSuperclasses() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} -inline void Node::Interface::Builder::setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::set( - _builder.getPointerField(4 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::initSuperclasses(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::init( - _builder.getPointerField(4 * ::capnp::POINTERS), size); -} -inline void Node::Interface::Builder::adoptSuperclasses( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::adopt( - _builder.getPointerField(4 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> Node::Interface::Builder::disownSuperclasses() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::disown( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} - -inline bool Node::Const::Reader::hasType() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Const::Builder::hasType() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Type::Reader Node::Const::Reader::getType() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Type::Builder Node::Const::Builder::getType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Type::Pipeline Node::Const::Pipeline::getType() { - return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); -} -#endif // !CAPNP_LITE -inline void Node::Const::Builder::setType( ::capnp::schema::Type::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Type::Builder Node::Const::Builder::initType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Node::Const::Builder::adoptType( - ::capnp::Orphan< ::capnp::schema::Type>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Type> Node::Const::Builder::disownType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Node::Const::Reader::hasValue() const { - return !_reader.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Const::Builder::hasValue() { - return !_builder.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Value::Reader Node::Const::Reader::getValue() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _reader.getPointerField(4 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Value::Builder Node::Const::Builder::getValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Value::Pipeline Node::Const::Pipeline::getValue() { - return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(4)); -} -#endif // !CAPNP_LITE -inline void Node::Const::Builder::setValue( ::capnp::schema::Value::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set( - _builder.getPointerField(4 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Value::Builder Node::Const::Builder::initValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} -inline void Node::Const::Builder::adoptValue( - ::capnp::Orphan< ::capnp::schema::Value>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt( - _builder.getPointerField(4 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Value> Node::Const::Builder::disownValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} - -inline bool Node::Annotation::Reader::hasType() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Node::Annotation::Builder::hasType() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Type::Reader Node::Annotation::Reader::getType() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Type::Builder Node::Annotation::Builder::getType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Type::Pipeline Node::Annotation::Pipeline::getType() { - return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); -} -#endif // !CAPNP_LITE -inline void Node::Annotation::Builder::setType( ::capnp::schema::Type::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Type::Builder Node::Annotation::Builder::initType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Node::Annotation::Builder::adoptType( - ::capnp::Orphan< ::capnp::schema::Type>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Type> Node::Annotation::Builder::disownType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Node::Annotation::Reader::getTargetsFile() const { - return _reader.getDataField( - 112 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsFile() { - return _builder.getDataField( - 112 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsFile(bool value) { - _builder.setDataField( - 112 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsConst() const { - return _reader.getDataField( - 113 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsConst() { - return _builder.getDataField( - 113 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsConst(bool value) { - _builder.setDataField( - 113 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsEnum() const { - return _reader.getDataField( - 114 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsEnum() { - return _builder.getDataField( - 114 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsEnum(bool value) { - _builder.setDataField( - 114 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsEnumerant() const { - return _reader.getDataField( - 115 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsEnumerant() { - return _builder.getDataField( - 115 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsEnumerant(bool value) { - _builder.setDataField( - 115 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsStruct() const { - return _reader.getDataField( - 116 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsStruct() { - return _builder.getDataField( - 116 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsStruct(bool value) { - _builder.setDataField( - 116 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsField() const { - return _reader.getDataField( - 117 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsField() { - return _builder.getDataField( - 117 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsField(bool value) { - _builder.setDataField( - 117 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsUnion() const { - return _reader.getDataField( - 118 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsUnion() { - return _builder.getDataField( - 118 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsUnion(bool value) { - _builder.setDataField( - 118 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsGroup() const { - return _reader.getDataField( - 119 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsGroup() { - return _builder.getDataField( - 119 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsGroup(bool value) { - _builder.setDataField( - 119 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsInterface() const { - return _reader.getDataField( - 120 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsInterface() { - return _builder.getDataField( - 120 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsInterface(bool value) { - _builder.setDataField( - 120 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsMethod() const { - return _reader.getDataField( - 121 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsMethod() { - return _builder.getDataField( - 121 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsMethod(bool value) { - _builder.setDataField( - 121 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsParam() const { - return _reader.getDataField( - 122 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsParam() { - return _builder.getDataField( - 122 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsParam(bool value) { - _builder.setDataField( - 122 * ::capnp::ELEMENTS, value); -} - -inline bool Node::Annotation::Reader::getTargetsAnnotation() const { - return _reader.getDataField( - 123 * ::capnp::ELEMENTS); -} - -inline bool Node::Annotation::Builder::getTargetsAnnotation() { - return _builder.getDataField( - 123 * ::capnp::ELEMENTS); -} -inline void Node::Annotation::Builder::setTargetsAnnotation(bool value) { - _builder.setDataField( - 123 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::schema::Field::Which Field::Reader::which() const { - return _reader.getDataField(4 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Field::Which Field::Builder::which() { - return _builder.getDataField(4 * ::capnp::ELEMENTS); -} - -inline bool Field::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Field::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Field::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Field::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Field::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Field::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Field::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Field::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint16_t Field::Reader::getCodeOrder() const { - return _reader.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Field::Builder::getCodeOrder() { - return _builder.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Field::Builder::setCodeOrder( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Field::Reader::hasAnnotations() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Field::Builder::hasAnnotations() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Reader Field::Reader::getAnnotations() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::getAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Field::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::initAnnotations(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void Field::Builder::adoptAnnotations( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Field::Builder::disownAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline ::uint16_t Field::Reader::getDiscriminantValue() const { - return _reader.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, 65535u); -} - -inline ::uint16_t Field::Builder::getDiscriminantValue() { - return _builder.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, 65535u); -} -inline void Field::Builder::setDiscriminantValue( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, value, 65535u); -} - -inline bool Field::Reader::isSlot() const { - return which() == Field::SLOT; -} -inline bool Field::Builder::isSlot() { - return which() == Field::SLOT; -} -inline typename Field::Slot::Reader Field::Reader::getSlot() const { - KJ_IREQUIRE((which() == Field::SLOT), - "Must check which() before get()ing a union member."); - return typename Field::Slot::Reader(_reader); -} -inline typename Field::Slot::Builder Field::Builder::getSlot() { - KJ_IREQUIRE((which() == Field::SLOT), - "Must check which() before get()ing a union member."); - return typename Field::Slot::Builder(_builder); -} -inline typename Field::Slot::Builder Field::Builder::initSlot() { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Field::SLOT); - _builder.setDataField< ::uint32_t>(1 * ::capnp::ELEMENTS, 0); - _builder.setDataField(128 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(2 * ::capnp::POINTERS).clear(); - _builder.getPointerField(3 * ::capnp::POINTERS).clear(); - return typename Field::Slot::Builder(_builder); -} -inline bool Field::Reader::isGroup() const { - return which() == Field::GROUP; -} -inline bool Field::Builder::isGroup() { - return which() == Field::GROUP; -} -inline typename Field::Group::Reader Field::Reader::getGroup() const { - KJ_IREQUIRE((which() == Field::GROUP), - "Must check which() before get()ing a union member."); - return typename Field::Group::Reader(_reader); -} -inline typename Field::Group::Builder Field::Builder::getGroup() { - KJ_IREQUIRE((which() == Field::GROUP), - "Must check which() before get()ing a union member."); - return typename Field::Group::Builder(_builder); -} -inline typename Field::Group::Builder Field::Builder::initGroup() { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Field::GROUP); - _builder.setDataField< ::uint64_t>(2 * ::capnp::ELEMENTS, 0); - return typename Field::Group::Builder(_builder); -} -inline typename Field::Ordinal::Reader Field::Reader::getOrdinal() const { - return typename Field::Ordinal::Reader(_reader); -} -inline typename Field::Ordinal::Builder Field::Builder::getOrdinal() { - return typename Field::Ordinal::Builder(_builder); -} -#if !CAPNP_LITE -inline typename Field::Ordinal::Pipeline Field::Pipeline::getOrdinal() { - return typename Field::Ordinal::Pipeline(_typeless.noop()); -} -#endif // !CAPNP_LITE -inline typename Field::Ordinal::Builder Field::Builder::initOrdinal() { - _builder.setDataField< ::uint16_t>(5 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(6 * ::capnp::ELEMENTS, 0); - return typename Field::Ordinal::Builder(_builder); -} -inline ::uint32_t Field::Slot::Reader::getOffset() const { - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Field::Slot::Builder::getOffset() { - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Field::Slot::Builder::setOffset( ::uint32_t value) { - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Field::Slot::Reader::hasType() const { - return !_reader.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline bool Field::Slot::Builder::hasType() { - return !_builder.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Type::Reader Field::Slot::Reader::getType() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _reader.getPointerField(2 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Type::Builder Field::Slot::Builder::getType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Type::Pipeline Field::Slot::Pipeline::getType() { - return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(2)); -} -#endif // !CAPNP_LITE -inline void Field::Slot::Builder::setType( ::capnp::schema::Type::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set( - _builder.getPointerField(2 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Type::Builder Field::Slot::Builder::initType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -inline void Field::Slot::Builder::adoptType( - ::capnp::Orphan< ::capnp::schema::Type>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt( - _builder.getPointerField(2 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Type> Field::Slot::Builder::disownType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} - -inline bool Field::Slot::Reader::hasDefaultValue() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Field::Slot::Builder::hasDefaultValue() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Value::Reader Field::Slot::Reader::getDefaultValue() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Value::Builder Field::Slot::Builder::getDefaultValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Value::Pipeline Field::Slot::Pipeline::getDefaultValue() { - return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(3)); -} -#endif // !CAPNP_LITE -inline void Field::Slot::Builder::setDefaultValue( ::capnp::schema::Value::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Value::Builder Field::Slot::Builder::initDefaultValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Field::Slot::Builder::adoptDefaultValue( - ::capnp::Orphan< ::capnp::schema::Value>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Value> Field::Slot::Builder::disownDefaultValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Field::Slot::Reader::getHadExplicitDefault() const { - return _reader.getDataField( - 128 * ::capnp::ELEMENTS); -} - -inline bool Field::Slot::Builder::getHadExplicitDefault() { - return _builder.getDataField( - 128 * ::capnp::ELEMENTS); -} -inline void Field::Slot::Builder::setHadExplicitDefault(bool value) { - _builder.setDataField( - 128 * ::capnp::ELEMENTS, value); -} - -inline ::uint64_t Field::Group::Reader::getTypeId() const { - return _reader.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Field::Group::Builder::getTypeId() { - return _builder.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Field::Group::Builder::setTypeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Reader::which() const { - return _reader.getDataField(5 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Builder::which() { - return _builder.getDataField(5 * ::capnp::ELEMENTS); -} - -inline bool Field::Ordinal::Reader::isImplicit() const { - return which() == Field::Ordinal::IMPLICIT; -} -inline bool Field::Ordinal::Builder::isImplicit() { - return which() == Field::Ordinal::IMPLICIT; -} -inline ::capnp::Void Field::Ordinal::Reader::getImplicit() const { - KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Field::Ordinal::Builder::getImplicit() { - KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Field::Ordinal::Builder::setImplicit( ::capnp::Void value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Field::Ordinal::IMPLICIT); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Field::Ordinal::Reader::isExplicit() const { - return which() == Field::Ordinal::EXPLICIT; -} -inline bool Field::Ordinal::Builder::isExplicit() { - return which() == Field::Ordinal::EXPLICIT; -} -inline ::uint16_t Field::Ordinal::Reader::getExplicit() const { - KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint16_t>( - 6 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Field::Ordinal::Builder::getExplicit() { - KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint16_t>( - 6 * ::capnp::ELEMENTS); -} -inline void Field::Ordinal::Builder::setExplicit( ::uint16_t value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Field::Ordinal::EXPLICIT); - _builder.setDataField< ::uint16_t>( - 6 * ::capnp::ELEMENTS, value); -} - -inline bool Enumerant::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Enumerant::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Enumerant::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Enumerant::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Enumerant::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Enumerant::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Enumerant::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Enumerant::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint16_t Enumerant::Reader::getCodeOrder() const { - return _reader.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Enumerant::Builder::getCodeOrder() { - return _builder.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Enumerant::Builder::setCodeOrder( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Enumerant::Reader::hasAnnotations() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Enumerant::Builder::hasAnnotations() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Reader Enumerant::Reader::getAnnotations() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::getAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Enumerant::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::initAnnotations(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void Enumerant::Builder::adoptAnnotations( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Enumerant::Builder::disownAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline ::uint64_t Superclass::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Superclass::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Superclass::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Superclass::Reader::hasBrand() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Superclass::Builder::hasBrand() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Superclass::Reader::getBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Superclass::Builder::getBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Superclass::Pipeline::getBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Superclass::Builder::setBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Superclass::Builder::initBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Superclass::Builder::adoptBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Superclass::Builder::disownBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Method::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Method::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Method::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Method::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Method::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Method::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Method::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Method::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint16_t Method::Reader::getCodeOrder() const { - return _reader.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Method::Builder::getCodeOrder() { - return _builder.getDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Method::Builder::setCodeOrder( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint64_t Method::Reader::getParamStructType() const { - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Method::Builder::getParamStructType() { - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Method::Builder::setParamStructType( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline ::uint64_t Method::Reader::getResultStructType() const { - return _reader.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Method::Builder::getResultStructType() { - return _builder.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Method::Builder::setResultStructType( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Method::Reader::hasAnnotations() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Method::Builder::hasAnnotations() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Reader Method::Reader::getAnnotations() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::getAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Method::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::initAnnotations(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void Method::Builder::adoptAnnotations( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Method::Builder::disownAnnotations() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline bool Method::Reader::hasParamBrand() const { - return !_reader.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline bool Method::Builder::hasParamBrand() { - return !_builder.getPointerField(2 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Method::Reader::getParamBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(2 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Method::Builder::getParamBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getParamBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(2)); -} -#endif // !CAPNP_LITE -inline void Method::Builder::setParamBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(2 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Method::Builder::initParamBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} -inline void Method::Builder::adoptParamBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(2 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownParamBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(2 * ::capnp::POINTERS)); -} - -inline bool Method::Reader::hasResultBrand() const { - return !_reader.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline bool Method::Builder::hasResultBrand() { - return !_builder.getPointerField(3 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Method::Reader::getResultBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(3 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Method::Builder::getResultBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getResultBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(3)); -} -#endif // !CAPNP_LITE -inline void Method::Builder::setResultBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(3 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Method::Builder::initResultBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} -inline void Method::Builder::adoptResultBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(3 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownResultBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(3 * ::capnp::POINTERS)); -} - -inline bool Method::Reader::hasImplicitParameters() const { - return !_reader.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline bool Method::Builder::hasImplicitParameters() { - return !_builder.getPointerField(4 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Method::Reader::getImplicitParameters() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get( - _reader.getPointerField(4 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::getImplicitParameters() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} -inline void Method::Builder::setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set( - _builder.getPointerField(4 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::initImplicitParameters(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init( - _builder.getPointerField(4 * ::capnp::POINTERS), size); -} -inline void Method::Builder::adoptImplicitParameters( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt( - _builder.getPointerField(4 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Method::Builder::disownImplicitParameters() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown( - _builder.getPointerField(4 * ::capnp::POINTERS)); -} - -inline ::capnp::schema::Type::Which Type::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Type::Which Type::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool Type::Reader::isVoid() const { - return which() == Type::VOID; -} -inline bool Type::Builder::isVoid() { - return which() == Type::VOID; -} -inline ::capnp::Void Type::Reader::getVoid() const { - KJ_IREQUIRE((which() == Type::VOID), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getVoid() { - KJ_IREQUIRE((which() == Type::VOID), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setVoid( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::VOID); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isBool() const { - return which() == Type::BOOL; -} -inline bool Type::Builder::isBool() { - return which() == Type::BOOL; -} -inline ::capnp::Void Type::Reader::getBool() const { - KJ_IREQUIRE((which() == Type::BOOL), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getBool() { - KJ_IREQUIRE((which() == Type::BOOL), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setBool( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::BOOL); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isInt8() const { - return which() == Type::INT8; -} -inline bool Type::Builder::isInt8() { - return which() == Type::INT8; -} -inline ::capnp::Void Type::Reader::getInt8() const { - KJ_IREQUIRE((which() == Type::INT8), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getInt8() { - KJ_IREQUIRE((which() == Type::INT8), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setInt8( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::INT8); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isInt16() const { - return which() == Type::INT16; -} -inline bool Type::Builder::isInt16() { - return which() == Type::INT16; -} -inline ::capnp::Void Type::Reader::getInt16() const { - KJ_IREQUIRE((which() == Type::INT16), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getInt16() { - KJ_IREQUIRE((which() == Type::INT16), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setInt16( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::INT16); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isInt32() const { - return which() == Type::INT32; -} -inline bool Type::Builder::isInt32() { - return which() == Type::INT32; -} -inline ::capnp::Void Type::Reader::getInt32() const { - KJ_IREQUIRE((which() == Type::INT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getInt32() { - KJ_IREQUIRE((which() == Type::INT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setInt32( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::INT32); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isInt64() const { - return which() == Type::INT64; -} -inline bool Type::Builder::isInt64() { - return which() == Type::INT64; -} -inline ::capnp::Void Type::Reader::getInt64() const { - KJ_IREQUIRE((which() == Type::INT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getInt64() { - KJ_IREQUIRE((which() == Type::INT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setInt64( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::INT64); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isUint8() const { - return which() == Type::UINT8; -} -inline bool Type::Builder::isUint8() { - return which() == Type::UINT8; -} -inline ::capnp::Void Type::Reader::getUint8() const { - KJ_IREQUIRE((which() == Type::UINT8), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getUint8() { - KJ_IREQUIRE((which() == Type::UINT8), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setUint8( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::UINT8); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isUint16() const { - return which() == Type::UINT16; -} -inline bool Type::Builder::isUint16() { - return which() == Type::UINT16; -} -inline ::capnp::Void Type::Reader::getUint16() const { - KJ_IREQUIRE((which() == Type::UINT16), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getUint16() { - KJ_IREQUIRE((which() == Type::UINT16), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setUint16( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::UINT16); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isUint32() const { - return which() == Type::UINT32; -} -inline bool Type::Builder::isUint32() { - return which() == Type::UINT32; -} -inline ::capnp::Void Type::Reader::getUint32() const { - KJ_IREQUIRE((which() == Type::UINT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getUint32() { - KJ_IREQUIRE((which() == Type::UINT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setUint32( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::UINT32); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isUint64() const { - return which() == Type::UINT64; -} -inline bool Type::Builder::isUint64() { - return which() == Type::UINT64; -} -inline ::capnp::Void Type::Reader::getUint64() const { - KJ_IREQUIRE((which() == Type::UINT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getUint64() { - KJ_IREQUIRE((which() == Type::UINT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setUint64( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::UINT64); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isFloat32() const { - return which() == Type::FLOAT32; -} -inline bool Type::Builder::isFloat32() { - return which() == Type::FLOAT32; -} -inline ::capnp::Void Type::Reader::getFloat32() const { - KJ_IREQUIRE((which() == Type::FLOAT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getFloat32() { - KJ_IREQUIRE((which() == Type::FLOAT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setFloat32( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::FLOAT32); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isFloat64() const { - return which() == Type::FLOAT64; -} -inline bool Type::Builder::isFloat64() { - return which() == Type::FLOAT64; -} -inline ::capnp::Void Type::Reader::getFloat64() const { - KJ_IREQUIRE((which() == Type::FLOAT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getFloat64() { - KJ_IREQUIRE((which() == Type::FLOAT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setFloat64( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::FLOAT64); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isText() const { - return which() == Type::TEXT; -} -inline bool Type::Builder::isText() { - return which() == Type::TEXT; -} -inline ::capnp::Void Type::Reader::getText() const { - KJ_IREQUIRE((which() == Type::TEXT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getText() { - KJ_IREQUIRE((which() == Type::TEXT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setText( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::TEXT); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isData() const { - return which() == Type::DATA; -} -inline bool Type::Builder::isData() { - return which() == Type::DATA; -} -inline ::capnp::Void Type::Reader::getData() const { - KJ_IREQUIRE((which() == Type::DATA), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::Builder::getData() { - KJ_IREQUIRE((which() == Type::DATA), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::Builder::setData( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::DATA); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Reader::isList() const { - return which() == Type::LIST; -} -inline bool Type::Builder::isList() { - return which() == Type::LIST; -} -inline typename Type::List::Reader Type::Reader::getList() const { - KJ_IREQUIRE((which() == Type::LIST), - "Must check which() before get()ing a union member."); - return typename Type::List::Reader(_reader); -} -inline typename Type::List::Builder Type::Builder::getList() { - KJ_IREQUIRE((which() == Type::LIST), - "Must check which() before get()ing a union member."); - return typename Type::List::Builder(_builder); -} -inline typename Type::List::Builder Type::Builder::initList() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::LIST); - _builder.getPointerField(0 * ::capnp::POINTERS).clear(); - return typename Type::List::Builder(_builder); -} -inline bool Type::Reader::isEnum() const { - return which() == Type::ENUM; -} -inline bool Type::Builder::isEnum() { - return which() == Type::ENUM; -} -inline typename Type::Enum::Reader Type::Reader::getEnum() const { - KJ_IREQUIRE((which() == Type::ENUM), - "Must check which() before get()ing a union member."); - return typename Type::Enum::Reader(_reader); -} -inline typename Type::Enum::Builder Type::Builder::getEnum() { - KJ_IREQUIRE((which() == Type::ENUM), - "Must check which() before get()ing a union member."); - return typename Type::Enum::Builder(_builder); -} -inline typename Type::Enum::Builder Type::Builder::initEnum() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::ENUM); - _builder.setDataField< ::uint64_t>(1 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(0 * ::capnp::POINTERS).clear(); - return typename Type::Enum::Builder(_builder); -} -inline bool Type::Reader::isStruct() const { - return which() == Type::STRUCT; -} -inline bool Type::Builder::isStruct() { - return which() == Type::STRUCT; -} -inline typename Type::Struct::Reader Type::Reader::getStruct() const { - KJ_IREQUIRE((which() == Type::STRUCT), - "Must check which() before get()ing a union member."); - return typename Type::Struct::Reader(_reader); -} -inline typename Type::Struct::Builder Type::Builder::getStruct() { - KJ_IREQUIRE((which() == Type::STRUCT), - "Must check which() before get()ing a union member."); - return typename Type::Struct::Builder(_builder); -} -inline typename Type::Struct::Builder Type::Builder::initStruct() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::STRUCT); - _builder.setDataField< ::uint64_t>(1 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(0 * ::capnp::POINTERS).clear(); - return typename Type::Struct::Builder(_builder); -} -inline bool Type::Reader::isInterface() const { - return which() == Type::INTERFACE; -} -inline bool Type::Builder::isInterface() { - return which() == Type::INTERFACE; -} -inline typename Type::Interface::Reader Type::Reader::getInterface() const { - KJ_IREQUIRE((which() == Type::INTERFACE), - "Must check which() before get()ing a union member."); - return typename Type::Interface::Reader(_reader); -} -inline typename Type::Interface::Builder Type::Builder::getInterface() { - KJ_IREQUIRE((which() == Type::INTERFACE), - "Must check which() before get()ing a union member."); - return typename Type::Interface::Builder(_builder); -} -inline typename Type::Interface::Builder Type::Builder::initInterface() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::INTERFACE); - _builder.setDataField< ::uint64_t>(1 * ::capnp::ELEMENTS, 0); - _builder.getPointerField(0 * ::capnp::POINTERS).clear(); - return typename Type::Interface::Builder(_builder); -} -inline bool Type::Reader::isAnyPointer() const { - return which() == Type::ANY_POINTER; -} -inline bool Type::Builder::isAnyPointer() { - return which() == Type::ANY_POINTER; -} -inline typename Type::AnyPointer::Reader Type::Reader::getAnyPointer() const { - KJ_IREQUIRE((which() == Type::ANY_POINTER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Reader(_reader); -} -inline typename Type::AnyPointer::Builder Type::Builder::getAnyPointer() { - KJ_IREQUIRE((which() == Type::ANY_POINTER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Builder(_builder); -} -inline typename Type::AnyPointer::Builder Type::Builder::initAnyPointer() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Type::ANY_POINTER); - _builder.setDataField< ::uint16_t>(4 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint16_t>(5 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint64_t>(2 * ::capnp::ELEMENTS, 0); - return typename Type::AnyPointer::Builder(_builder); -} -inline bool Type::List::Reader::hasElementType() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Type::List::Builder::hasElementType() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Type::Reader Type::List::Reader::getElementType() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Type::Builder Type::List::Builder::getElementType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Type::Pipeline Type::List::Pipeline::getElementType() { - return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Type::List::Builder::setElementType( ::capnp::schema::Type::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Type::Builder Type::List::Builder::initElementType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Type::List::Builder::adoptElementType( - ::capnp::Orphan< ::capnp::schema::Type>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Type> Type::List::Builder::disownElementType() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint64_t Type::Enum::Reader::getTypeId() const { - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Type::Enum::Builder::getTypeId() { - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Type::Enum::Builder::setTypeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Enum::Reader::hasBrand() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Type::Enum::Builder::hasBrand() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Type::Enum::Reader::getBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Type::Enum::Builder::getBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Type::Enum::Pipeline::getBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Type::Enum::Builder::setBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Type::Enum::Builder::initBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Type::Enum::Builder::adoptBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Enum::Builder::disownBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint64_t Type::Struct::Reader::getTypeId() const { - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Type::Struct::Builder::getTypeId() { - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Type::Struct::Builder::setTypeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Struct::Reader::hasBrand() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Type::Struct::Builder::hasBrand() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Type::Struct::Reader::getBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Type::Struct::Builder::getBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Type::Struct::Pipeline::getBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Type::Struct::Builder::setBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Type::Struct::Builder::initBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Type::Struct::Builder::adoptBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Struct::Builder::disownBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::uint64_t Type::Interface::Reader::getTypeId() const { - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Type::Interface::Builder::getTypeId() { - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Type::Interface::Builder::setTypeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Type::Interface::Reader::hasBrand() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Type::Interface::Builder::hasBrand() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Type::Interface::Reader::getBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Type::Interface::Builder::getBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Type::Interface::Pipeline::getBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Type::Interface::Builder::setBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Type::Interface::Builder::initBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Type::Interface::Builder::adoptBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Interface::Builder::disownBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Reader::which() const { - return _reader.getDataField(4 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Builder::which() { - return _builder.getDataField(4 * ::capnp::ELEMENTS); -} - -inline bool Type::AnyPointer::Reader::isUnconstrained() const { - return which() == Type::AnyPointer::UNCONSTRAINED; -} -inline bool Type::AnyPointer::Builder::isUnconstrained() { - return which() == Type::AnyPointer::UNCONSTRAINED; -} -inline typename Type::AnyPointer::Unconstrained::Reader Type::AnyPointer::Reader::getUnconstrained() const { - KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Unconstrained::Reader(_reader); -} -inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::getUnconstrained() { - KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Unconstrained::Builder(_builder); -} -inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::initUnconstrained() { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Type::AnyPointer::UNCONSTRAINED); - _builder.setDataField< ::uint16_t>(5 * ::capnp::ELEMENTS, 0); - return typename Type::AnyPointer::Unconstrained::Builder(_builder); -} -inline bool Type::AnyPointer::Reader::isParameter() const { - return which() == Type::AnyPointer::PARAMETER; -} -inline bool Type::AnyPointer::Builder::isParameter() { - return which() == Type::AnyPointer::PARAMETER; -} -inline typename Type::AnyPointer::Parameter::Reader Type::AnyPointer::Reader::getParameter() const { - KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Parameter::Reader(_reader); -} -inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::getParameter() { - KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::Parameter::Builder(_builder); -} -inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::initParameter() { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Type::AnyPointer::PARAMETER); - _builder.setDataField< ::uint16_t>(5 * ::capnp::ELEMENTS, 0); - _builder.setDataField< ::uint64_t>(2 * ::capnp::ELEMENTS, 0); - return typename Type::AnyPointer::Parameter::Builder(_builder); -} -inline bool Type::AnyPointer::Reader::isImplicitMethodParameter() const { - return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; -} -inline bool Type::AnyPointer::Builder::isImplicitMethodParameter() { - return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; -} -inline typename Type::AnyPointer::ImplicitMethodParameter::Reader Type::AnyPointer::Reader::getImplicitMethodParameter() const { - KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::ImplicitMethodParameter::Reader(_reader); -} -inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::getImplicitMethodParameter() { - KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), - "Must check which() before get()ing a union member."); - return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); -} -inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::initImplicitMethodParameter() { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Type::AnyPointer::IMPLICIT_METHOD_PARAMETER); - _builder.setDataField< ::uint16_t>(5 * ::capnp::ELEMENTS, 0); - return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); -} -inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Reader::which() const { - return _reader.getDataField(5 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Builder::which() { - return _builder.getDataField(5 * ::capnp::ELEMENTS); -} - -inline bool Type::AnyPointer::Unconstrained::Reader::isAnyKind() const { - return which() == Type::AnyPointer::Unconstrained::ANY_KIND; -} -inline bool Type::AnyPointer::Unconstrained::Builder::isAnyKind() { - return which() == Type::AnyPointer::Unconstrained::ANY_KIND; -} -inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getAnyKind() const { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getAnyKind() { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Unconstrained::Builder::setAnyKind( ::capnp::Void value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::ANY_KIND); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::AnyPointer::Unconstrained::Reader::isStruct() const { - return which() == Type::AnyPointer::Unconstrained::STRUCT; -} -inline bool Type::AnyPointer::Unconstrained::Builder::isStruct() { - return which() == Type::AnyPointer::Unconstrained::STRUCT; -} -inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getStruct() const { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getStruct() { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Unconstrained::Builder::setStruct( ::capnp::Void value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::STRUCT); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::AnyPointer::Unconstrained::Reader::isList() const { - return which() == Type::AnyPointer::Unconstrained::LIST; -} -inline bool Type::AnyPointer::Unconstrained::Builder::isList() { - return which() == Type::AnyPointer::Unconstrained::LIST; -} -inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getList() const { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getList() { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Unconstrained::Builder::setList( ::capnp::Void value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::LIST); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Type::AnyPointer::Unconstrained::Reader::isCapability() const { - return which() == Type::AnyPointer::Unconstrained::CAPABILITY; -} -inline bool Type::AnyPointer::Unconstrained::Builder::isCapability() { - return which() == Type::AnyPointer::Unconstrained::CAPABILITY; -} -inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getCapability() const { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getCapability() { - KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Unconstrained::Builder::setCapability( ::capnp::Void value) { - _builder.setDataField( - 5 * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::CAPABILITY); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::uint64_t Type::AnyPointer::Parameter::Reader::getScopeId() const { - return _reader.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Type::AnyPointer::Parameter::Builder::getScopeId() { - return _builder.getDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Parameter::Builder::setScopeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Type::AnyPointer::Parameter::Reader::getParameterIndex() const { - return _reader.getDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Type::AnyPointer::Parameter::Builder::getParameterIndex() { - return _builder.getDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::Parameter::Builder::setParameterIndex( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS, value); -} - -inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Reader::getParameterIndex() const { - return _reader.getDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Builder::getParameterIndex() { - return _builder.getDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS); -} -inline void Type::AnyPointer::ImplicitMethodParameter::Builder::setParameterIndex( ::uint16_t value) { - _builder.setDataField< ::uint16_t>( - 5 * ::capnp::ELEMENTS, value); -} - -inline bool Brand::Reader::hasScopes() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Brand::Builder::hasScopes() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader Brand::Reader::getScopes() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::getScopes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Brand::Builder::setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::initScopes(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Brand::Builder::adoptScopes( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> Brand::Builder::disownScopes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Reader::which() const { - return _reader.getDataField(4 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Builder::which() { - return _builder.getDataField(4 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Brand::Scope::Reader::getScopeId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Brand::Scope::Builder::getScopeId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Brand::Scope::Builder::setScopeId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Brand::Scope::Reader::isBind() const { - return which() == Brand::Scope::BIND; -} -inline bool Brand::Scope::Builder::isBind() { - return which() == Brand::Scope::BIND; -} -inline bool Brand::Scope::Reader::hasBind() const { - if (which() != Brand::Scope::BIND) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Brand::Scope::Builder::hasBind() { - if (which() != Brand::Scope::BIND) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader Brand::Scope::Reader::getBind() const { - KJ_IREQUIRE((which() == Brand::Scope::BIND), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::getBind() { - KJ_IREQUIRE((which() == Brand::Scope::BIND), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Brand::Scope::Builder::setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value) { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Brand::Scope::BIND); - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::initBind(unsigned int size) { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Brand::Scope::BIND); - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Brand::Scope::Builder::adoptBind( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value) { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Brand::Scope::BIND); - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> Brand::Scope::Builder::disownBind() { - KJ_IREQUIRE((which() == Brand::Scope::BIND), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Brand::Scope::Reader::isInherit() const { - return which() == Brand::Scope::INHERIT; -} -inline bool Brand::Scope::Builder::isInherit() { - return which() == Brand::Scope::INHERIT; -} -inline ::capnp::Void Brand::Scope::Reader::getInherit() const { - KJ_IREQUIRE((which() == Brand::Scope::INHERIT), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Brand::Scope::Builder::getInherit() { - KJ_IREQUIRE((which() == Brand::Scope::INHERIT), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Brand::Scope::Builder::setInherit( ::capnp::Void value) { - _builder.setDataField( - 4 * ::capnp::ELEMENTS, Brand::Scope::INHERIT); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool Brand::Binding::Reader::isUnbound() const { - return which() == Brand::Binding::UNBOUND; -} -inline bool Brand::Binding::Builder::isUnbound() { - return which() == Brand::Binding::UNBOUND; -} -inline ::capnp::Void Brand::Binding::Reader::getUnbound() const { - KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Brand::Binding::Builder::getUnbound() { - KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Brand::Binding::Builder::setUnbound( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Brand::Binding::UNBOUND); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Brand::Binding::Reader::isType() const { - return which() == Brand::Binding::TYPE; -} -inline bool Brand::Binding::Builder::isType() { - return which() == Brand::Binding::TYPE; -} -inline bool Brand::Binding::Reader::hasType() const { - if (which() != Brand::Binding::TYPE) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Brand::Binding::Builder::hasType() { - if (which() != Brand::Binding::TYPE) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Type::Reader Brand::Binding::Reader::getType() const { - KJ_IREQUIRE((which() == Brand::Binding::TYPE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Type::Builder Brand::Binding::Builder::getType() { - KJ_IREQUIRE((which() == Brand::Binding::TYPE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Brand::Binding::Builder::setType( ::capnp::schema::Type::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Brand::Binding::TYPE); - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Type::Builder Brand::Binding::Builder::initType() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Brand::Binding::TYPE); - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Brand::Binding::Builder::adoptType( - ::capnp::Orphan< ::capnp::schema::Type>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Brand::Binding::TYPE); - ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Type> Brand::Binding::Builder::disownType() { - KJ_IREQUIRE((which() == Brand::Binding::TYPE), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline ::capnp::schema::Value::Which Value::Reader::which() const { - return _reader.getDataField(0 * ::capnp::ELEMENTS); -} -inline ::capnp::schema::Value::Which Value::Builder::which() { - return _builder.getDataField(0 * ::capnp::ELEMENTS); -} - -inline bool Value::Reader::isVoid() const { - return which() == Value::VOID; -} -inline bool Value::Builder::isVoid() { - return which() == Value::VOID; -} -inline ::capnp::Void Value::Reader::getVoid() const { - KJ_IREQUIRE((which() == Value::VOID), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Value::Builder::getVoid() { - KJ_IREQUIRE((which() == Value::VOID), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setVoid( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::VOID); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isBool() const { - return which() == Value::BOOL; -} -inline bool Value::Builder::isBool() { - return which() == Value::BOOL; -} -inline bool Value::Reader::getBool() const { - KJ_IREQUIRE((which() == Value::BOOL), - "Must check which() before get()ing a union member."); - return _reader.getDataField( - 16 * ::capnp::ELEMENTS); -} - -inline bool Value::Builder::getBool() { - KJ_IREQUIRE((which() == Value::BOOL), - "Must check which() before get()ing a union member."); - return _builder.getDataField( - 16 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setBool(bool value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::BOOL); - _builder.setDataField( - 16 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isInt8() const { - return which() == Value::INT8; -} -inline bool Value::Builder::isInt8() { - return which() == Value::INT8; -} -inline ::int8_t Value::Reader::getInt8() const { - KJ_IREQUIRE((which() == Value::INT8), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::int8_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::int8_t Value::Builder::getInt8() { - KJ_IREQUIRE((which() == Value::INT8), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::int8_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setInt8( ::int8_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::INT8); - _builder.setDataField< ::int8_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isInt16() const { - return which() == Value::INT16; -} -inline bool Value::Builder::isInt16() { - return which() == Value::INT16; -} -inline ::int16_t Value::Reader::getInt16() const { - KJ_IREQUIRE((which() == Value::INT16), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::int16_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::int16_t Value::Builder::getInt16() { - KJ_IREQUIRE((which() == Value::INT16), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::int16_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setInt16( ::int16_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::INT16); - _builder.setDataField< ::int16_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isInt32() const { - return which() == Value::INT32; -} -inline bool Value::Builder::isInt32() { - return which() == Value::INT32; -} -inline ::int32_t Value::Reader::getInt32() const { - KJ_IREQUIRE((which() == Value::INT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::int32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::int32_t Value::Builder::getInt32() { - KJ_IREQUIRE((which() == Value::INT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::int32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setInt32( ::int32_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::INT32); - _builder.setDataField< ::int32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isInt64() const { - return which() == Value::INT64; -} -inline bool Value::Builder::isInt64() { - return which() == Value::INT64; -} -inline ::int64_t Value::Reader::getInt64() const { - KJ_IREQUIRE((which() == Value::INT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::int64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::int64_t Value::Builder::getInt64() { - KJ_IREQUIRE((which() == Value::INT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::int64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setInt64( ::int64_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::INT64); - _builder.setDataField< ::int64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isUint8() const { - return which() == Value::UINT8; -} -inline bool Value::Builder::isUint8() { - return which() == Value::UINT8; -} -inline ::uint8_t Value::Reader::getUint8() const { - KJ_IREQUIRE((which() == Value::UINT8), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint8_t>( - 2 * ::capnp::ELEMENTS); -} - -inline ::uint8_t Value::Builder::getUint8() { - KJ_IREQUIRE((which() == Value::UINT8), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint8_t>( - 2 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setUint8( ::uint8_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::UINT8); - _builder.setDataField< ::uint8_t>( - 2 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isUint16() const { - return which() == Value::UINT16; -} -inline bool Value::Builder::isUint16() { - return which() == Value::UINT16; -} -inline ::uint16_t Value::Reader::getUint16() const { - KJ_IREQUIRE((which() == Value::UINT16), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Value::Builder::getUint16() { - KJ_IREQUIRE((which() == Value::UINT16), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setUint16( ::uint16_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::UINT16); - _builder.setDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isUint32() const { - return which() == Value::UINT32; -} -inline bool Value::Builder::isUint32() { - return which() == Value::UINT32; -} -inline ::uint32_t Value::Reader::getUint32() const { - KJ_IREQUIRE((which() == Value::UINT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint32_t Value::Builder::getUint32() { - KJ_IREQUIRE((which() == Value::UINT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setUint32( ::uint32_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::UINT32); - _builder.setDataField< ::uint32_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isUint64() const { - return which() == Value::UINT64; -} -inline bool Value::Builder::isUint64() { - return which() == Value::UINT64; -} -inline ::uint64_t Value::Reader::getUint64() const { - KJ_IREQUIRE((which() == Value::UINT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Value::Builder::getUint64() { - KJ_IREQUIRE((which() == Value::UINT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setUint64( ::uint64_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::UINT64); - _builder.setDataField< ::uint64_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isFloat32() const { - return which() == Value::FLOAT32; -} -inline bool Value::Builder::isFloat32() { - return which() == Value::FLOAT32; -} -inline float Value::Reader::getFloat32() const { - KJ_IREQUIRE((which() == Value::FLOAT32), - "Must check which() before get()ing a union member."); - return _reader.getDataField( - 1 * ::capnp::ELEMENTS); -} - -inline float Value::Builder::getFloat32() { - KJ_IREQUIRE((which() == Value::FLOAT32), - "Must check which() before get()ing a union member."); - return _builder.getDataField( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setFloat32(float value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::FLOAT32); - _builder.setDataField( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isFloat64() const { - return which() == Value::FLOAT64; -} -inline bool Value::Builder::isFloat64() { - return which() == Value::FLOAT64; -} -inline double Value::Reader::getFloat64() const { - KJ_IREQUIRE((which() == Value::FLOAT64), - "Must check which() before get()ing a union member."); - return _reader.getDataField( - 1 * ::capnp::ELEMENTS); -} - -inline double Value::Builder::getFloat64() { - KJ_IREQUIRE((which() == Value::FLOAT64), - "Must check which() before get()ing a union member."); - return _builder.getDataField( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setFloat64(double value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::FLOAT64); - _builder.setDataField( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isText() const { - return which() == Value::TEXT; -} -inline bool Value::Builder::isText() { - return which() == Value::TEXT; -} -inline bool Value::Reader::hasText() const { - if (which() != Value::TEXT) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Value::Builder::hasText() { - if (which() != Value::TEXT) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader Value::Reader::getText() const { - KJ_IREQUIRE((which() == Value::TEXT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder Value::Builder::getText() { - KJ_IREQUIRE((which() == Value::TEXT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Value::Builder::setText( ::capnp::Text::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::TEXT); - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder Value::Builder::initText(unsigned int size) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::TEXT); - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Value::Builder::adoptText( - ::capnp::Orphan< ::capnp::Text>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::TEXT); - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> Value::Builder::disownText() { - KJ_IREQUIRE((which() == Value::TEXT), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Value::Reader::isData() const { - return which() == Value::DATA; -} -inline bool Value::Builder::isData() { - return which() == Value::DATA; -} -inline bool Value::Reader::hasData() const { - if (which() != Value::DATA) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Value::Builder::hasData() { - if (which() != Value::DATA) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Data::Reader Value::Reader::getData() const { - KJ_IREQUIRE((which() == Value::DATA), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Data>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Data::Builder Value::Builder::getData() { - KJ_IREQUIRE((which() == Value::DATA), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Data>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Value::Builder::setData( ::capnp::Data::Reader value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::DATA); - ::capnp::_::PointerHelpers< ::capnp::Data>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Data::Builder Value::Builder::initData(unsigned int size) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::DATA); - return ::capnp::_::PointerHelpers< ::capnp::Data>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void Value::Builder::adoptData( - ::capnp::Orphan< ::capnp::Data>&& value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::DATA); - ::capnp::_::PointerHelpers< ::capnp::Data>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Data> Value::Builder::disownData() { - KJ_IREQUIRE((which() == Value::DATA), - "Must check which() before get()ing a union member."); - return ::capnp::_::PointerHelpers< ::capnp::Data>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Value::Reader::isList() const { - return which() == Value::LIST; -} -inline bool Value::Builder::isList() { - return which() == Value::LIST; -} -inline bool Value::Reader::hasList() const { - if (which() != Value::LIST) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Value::Builder::hasList() { - if (which() != Value::LIST) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Value::Reader::getList() const { - KJ_IREQUIRE((which() == Value::LIST), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::getList() { - KJ_IREQUIRE((which() == Value::LIST), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::initList() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::LIST); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Value::Reader::isEnum() const { - return which() == Value::ENUM; -} -inline bool Value::Builder::isEnum() { - return which() == Value::ENUM; -} -inline ::uint16_t Value::Reader::getEnum() const { - KJ_IREQUIRE((which() == Value::ENUM), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} - -inline ::uint16_t Value::Builder::getEnum() { - KJ_IREQUIRE((which() == Value::ENUM), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setEnum( ::uint16_t value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::ENUM); - _builder.setDataField< ::uint16_t>( - 1 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isStruct() const { - return which() == Value::STRUCT; -} -inline bool Value::Builder::isStruct() { - return which() == Value::STRUCT; -} -inline bool Value::Reader::hasStruct() const { - if (which() != Value::STRUCT) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Value::Builder::hasStruct() { - if (which() != Value::STRUCT) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Value::Reader::getStruct() const { - KJ_IREQUIRE((which() == Value::STRUCT), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::getStruct() { - KJ_IREQUIRE((which() == Value::STRUCT), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::initStruct() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::STRUCT); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline bool Value::Reader::isInterface() const { - return which() == Value::INTERFACE; -} -inline bool Value::Builder::isInterface() { - return which() == Value::INTERFACE; -} -inline ::capnp::Void Value::Reader::getInterface() const { - KJ_IREQUIRE((which() == Value::INTERFACE), - "Must check which() before get()ing a union member."); - return _reader.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} - -inline ::capnp::Void Value::Builder::getInterface() { - KJ_IREQUIRE((which() == Value::INTERFACE), - "Must check which() before get()ing a union member."); - return _builder.getDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS); -} -inline void Value::Builder::setInterface( ::capnp::Void value) { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::INTERFACE); - _builder.setDataField< ::capnp::Void>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Value::Reader::isAnyPointer() const { - return which() == Value::ANY_POINTER; -} -inline bool Value::Builder::isAnyPointer() { - return which() == Value::ANY_POINTER; -} -inline bool Value::Reader::hasAnyPointer() const { - if (which() != Value::ANY_POINTER) return false; - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Value::Builder::hasAnyPointer() { - if (which() != Value::ANY_POINTER) return false; - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::AnyPointer::Reader Value::Reader::getAnyPointer() const { - KJ_IREQUIRE((which() == Value::ANY_POINTER), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Reader( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::getAnyPointer() { - KJ_IREQUIRE((which() == Value::ANY_POINTER), - "Must check which() before get()ing a union member."); - return ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::AnyPointer::Builder Value::Builder::initAnyPointer() { - _builder.setDataField( - 0 * ::capnp::ELEMENTS, Value::ANY_POINTER); - auto result = ::capnp::AnyPointer::Builder( - _builder.getPointerField(0 * ::capnp::POINTERS)); - result.clear(); - return result; -} - -inline ::uint64_t Annotation::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t Annotation::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void Annotation::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool Annotation::Reader::hasValue() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool Annotation::Builder::hasValue() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Value::Reader Annotation::Reader::getValue() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Value::Builder Annotation::Builder::getValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Value::Pipeline Annotation::Pipeline::getValue() { - return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(0)); -} -#endif // !CAPNP_LITE -inline void Annotation::Builder::setValue( ::capnp::schema::Value::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Value::Builder Annotation::Builder::initValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void Annotation::Builder::adoptValue( - ::capnp::Orphan< ::capnp::schema::Value>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Value> Annotation::Builder::disownValue() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool Annotation::Reader::hasBrand() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool Annotation::Builder::hasBrand() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::schema::Brand::Reader Annotation::Reader::getBrand() const { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::schema::Brand::Builder Annotation::Builder::getBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -#if !CAPNP_LITE -inline ::capnp::schema::Brand::Pipeline Annotation::Pipeline::getBrand() { - return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(1)); -} -#endif // !CAPNP_LITE -inline void Annotation::Builder::setBrand( ::capnp::schema::Brand::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::schema::Brand::Builder Annotation::Builder::initBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void Annotation::Builder::adoptBrand( - ::capnp::Orphan< ::capnp::schema::Brand>&& value) { - ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::schema::Brand> Annotation::Builder::disownBrand() { - return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline bool CodeGeneratorRequest::Reader::hasNodes() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool CodeGeneratorRequest::Builder::hasNodes() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::Node>::Reader CodeGeneratorRequest::Reader::getNodes() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::getNodes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CodeGeneratorRequest::Builder::setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::initNodes(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void CodeGeneratorRequest::Builder::adoptNodes( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> CodeGeneratorRequest::Builder::disownNodes() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool CodeGeneratorRequest::Reader::hasRequestedFiles() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool CodeGeneratorRequest::Builder::hasRequestedFiles() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader CodeGeneratorRequest::Reader::getRequestedFiles() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::getRequestedFiles() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void CodeGeneratorRequest::Builder::setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::initRequestedFiles(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void CodeGeneratorRequest::Builder::adoptRequestedFiles( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> CodeGeneratorRequest::Builder::disownRequestedFiles() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline ::uint64_t CodeGeneratorRequest::RequestedFile::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t CodeGeneratorRequest::RequestedFile::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void CodeGeneratorRequest::RequestedFile::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool CodeGeneratorRequest::RequestedFile::Reader::hasFilename() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool CodeGeneratorRequest::RequestedFile::Builder::hasFilename() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Reader::getFilename() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::getFilename() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CodeGeneratorRequest::RequestedFile::Builder::setFilename( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::initFilename(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void CodeGeneratorRequest::RequestedFile::Builder::adoptFilename( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Builder::disownFilename() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -inline bool CodeGeneratorRequest::RequestedFile::Reader::hasImports() const { - return !_reader.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline bool CodeGeneratorRequest::RequestedFile::Builder::hasImports() { - return !_builder.getPointerField(1 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader CodeGeneratorRequest::RequestedFile::Reader::getImports() const { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get( - _reader.getPointerField(1 * ::capnp::POINTERS)); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::getImports() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} -inline void CodeGeneratorRequest::RequestedFile::Builder::setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::set( - _builder.getPointerField(1 * ::capnp::POINTERS), value); -} -inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::initImports(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::init( - _builder.getPointerField(1 * ::capnp::POINTERS), size); -} -inline void CodeGeneratorRequest::RequestedFile::Builder::adoptImports( - ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value) { - ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::adopt( - _builder.getPointerField(1 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> CodeGeneratorRequest::RequestedFile::Builder::disownImports() { - return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::disown( - _builder.getPointerField(1 * ::capnp::POINTERS)); -} - -inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Reader::getId() const { - return _reader.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} - -inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Builder::getId() { - return _builder.getDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS); -} -inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setId( ::uint64_t value) { - _builder.setDataField< ::uint64_t>( - 0 * ::capnp::ELEMENTS, value); -} - -inline bool CodeGeneratorRequest::RequestedFile::Import::Reader::hasName() const { - return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline bool CodeGeneratorRequest::RequestedFile::Import::Builder::hasName() { - return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull(); -} -inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Import::Reader::getName() const { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _reader.getPointerField(0 * ::capnp::POINTERS)); -} -inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::getName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::get( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} -inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setName( ::capnp::Text::Reader value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::set( - _builder.getPointerField(0 * ::capnp::POINTERS), value); -} -inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::initName(unsigned int size) { - return ::capnp::_::PointerHelpers< ::capnp::Text>::init( - _builder.getPointerField(0 * ::capnp::POINTERS), size); -} -inline void CodeGeneratorRequest::RequestedFile::Import::Builder::adoptName( - ::capnp::Orphan< ::capnp::Text>&& value) { - ::capnp::_::PointerHelpers< ::capnp::Text>::adopt( - _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value)); -} -inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Import::Builder::disownName() { - return ::capnp::_::PointerHelpers< ::capnp::Text>::disown( - _builder.getPointerField(0 * ::capnp::POINTERS)); -} - -} // namespace -} // namespace - -#endif // CAPNP_INCLUDED_a93fc509624c72d9_ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: schema.capnp + +#ifndef CAPNP_INCLUDED_a93fc509624c72d9_ +#define CAPNP_INCLUDED_a93fc509624c72d9_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(e682ab4cf923a417); +CAPNP_DECLARE_SCHEMA(b9521bccf10fa3b1); +CAPNP_DECLARE_SCHEMA(debf55bbfa0fc242); +CAPNP_DECLARE_SCHEMA(9ea0b19b37fb4435); +CAPNP_DECLARE_SCHEMA(b54ab3364333f598); +CAPNP_DECLARE_SCHEMA(e82753cff0c2218f); +CAPNP_DECLARE_SCHEMA(b18aa5ac7a0d9420); +CAPNP_DECLARE_SCHEMA(ec1619d4400a0290); +CAPNP_DECLARE_SCHEMA(9aad50a41f4af45f); +CAPNP_DECLARE_SCHEMA(97b14cbe7cfec712); +CAPNP_DECLARE_SCHEMA(c42305476bb4746f); +CAPNP_DECLARE_SCHEMA(cafccddb68db1d11); +CAPNP_DECLARE_SCHEMA(bb90d5c287870be6); +CAPNP_DECLARE_SCHEMA(978a7cebdc549a4d); +CAPNP_DECLARE_SCHEMA(a9962a9ed0a4d7f8); +CAPNP_DECLARE_SCHEMA(9500cce23b334d80); +CAPNP_DECLARE_SCHEMA(d07378ede1f9cc60); +CAPNP_DECLARE_SCHEMA(87e739250a60ea97); +CAPNP_DECLARE_SCHEMA(9e0e78711a7f87a9); +CAPNP_DECLARE_SCHEMA(ac3a6f60ef4cc6d3); +CAPNP_DECLARE_SCHEMA(ed8bca69f7fb0cbf); +CAPNP_DECLARE_SCHEMA(c2573fe8a23e49f1); +CAPNP_DECLARE_SCHEMA(8e3b5f79fe593656); +CAPNP_DECLARE_SCHEMA(9dd1f724f4614a85); +CAPNP_DECLARE_SCHEMA(baefc9120c56e274); +CAPNP_DECLARE_SCHEMA(903455f06065422b); +CAPNP_DECLARE_SCHEMA(abd73485a9636bc9); +CAPNP_DECLARE_SCHEMA(c863cd16969ee7fc); +CAPNP_DECLARE_SCHEMA(ce23dcd2d7b00c9b); +CAPNP_DECLARE_SCHEMA(f1c8950dab257542); +CAPNP_DECLARE_SCHEMA(d1958f7dba521926); +enum class ElementSize_d1958f7dba521926: uint16_t { + EMPTY, + BIT, + BYTE, + TWO_BYTES, + FOUR_BYTES, + EIGHT_BYTES, + POINTER, + INLINE_COMPOSITE, +}; +CAPNP_DECLARE_ENUM(ElementSize, d1958f7dba521926); +CAPNP_DECLARE_SCHEMA(d85d305b7d839963); +CAPNP_DECLARE_SCHEMA(bfc546f6210ad7ce); +CAPNP_DECLARE_SCHEMA(cfea0eb02e810062); +CAPNP_DECLARE_SCHEMA(ae504193122357e5); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace schema { + +struct Node { + Node() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + FILE, + STRUCT, + ENUM, + INTERFACE, + CONST, + ANNOTATION, + }; + struct Parameter; + struct NestedNode; + struct Struct; + struct Enum; + struct Interface; + struct Const; + struct Annotation; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e682ab4cf923a417, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Parameter { + Parameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b9521bccf10fa3b1, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::NestedNode { + NestedNode() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(debf55bbfa0fc242, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Struct { + Struct() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9ea0b19b37fb4435, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Enum { + Enum() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b54ab3364333f598, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Interface { + Interface() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e82753cff0c2218f, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Const { + Const() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b18aa5ac7a0d9420, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Annotation { + Annotation() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ec1619d4400a0290, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field { + Field() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + SLOT, + GROUP, + }; + static constexpr ::uint16_t NO_DISCRIMINANT = 65535u; + struct Slot; + struct Group; + struct Ordinal; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9aad50a41f4af45f, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Slot { + Slot() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c42305476bb4746f, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Group { + Group() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(cafccddb68db1d11, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Ordinal { + Ordinal() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + IMPLICIT, + EXPLICIT, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bb90d5c287870be6, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Enumerant { + Enumerant() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(978a7cebdc549a4d, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Superclass { + Superclass() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(a9962a9ed0a4d7f8, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Method { + Method() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9500cce23b334d80, 3, 5) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type { + Type() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + VOID, + BOOL, + INT8, + INT16, + INT32, + INT64, + UINT8, + UINT16, + UINT32, + UINT64, + FLOAT32, + FLOAT64, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + INTERFACE, + ANY_POINTER, + }; + struct List; + struct Enum; + struct Struct; + struct Interface; + struct AnyPointer; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d07378ede1f9cc60, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::List { + List() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(87e739250a60ea97, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Enum { + Enum() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9e0e78711a7f87a9, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Struct { + Struct() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ac3a6f60ef4cc6d3, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Interface { + Interface() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ed8bca69f7fb0cbf, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer { + AnyPointer() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNCONSTRAINED, + PARAMETER, + IMPLICIT_METHOD_PARAMETER, + }; + struct Unconstrained; + struct Parameter; + struct ImplicitMethodParameter; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c2573fe8a23e49f1, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::Unconstrained { + Unconstrained() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + ANY_KIND, + STRUCT, + LIST, + CAPABILITY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8e3b5f79fe593656, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::Parameter { + Parameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9dd1f724f4614a85, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::ImplicitMethodParameter { + ImplicitMethodParameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(baefc9120c56e274, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand { + Brand() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Scope; + struct Binding; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(903455f06065422b, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand::Scope { + Scope() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + BIND, + INHERIT, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(abd73485a9636bc9, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand::Binding { + Binding() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNBOUND, + TYPE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c863cd16969ee7fc, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Value { + Value() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + VOID, + BOOL, + INT8, + INT16, + INT32, + INT64, + UINT8, + UINT16, + UINT32, + UINT64, + FLOAT32, + FLOAT64, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + INTERFACE, + ANY_POINTER, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ce23dcd2d7b00c9b, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Annotation { + Annotation() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f1c8950dab257542, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +typedef ::capnp::schemas::ElementSize_d1958f7dba521926 ElementSize; + +struct CapnpVersion { + CapnpVersion() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d85d305b7d839963, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest { + CodeGeneratorRequest() = delete; + + class Reader; + class Builder; + class Pipeline; + struct RequestedFile; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bfc546f6210ad7ce, 0, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest::RequestedFile { + RequestedFile() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Import; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(cfea0eb02e810062, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest::RequestedFile::Import { + Import() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ae504193122357e5, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class Node::Reader { +public: + typedef Node Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint64_t getId() const; + + inline bool hasDisplayName() const; + inline ::capnp::Text::Reader getDisplayName() const; + + inline ::uint32_t getDisplayNamePrefixLength() const; + + inline ::uint64_t getScopeId() const; + + inline bool hasNestedNodes() const; + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader getNestedNodes() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline bool isFile() const; + inline ::capnp::Void getFile() const; + + inline bool isStruct() const; + inline typename Struct::Reader getStruct() const; + + inline bool isEnum() const; + inline typename Enum::Reader getEnum() const; + + inline bool isInterface() const; + inline typename Interface::Reader getInterface() const; + + inline bool isConst() const; + inline typename Const::Reader getConst() const; + + inline bool isAnnotation() const; + inline typename Annotation::Reader getAnnotation() const; + + inline bool hasParameters() const; + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getParameters() const; + + inline bool getIsGeneric() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Builder { +public: + typedef Node Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasDisplayName(); + inline ::capnp::Text::Builder getDisplayName(); + inline void setDisplayName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initDisplayName(unsigned int size); + inline void adoptDisplayName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownDisplayName(); + + inline ::uint32_t getDisplayNamePrefixLength(); + inline void setDisplayNamePrefixLength( ::uint32_t value); + + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline bool hasNestedNodes(); + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder getNestedNodes(); + inline void setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder initNestedNodes(unsigned int size); + inline void adoptNestedNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> disownNestedNodes(); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline bool isFile(); + inline ::capnp::Void getFile(); + inline void setFile( ::capnp::Void value = ::capnp::VOID); + + inline bool isStruct(); + inline typename Struct::Builder getStruct(); + inline typename Struct::Builder initStruct(); + + inline bool isEnum(); + inline typename Enum::Builder getEnum(); + inline typename Enum::Builder initEnum(); + + inline bool isInterface(); + inline typename Interface::Builder getInterface(); + inline typename Interface::Builder initInterface(); + + inline bool isConst(); + inline typename Const::Builder getConst(); + inline typename Const::Builder initConst(); + + inline bool isAnnotation(); + inline typename Annotation::Builder getAnnotation(); + inline typename Annotation::Builder initAnnotation(); + + inline bool hasParameters(); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getParameters(); + inline void setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initParameters(unsigned int size); + inline void adoptParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownParameters(); + + inline bool getIsGeneric(); + inline void setIsGeneric(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Pipeline { +public: + typedef Node Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Parameter::Reader { +public: + typedef Parameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Parameter::Builder { +public: + typedef Parameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Parameter::Pipeline { +public: + typedef Parameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::NestedNode::Reader { +public: + typedef NestedNode Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint64_t getId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::NestedNode::Builder { +public: + typedef NestedNode Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::NestedNode::Pipeline { +public: + typedef NestedNode Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Struct::Reader { +public: + typedef Struct Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getDataWordCount() const; + + inline ::uint16_t getPointerCount() const; + + inline ::capnp::schema::ElementSize getPreferredListEncoding() const; + + inline bool getIsGroup() const; + + inline ::uint16_t getDiscriminantCount() const; + + inline ::uint32_t getDiscriminantOffset() const; + + inline bool hasFields() const; + inline ::capnp::List< ::capnp::schema::Field>::Reader getFields() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Struct::Builder { +public: + typedef Struct Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getDataWordCount(); + inline void setDataWordCount( ::uint16_t value); + + inline ::uint16_t getPointerCount(); + inline void setPointerCount( ::uint16_t value); + + inline ::capnp::schema::ElementSize getPreferredListEncoding(); + inline void setPreferredListEncoding( ::capnp::schema::ElementSize value); + + inline bool getIsGroup(); + inline void setIsGroup(bool value); + + inline ::uint16_t getDiscriminantCount(); + inline void setDiscriminantCount( ::uint16_t value); + + inline ::uint32_t getDiscriminantOffset(); + inline void setDiscriminantOffset( ::uint32_t value); + + inline bool hasFields(); + inline ::capnp::List< ::capnp::schema::Field>::Builder getFields(); + inline void setFields( ::capnp::List< ::capnp::schema::Field>::Reader value); + inline ::capnp::List< ::capnp::schema::Field>::Builder initFields(unsigned int size); + inline void adoptFields(::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> disownFields(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Struct::Pipeline { +public: + typedef Struct Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Enum::Reader { +public: + typedef Enum Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasEnumerants() const; + inline ::capnp::List< ::capnp::schema::Enumerant>::Reader getEnumerants() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Enum::Builder { +public: + typedef Enum Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasEnumerants(); + inline ::capnp::List< ::capnp::schema::Enumerant>::Builder getEnumerants(); + inline void setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value); + inline ::capnp::List< ::capnp::schema::Enumerant>::Builder initEnumerants(unsigned int size); + inline void adoptEnumerants(::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> disownEnumerants(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Enum::Pipeline { +public: + typedef Enum Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Interface::Reader { +public: + typedef Interface Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasMethods() const; + inline ::capnp::List< ::capnp::schema::Method>::Reader getMethods() const; + + inline bool hasSuperclasses() const; + inline ::capnp::List< ::capnp::schema::Superclass>::Reader getSuperclasses() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Interface::Builder { +public: + typedef Interface Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasMethods(); + inline ::capnp::List< ::capnp::schema::Method>::Builder getMethods(); + inline void setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value); + inline ::capnp::List< ::capnp::schema::Method>::Builder initMethods(unsigned int size); + inline void adoptMethods(::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> disownMethods(); + + inline bool hasSuperclasses(); + inline ::capnp::List< ::capnp::schema::Superclass>::Builder getSuperclasses(); + inline void setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value); + inline ::capnp::List< ::capnp::schema::Superclass>::Builder initSuperclasses(unsigned int size); + inline void adoptSuperclasses(::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> disownSuperclasses(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Interface::Pipeline { +public: + typedef Interface Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Const::Reader { +public: + typedef Const Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool hasValue() const; + inline ::capnp::schema::Value::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Const::Builder { +public: + typedef Const Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool hasValue(); + inline ::capnp::schema::Value::Builder getValue(); + inline void setValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Const::Pipeline { +public: + typedef Const Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); + inline ::capnp::schema::Value::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Annotation::Reader { +public: + typedef Annotation Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool getTargetsFile() const; + + inline bool getTargetsConst() const; + + inline bool getTargetsEnum() const; + + inline bool getTargetsEnumerant() const; + + inline bool getTargetsStruct() const; + + inline bool getTargetsField() const; + + inline bool getTargetsUnion() const; + + inline bool getTargetsGroup() const; + + inline bool getTargetsInterface() const; + + inline bool getTargetsMethod() const; + + inline bool getTargetsParam() const; + + inline bool getTargetsAnnotation() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Annotation::Builder { +public: + typedef Annotation Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool getTargetsFile(); + inline void setTargetsFile(bool value); + + inline bool getTargetsConst(); + inline void setTargetsConst(bool value); + + inline bool getTargetsEnum(); + inline void setTargetsEnum(bool value); + + inline bool getTargetsEnumerant(); + inline void setTargetsEnumerant(bool value); + + inline bool getTargetsStruct(); + inline void setTargetsStruct(bool value); + + inline bool getTargetsField(); + inline void setTargetsField(bool value); + + inline bool getTargetsUnion(); + inline void setTargetsUnion(bool value); + + inline bool getTargetsGroup(); + inline void setTargetsGroup(bool value); + + inline bool getTargetsInterface(); + inline void setTargetsInterface(bool value); + + inline bool getTargetsMethod(); + inline void setTargetsMethod(bool value); + + inline bool getTargetsParam(); + inline void setTargetsParam(bool value); + + inline bool getTargetsAnnotation(); + inline void setTargetsAnnotation(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Annotation::Pipeline { +public: + typedef Annotation Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Reader { +public: + typedef Field Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline ::uint16_t getDiscriminantValue() const; + + inline bool isSlot() const; + inline typename Slot::Reader getSlot() const; + + inline bool isGroup() const; + inline typename Group::Reader getGroup() const; + + inline typename Ordinal::Reader getOrdinal() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Builder { +public: + typedef Field Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline ::uint16_t getDiscriminantValue(); + inline void setDiscriminantValue( ::uint16_t value); + + inline bool isSlot(); + inline typename Slot::Builder getSlot(); + inline typename Slot::Builder initSlot(); + + inline bool isGroup(); + inline typename Group::Builder getGroup(); + inline typename Group::Builder initGroup(); + + inline typename Ordinal::Builder getOrdinal(); + inline typename Ordinal::Builder initOrdinal(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Pipeline { +public: + typedef Field Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename Ordinal::Pipeline getOrdinal(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Slot::Reader { +public: + typedef Slot Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getOffset() const; + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool hasDefaultValue() const; + inline ::capnp::schema::Value::Reader getDefaultValue() const; + + inline bool getHadExplicitDefault() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Slot::Builder { +public: + typedef Slot Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getOffset(); + inline void setOffset( ::uint32_t value); + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool hasDefaultValue(); + inline ::capnp::schema::Value::Builder getDefaultValue(); + inline void setDefaultValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initDefaultValue(); + inline void adoptDefaultValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownDefaultValue(); + + inline bool getHadExplicitDefault(); + inline void setHadExplicitDefault(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Slot::Pipeline { +public: + typedef Slot Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); + inline ::capnp::schema::Value::Pipeline getDefaultValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Group::Reader { +public: + typedef Group Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Group::Builder { +public: + typedef Group Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Group::Pipeline { +public: + typedef Group Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Ordinal::Reader { +public: + typedef Ordinal Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isImplicit() const; + inline ::capnp::Void getImplicit() const; + + inline bool isExplicit() const; + inline ::uint16_t getExplicit() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Ordinal::Builder { +public: + typedef Ordinal Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isImplicit(); + inline ::capnp::Void getImplicit(); + inline void setImplicit( ::capnp::Void value = ::capnp::VOID); + + inline bool isExplicit(); + inline ::uint16_t getExplicit(); + inline void setExplicit( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Ordinal::Pipeline { +public: + typedef Ordinal Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Enumerant::Reader { +public: + typedef Enumerant Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Enumerant::Builder { +public: + typedef Enumerant Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Enumerant::Pipeline { +public: + typedef Enumerant Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Superclass::Reader { +public: + typedef Superclass Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Superclass::Builder { +public: + typedef Superclass Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Superclass::Pipeline { +public: + typedef Superclass Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Method::Reader { +public: + typedef Method Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline ::uint64_t getParamStructType() const; + + inline ::uint64_t getResultStructType() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline bool hasParamBrand() const; + inline ::capnp::schema::Brand::Reader getParamBrand() const; + + inline bool hasResultBrand() const; + inline ::capnp::schema::Brand::Reader getResultBrand() const; + + inline bool hasImplicitParameters() const; + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getImplicitParameters() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Method::Builder { +public: + typedef Method Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline ::uint64_t getParamStructType(); + inline void setParamStructType( ::uint64_t value); + + inline ::uint64_t getResultStructType(); + inline void setResultStructType( ::uint64_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline bool hasParamBrand(); + inline ::capnp::schema::Brand::Builder getParamBrand(); + inline void setParamBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initParamBrand(); + inline void adoptParamBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownParamBrand(); + + inline bool hasResultBrand(); + inline ::capnp::schema::Brand::Builder getResultBrand(); + inline void setResultBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initResultBrand(); + inline void adoptResultBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownResultBrand(); + + inline bool hasImplicitParameters(); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getImplicitParameters(); + inline void setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initImplicitParameters(unsigned int size); + inline void adoptImplicitParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownImplicitParameters(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Method::Pipeline { +public: + typedef Method Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getParamBrand(); + inline ::capnp::schema::Brand::Pipeline getResultBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Reader { +public: + typedef Type Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isVoid() const; + inline ::capnp::Void getVoid() const; + + inline bool isBool() const; + inline ::capnp::Void getBool() const; + + inline bool isInt8() const; + inline ::capnp::Void getInt8() const; + + inline bool isInt16() const; + inline ::capnp::Void getInt16() const; + + inline bool isInt32() const; + inline ::capnp::Void getInt32() const; + + inline bool isInt64() const; + inline ::capnp::Void getInt64() const; + + inline bool isUint8() const; + inline ::capnp::Void getUint8() const; + + inline bool isUint16() const; + inline ::capnp::Void getUint16() const; + + inline bool isUint32() const; + inline ::capnp::Void getUint32() const; + + inline bool isUint64() const; + inline ::capnp::Void getUint64() const; + + inline bool isFloat32() const; + inline ::capnp::Void getFloat32() const; + + inline bool isFloat64() const; + inline ::capnp::Void getFloat64() const; + + inline bool isText() const; + inline ::capnp::Void getText() const; + + inline bool isData() const; + inline ::capnp::Void getData() const; + + inline bool isList() const; + inline typename List::Reader getList() const; + + inline bool isEnum() const; + inline typename Enum::Reader getEnum() const; + + inline bool isStruct() const; + inline typename Struct::Reader getStruct() const; + + inline bool isInterface() const; + inline typename Interface::Reader getInterface() const; + + inline bool isAnyPointer() const; + inline typename AnyPointer::Reader getAnyPointer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Builder { +public: + typedef Type Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isVoid(); + inline ::capnp::Void getVoid(); + inline void setVoid( ::capnp::Void value = ::capnp::VOID); + + inline bool isBool(); + inline ::capnp::Void getBool(); + inline void setBool( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt8(); + inline ::capnp::Void getInt8(); + inline void setInt8( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt16(); + inline ::capnp::Void getInt16(); + inline void setInt16( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt32(); + inline ::capnp::Void getInt32(); + inline void setInt32( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt64(); + inline ::capnp::Void getInt64(); + inline void setInt64( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint8(); + inline ::capnp::Void getUint8(); + inline void setUint8( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint16(); + inline ::capnp::Void getUint16(); + inline void setUint16( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint32(); + inline ::capnp::Void getUint32(); + inline void setUint32( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint64(); + inline ::capnp::Void getUint64(); + inline void setUint64( ::capnp::Void value = ::capnp::VOID); + + inline bool isFloat32(); + inline ::capnp::Void getFloat32(); + inline void setFloat32( ::capnp::Void value = ::capnp::VOID); + + inline bool isFloat64(); + inline ::capnp::Void getFloat64(); + inline void setFloat64( ::capnp::Void value = ::capnp::VOID); + + inline bool isText(); + inline ::capnp::Void getText(); + inline void setText( ::capnp::Void value = ::capnp::VOID); + + inline bool isData(); + inline ::capnp::Void getData(); + inline void setData( ::capnp::Void value = ::capnp::VOID); + + inline bool isList(); + inline typename List::Builder getList(); + inline typename List::Builder initList(); + + inline bool isEnum(); + inline typename Enum::Builder getEnum(); + inline typename Enum::Builder initEnum(); + + inline bool isStruct(); + inline typename Struct::Builder getStruct(); + inline typename Struct::Builder initStruct(); + + inline bool isInterface(); + inline typename Interface::Builder getInterface(); + inline typename Interface::Builder initInterface(); + + inline bool isAnyPointer(); + inline typename AnyPointer::Builder getAnyPointer(); + inline typename AnyPointer::Builder initAnyPointer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Pipeline { +public: + typedef Type Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::List::Reader { +public: + typedef List Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasElementType() const; + inline ::capnp::schema::Type::Reader getElementType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::List::Builder { +public: + typedef List Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasElementType(); + inline ::capnp::schema::Type::Builder getElementType(); + inline void setElementType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initElementType(); + inline void adoptElementType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownElementType(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::List::Pipeline { +public: + typedef List Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getElementType(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Enum::Reader { +public: + typedef Enum Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Enum::Builder { +public: + typedef Enum Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Enum::Pipeline { +public: + typedef Enum Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Struct::Reader { +public: + typedef Struct Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Struct::Builder { +public: + typedef Struct Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Struct::Pipeline { +public: + typedef Struct Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Interface::Reader { +public: + typedef Interface Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Interface::Builder { +public: + typedef Interface Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Interface::Pipeline { +public: + typedef Interface Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Reader { +public: + typedef AnyPointer Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnconstrained() const; + inline typename Unconstrained::Reader getUnconstrained() const; + + inline bool isParameter() const; + inline typename Parameter::Reader getParameter() const; + + inline bool isImplicitMethodParameter() const; + inline typename ImplicitMethodParameter::Reader getImplicitMethodParameter() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Builder { +public: + typedef AnyPointer Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnconstrained(); + inline typename Unconstrained::Builder getUnconstrained(); + inline typename Unconstrained::Builder initUnconstrained(); + + inline bool isParameter(); + inline typename Parameter::Builder getParameter(); + inline typename Parameter::Builder initParameter(); + + inline bool isImplicitMethodParameter(); + inline typename ImplicitMethodParameter::Builder getImplicitMethodParameter(); + inline typename ImplicitMethodParameter::Builder initImplicitMethodParameter(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Pipeline { +public: + typedef AnyPointer Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Unconstrained::Reader { +public: + typedef Unconstrained Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isAnyKind() const; + inline ::capnp::Void getAnyKind() const; + + inline bool isStruct() const; + inline ::capnp::Void getStruct() const; + + inline bool isList() const; + inline ::capnp::Void getList() const; + + inline bool isCapability() const; + inline ::capnp::Void getCapability() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Unconstrained::Builder { +public: + typedef Unconstrained Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isAnyKind(); + inline ::capnp::Void getAnyKind(); + inline void setAnyKind( ::capnp::Void value = ::capnp::VOID); + + inline bool isStruct(); + inline ::capnp::Void getStruct(); + inline void setStruct( ::capnp::Void value = ::capnp::VOID); + + inline bool isList(); + inline ::capnp::Void getList(); + inline void setList( ::capnp::Void value = ::capnp::VOID); + + inline bool isCapability(); + inline ::capnp::Void getCapability(); + inline void setCapability( ::capnp::Void value = ::capnp::VOID); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Unconstrained::Pipeline { +public: + typedef Unconstrained Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Parameter::Reader { +public: + typedef Parameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getScopeId() const; + + inline ::uint16_t getParameterIndex() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Parameter::Builder { +public: + typedef Parameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline ::uint16_t getParameterIndex(); + inline void setParameterIndex( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Parameter::Pipeline { +public: + typedef Parameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::ImplicitMethodParameter::Reader { +public: + typedef ImplicitMethodParameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getParameterIndex() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::ImplicitMethodParameter::Builder { +public: + typedef ImplicitMethodParameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getParameterIndex(); + inline void setParameterIndex( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::ImplicitMethodParameter::Pipeline { +public: + typedef ImplicitMethodParameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Reader { +public: + typedef Brand Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasScopes() const; + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader getScopes() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Builder { +public: + typedef Brand Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasScopes(); + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder getScopes(); + inline void setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value); + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder initScopes(unsigned int size); + inline void adoptScopes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> disownScopes(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Pipeline { +public: + typedef Brand Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Scope::Reader { +public: + typedef Scope Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint64_t getScopeId() const; + + inline bool isBind() const; + inline bool hasBind() const; + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader getBind() const; + + inline bool isInherit() const; + inline ::capnp::Void getInherit() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Scope::Builder { +public: + typedef Scope Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline bool isBind(); + inline bool hasBind(); + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder getBind(); + inline void setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value); + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder initBind(unsigned int size); + inline void adoptBind(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> disownBind(); + + inline bool isInherit(); + inline ::capnp::Void getInherit(); + inline void setInherit( ::capnp::Void value = ::capnp::VOID); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Scope::Pipeline { +public: + typedef Scope Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Binding::Reader { +public: + typedef Binding Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnbound() const; + inline ::capnp::Void getUnbound() const; + + inline bool isType() const; + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Binding::Builder { +public: + typedef Binding Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnbound(); + inline ::capnp::Void getUnbound(); + inline void setUnbound( ::capnp::Void value = ::capnp::VOID); + + inline bool isType(); + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Binding::Pipeline { +public: + typedef Binding Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Value::Reader { +public: + typedef Value Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isVoid() const; + inline ::capnp::Void getVoid() const; + + inline bool isBool() const; + inline bool getBool() const; + + inline bool isInt8() const; + inline ::int8_t getInt8() const; + + inline bool isInt16() const; + inline ::int16_t getInt16() const; + + inline bool isInt32() const; + inline ::int32_t getInt32() const; + + inline bool isInt64() const; + inline ::int64_t getInt64() const; + + inline bool isUint8() const; + inline ::uint8_t getUint8() const; + + inline bool isUint16() const; + inline ::uint16_t getUint16() const; + + inline bool isUint32() const; + inline ::uint32_t getUint32() const; + + inline bool isUint64() const; + inline ::uint64_t getUint64() const; + + inline bool isFloat32() const; + inline float getFloat32() const; + + inline bool isFloat64() const; + inline double getFloat64() const; + + inline bool isText() const; + inline bool hasText() const; + inline ::capnp::Text::Reader getText() const; + + inline bool isData() const; + inline bool hasData() const; + inline ::capnp::Data::Reader getData() const; + + inline bool isList() const; + inline bool hasList() const; + inline ::capnp::AnyPointer::Reader getList() const; + + inline bool isEnum() const; + inline ::uint16_t getEnum() const; + + inline bool isStruct() const; + inline bool hasStruct() const; + inline ::capnp::AnyPointer::Reader getStruct() const; + + inline bool isInterface() const; + inline ::capnp::Void getInterface() const; + + inline bool isAnyPointer() const; + inline bool hasAnyPointer() const; + inline ::capnp::AnyPointer::Reader getAnyPointer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Value::Builder { +public: + typedef Value Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isVoid(); + inline ::capnp::Void getVoid(); + inline void setVoid( ::capnp::Void value = ::capnp::VOID); + + inline bool isBool(); + inline bool getBool(); + inline void setBool(bool value); + + inline bool isInt8(); + inline ::int8_t getInt8(); + inline void setInt8( ::int8_t value); + + inline bool isInt16(); + inline ::int16_t getInt16(); + inline void setInt16( ::int16_t value); + + inline bool isInt32(); + inline ::int32_t getInt32(); + inline void setInt32( ::int32_t value); + + inline bool isInt64(); + inline ::int64_t getInt64(); + inline void setInt64( ::int64_t value); + + inline bool isUint8(); + inline ::uint8_t getUint8(); + inline void setUint8( ::uint8_t value); + + inline bool isUint16(); + inline ::uint16_t getUint16(); + inline void setUint16( ::uint16_t value); + + inline bool isUint32(); + inline ::uint32_t getUint32(); + inline void setUint32( ::uint32_t value); + + inline bool isUint64(); + inline ::uint64_t getUint64(); + inline void setUint64( ::uint64_t value); + + inline bool isFloat32(); + inline float getFloat32(); + inline void setFloat32(float value); + + inline bool isFloat64(); + inline double getFloat64(); + inline void setFloat64(double value); + + inline bool isText(); + inline bool hasText(); + inline ::capnp::Text::Builder getText(); + inline void setText( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initText(unsigned int size); + inline void adoptText(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownText(); + + inline bool isData(); + inline bool hasData(); + inline ::capnp::Data::Builder getData(); + inline void setData( ::capnp::Data::Reader value); + inline ::capnp::Data::Builder initData(unsigned int size); + inline void adoptData(::capnp::Orphan< ::capnp::Data>&& value); + inline ::capnp::Orphan< ::capnp::Data> disownData(); + + inline bool isList(); + inline bool hasList(); + inline ::capnp::AnyPointer::Builder getList(); + inline ::capnp::AnyPointer::Builder initList(); + + inline bool isEnum(); + inline ::uint16_t getEnum(); + inline void setEnum( ::uint16_t value); + + inline bool isStruct(); + inline bool hasStruct(); + inline ::capnp::AnyPointer::Builder getStruct(); + inline ::capnp::AnyPointer::Builder initStruct(); + + inline bool isInterface(); + inline ::capnp::Void getInterface(); + inline void setInterface( ::capnp::Void value = ::capnp::VOID); + + inline bool isAnyPointer(); + inline bool hasAnyPointer(); + inline ::capnp::AnyPointer::Builder getAnyPointer(); + inline ::capnp::AnyPointer::Builder initAnyPointer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Value::Pipeline { +public: + typedef Value Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Annotation::Reader { +public: + typedef Annotation Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasValue() const; + inline ::capnp::schema::Value::Reader getValue() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Annotation::Builder { +public: + typedef Annotation Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasValue(); + inline ::capnp::schema::Value::Builder getValue(); + inline void setValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Annotation::Pipeline { +public: + typedef Annotation Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Value::Pipeline getValue(); + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CapnpVersion::Reader { +public: + typedef CapnpVersion Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getMajor() const; + + inline ::uint8_t getMinor() const; + + inline ::uint8_t getMicro() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CapnpVersion::Builder { +public: + typedef CapnpVersion Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getMajor(); + inline void setMajor( ::uint16_t value); + + inline ::uint8_t getMinor(); + inline void setMinor( ::uint8_t value); + + inline ::uint8_t getMicro(); + inline void setMicro( ::uint8_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CapnpVersion::Pipeline { +public: + typedef CapnpVersion Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::Reader { +public: + typedef CodeGeneratorRequest Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasNodes() const; + inline ::capnp::List< ::capnp::schema::Node>::Reader getNodes() const; + + inline bool hasRequestedFiles() const; + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader getRequestedFiles() const; + + inline bool hasCapnpVersion() const; + inline ::capnp::schema::CapnpVersion::Reader getCapnpVersion() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::Builder { +public: + typedef CodeGeneratorRequest Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasNodes(); + inline ::capnp::List< ::capnp::schema::Node>::Builder getNodes(); + inline void setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value); + inline ::capnp::List< ::capnp::schema::Node>::Builder initNodes(unsigned int size); + inline void adoptNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> disownNodes(); + + inline bool hasRequestedFiles(); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder getRequestedFiles(); + inline void setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder initRequestedFiles(unsigned int size); + inline void adoptRequestedFiles(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> disownRequestedFiles(); + + inline bool hasCapnpVersion(); + inline ::capnp::schema::CapnpVersion::Builder getCapnpVersion(); + inline void setCapnpVersion( ::capnp::schema::CapnpVersion::Reader value); + inline ::capnp::schema::CapnpVersion::Builder initCapnpVersion(); + inline void adoptCapnpVersion(::capnp::Orphan< ::capnp::schema::CapnpVersion>&& value); + inline ::capnp::Orphan< ::capnp::schema::CapnpVersion> disownCapnpVersion(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::Pipeline { +public: + typedef CodeGeneratorRequest Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::CapnpVersion::Pipeline getCapnpVersion(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::RequestedFile::Reader { +public: + typedef RequestedFile Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasFilename() const; + inline ::capnp::Text::Reader getFilename() const; + + inline bool hasImports() const; + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader getImports() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::RequestedFile::Builder { +public: + typedef RequestedFile Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasFilename(); + inline ::capnp::Text::Builder getFilename(); + inline void setFilename( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initFilename(unsigned int size); + inline void adoptFilename(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownFilename(); + + inline bool hasImports(); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder getImports(); + inline void setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder initImports(unsigned int size); + inline void adoptImports(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> disownImports(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::RequestedFile::Pipeline { +public: + typedef RequestedFile Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::RequestedFile::Import::Reader { +public: + typedef Import Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::RequestedFile::Import::Builder { +public: + typedef Import Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::RequestedFile::Import::Pipeline { +public: + typedef Import Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::schema::Node::Which Node::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Node::Which Node::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::hasDisplayName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasDisplayName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::Reader::getDisplayName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::Builder::getDisplayName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setDisplayName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::Builder::initDisplayName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptDisplayName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::Builder::disownDisplayName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Node::Reader::getDisplayNamePrefixLength() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Node::Builder::getDisplayNamePrefixLength() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setDisplayNamePrefixLength( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Node::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::hasNestedNodes() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasNestedNodes() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader Node::Reader::getNestedNodes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::getNestedNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::initNestedNodes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptNestedNodes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> Node::Builder::disownNestedNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Node::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Node::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::isFile() const { + return which() == Node::FILE; +} +inline bool Node::Builder::isFile() { + return which() == Node::FILE; +} +inline ::capnp::Void Node::Reader::getFile() const { + KJ_IREQUIRE((which() == Node::FILE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Node::Builder::getFile() { + KJ_IREQUIRE((which() == Node::FILE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setFile( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::FILE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::isStruct() const { + return which() == Node::STRUCT; +} +inline bool Node::Builder::isStruct() { + return which() == Node::STRUCT; +} +inline typename Node::Struct::Reader Node::Reader::getStruct() const { + KJ_IREQUIRE((which() == Node::STRUCT), + "Must check which() before get()ing a union member."); + return typename Node::Struct::Reader(_reader); +} +inline typename Node::Struct::Builder Node::Builder::getStruct() { + KJ_IREQUIRE((which() == Node::STRUCT), + "Must check which() before get()ing a union member."); + return typename Node::Struct::Builder(_builder); +} +inline typename Node::Struct::Builder Node::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::STRUCT); + _builder.setDataField< ::uint16_t>(::capnp::bounded<7>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<12>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<13>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<224>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<15>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint32_t>(::capnp::bounded<8>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Struct::Builder(_builder); +} +inline bool Node::Reader::isEnum() const { + return which() == Node::ENUM; +} +inline bool Node::Builder::isEnum() { + return which() == Node::ENUM; +} +inline typename Node::Enum::Reader Node::Reader::getEnum() const { + KJ_IREQUIRE((which() == Node::ENUM), + "Must check which() before get()ing a union member."); + return typename Node::Enum::Reader(_reader); +} +inline typename Node::Enum::Builder Node::Builder::getEnum() { + KJ_IREQUIRE((which() == Node::ENUM), + "Must check which() before get()ing a union member."); + return typename Node::Enum::Builder(_builder); +} +inline typename Node::Enum::Builder Node::Builder::initEnum() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::ENUM); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Enum::Builder(_builder); +} +inline bool Node::Reader::isInterface() const { + return which() == Node::INTERFACE; +} +inline bool Node::Builder::isInterface() { + return which() == Node::INTERFACE; +} +inline typename Node::Interface::Reader Node::Reader::getInterface() const { + KJ_IREQUIRE((which() == Node::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Node::Interface::Reader(_reader); +} +inline typename Node::Interface::Builder Node::Builder::getInterface() { + KJ_IREQUIRE((which() == Node::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Node::Interface::Builder(_builder); +} +inline typename Node::Interface::Builder Node::Builder::initInterface() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::INTERFACE); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<4>() * ::capnp::POINTERS).clear(); + return typename Node::Interface::Builder(_builder); +} +inline bool Node::Reader::isConst() const { + return which() == Node::CONST; +} +inline bool Node::Builder::isConst() { + return which() == Node::CONST; +} +inline typename Node::Const::Reader Node::Reader::getConst() const { + KJ_IREQUIRE((which() == Node::CONST), + "Must check which() before get()ing a union member."); + return typename Node::Const::Reader(_reader); +} +inline typename Node::Const::Builder Node::Builder::getConst() { + KJ_IREQUIRE((which() == Node::CONST), + "Must check which() before get()ing a union member."); + return typename Node::Const::Builder(_builder); +} +inline typename Node::Const::Builder Node::Builder::initConst() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::CONST); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<4>() * ::capnp::POINTERS).clear(); + return typename Node::Const::Builder(_builder); +} +inline bool Node::Reader::isAnnotation() const { + return which() == Node::ANNOTATION; +} +inline bool Node::Builder::isAnnotation() { + return which() == Node::ANNOTATION; +} +inline typename Node::Annotation::Reader Node::Reader::getAnnotation() const { + KJ_IREQUIRE((which() == Node::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Node::Annotation::Reader(_reader); +} +inline typename Node::Annotation::Builder Node::Builder::getAnnotation() { + KJ_IREQUIRE((which() == Node::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Node::Annotation::Builder(_builder); +} +inline typename Node::Annotation::Builder Node::Builder::initAnnotation() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::ANNOTATION); + _builder.setDataField(::capnp::bounded<112>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<113>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<114>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<115>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<116>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<117>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<118>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<119>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<120>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<121>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<122>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<123>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Annotation::Builder(_builder); +} +inline bool Node::Reader::hasParameters() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasParameters() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Node::Reader::getParameters() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::getParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::initParameters(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptParameters( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Node::Builder::disownParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::getIsGeneric() const { + return _reader.getDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS); +} + +inline bool Node::Builder::getIsGeneric() { + return _builder.getDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setIsGeneric(bool value) { + _builder.setDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Parameter::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Parameter::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::Parameter::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::Parameter::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::Parameter::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::Parameter::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::Parameter::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::Parameter::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Node::NestedNode::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::NestedNode::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::NestedNode::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::NestedNode::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::NestedNode::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::NestedNode::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::NestedNode::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::NestedNode::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Node::NestedNode::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::NestedNode::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::NestedNode::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getDataWordCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getDataWordCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDataWordCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getPointerCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getPointerCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setPointerCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::ElementSize Node::Struct::Reader::getPreferredListEncoding() const { + return _reader.getDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS); +} + +inline ::capnp::schema::ElementSize Node::Struct::Builder::getPreferredListEncoding() { + return _builder.getDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setPreferredListEncoding( ::capnp::schema::ElementSize value) { + _builder.setDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Struct::Reader::getIsGroup() const { + return _reader.getDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS); +} + +inline bool Node::Struct::Builder::getIsGroup() { + return _builder.getDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setIsGroup(bool value) { + _builder.setDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getDiscriminantCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getDiscriminantCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDiscriminantCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Node::Struct::Reader::getDiscriminantOffset() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Node::Struct::Builder::getDiscriminantOffset() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDiscriminantOffset( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Struct::Reader::hasFields() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Struct::Builder::hasFields() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Field>::Reader Node::Struct::Reader::getFields() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::getFields() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Struct::Builder::setFields( ::capnp::List< ::capnp::schema::Field>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::initFields(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Struct::Builder::adoptFields( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> Node::Struct::Builder::disownFields() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Enum::Reader::hasEnumerants() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Enum::Builder::hasEnumerants() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Reader Node::Enum::Reader::getEnumerants() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::getEnumerants() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Enum::Builder::setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::initEnumerants(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Enum::Builder::adoptEnumerants( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> Node::Enum::Builder::disownEnumerants() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Interface::Reader::hasMethods() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Interface::Builder::hasMethods() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Method>::Reader Node::Interface::Reader::getMethods() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::getMethods() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Interface::Builder::setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::initMethods(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Interface::Builder::adoptMethods( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> Node::Interface::Builder::disownMethods() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Interface::Reader::hasSuperclasses() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Interface::Builder::hasSuperclasses() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Reader Node::Interface::Reader::getSuperclasses() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::getSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Node::Interface::Builder::setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::initSuperclasses(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), size); +} +inline void Node::Interface::Builder::adoptSuperclasses( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> Node::Interface::Builder::disownSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline bool Node::Const::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Const::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Node::Const::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Node::Const::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Node::Const::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Node::Const::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Node::Const::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Const::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Node::Const::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Const::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Const::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Node::Const::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Node::Const::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Node::Const::Pipeline::getValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(4)); +} +#endif // !CAPNP_LITE +inline void Node::Const::Builder::setValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Node::Const::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Node::Const::Builder::adoptValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Node::Const::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline bool Node::Annotation::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Annotation::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Node::Annotation::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Node::Annotation::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Node::Annotation::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Node::Annotation::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Node::Annotation::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Annotation::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Node::Annotation::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Annotation::Reader::getTargetsFile() const { + return _reader.getDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsFile() { + return _builder.getDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsFile(bool value) { + _builder.setDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsConst() const { + return _reader.getDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsConst() { + return _builder.getDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsConst(bool value) { + _builder.setDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsEnum() const { + return _reader.getDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsEnum() { + return _builder.getDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsEnum(bool value) { + _builder.setDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsEnumerant() const { + return _reader.getDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsEnumerant() { + return _builder.getDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsEnumerant(bool value) { + _builder.setDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsStruct() const { + return _reader.getDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsStruct() { + return _builder.getDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsStruct(bool value) { + _builder.setDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsField() const { + return _reader.getDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsField() { + return _builder.getDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsField(bool value) { + _builder.setDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsUnion() const { + return _reader.getDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsUnion() { + return _builder.getDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsUnion(bool value) { + _builder.setDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsGroup() const { + return _reader.getDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsGroup() { + return _builder.getDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsGroup(bool value) { + _builder.setDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsInterface() const { + return _reader.getDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsInterface() { + return _builder.getDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsInterface(bool value) { + _builder.setDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsMethod() const { + return _reader.getDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsMethod() { + return _builder.getDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsMethod(bool value) { + _builder.setDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsParam() const { + return _reader.getDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsParam() { + return _builder.getDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsParam(bool value) { + _builder.setDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsAnnotation() const { + return _reader.getDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsAnnotation() { + return _builder.getDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsAnnotation(bool value) { + _builder.setDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Field::Which Field::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Field::Which Field::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline bool Field::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Field::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Field::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Field::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Field::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Field::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Field::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Field::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Field::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Field::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Field::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Field::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Field::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Field::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Field::Reader::getDiscriminantValue() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, 65535u); +} + +inline ::uint16_t Field::Builder::getDiscriminantValue() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, 65535u); +} +inline void Field::Builder::setDiscriminantValue( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value, 65535u); +} + +inline bool Field::Reader::isSlot() const { + return which() == Field::SLOT; +} +inline bool Field::Builder::isSlot() { + return which() == Field::SLOT; +} +inline typename Field::Slot::Reader Field::Reader::getSlot() const { + KJ_IREQUIRE((which() == Field::SLOT), + "Must check which() before get()ing a union member."); + return typename Field::Slot::Reader(_reader); +} +inline typename Field::Slot::Builder Field::Builder::getSlot() { + KJ_IREQUIRE((which() == Field::SLOT), + "Must check which() before get()ing a union member."); + return typename Field::Slot::Builder(_builder); +} +inline typename Field::Slot::Builder Field::Builder::initSlot() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Field::SLOT); + _builder.setDataField< ::uint32_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<128>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<2>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Field::Slot::Builder(_builder); +} +inline bool Field::Reader::isGroup() const { + return which() == Field::GROUP; +} +inline bool Field::Builder::isGroup() { + return which() == Field::GROUP; +} +inline typename Field::Group::Reader Field::Reader::getGroup() const { + KJ_IREQUIRE((which() == Field::GROUP), + "Must check which() before get()ing a union member."); + return typename Field::Group::Reader(_reader); +} +inline typename Field::Group::Builder Field::Builder::getGroup() { + KJ_IREQUIRE((which() == Field::GROUP), + "Must check which() before get()ing a union member."); + return typename Field::Group::Builder(_builder); +} +inline typename Field::Group::Builder Field::Builder::initGroup() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Field::GROUP); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Field::Group::Builder(_builder); +} +inline typename Field::Ordinal::Reader Field::Reader::getOrdinal() const { + return typename Field::Ordinal::Reader(_reader); +} +inline typename Field::Ordinal::Builder Field::Builder::getOrdinal() { + return typename Field::Ordinal::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Field::Ordinal::Pipeline Field::Pipeline::getOrdinal() { + return typename Field::Ordinal::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Field::Ordinal::Builder Field::Builder::initOrdinal() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + return typename Field::Ordinal::Builder(_builder); +} +inline ::uint32_t Field::Slot::Reader::getOffset() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Field::Slot::Builder::getOffset() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Field::Slot::Builder::setOffset( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Slot::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Slot::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Field::Slot::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Field::Slot::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Field::Slot::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void Field::Slot::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Field::Slot::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Field::Slot::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Field::Slot::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Field::Slot::Reader::hasDefaultValue() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Slot::Builder::hasDefaultValue() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Field::Slot::Reader::getDefaultValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Field::Slot::Builder::getDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Field::Slot::Pipeline::getDefaultValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Field::Slot::Builder::setDefaultValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Field::Slot::Builder::initDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Field::Slot::Builder::adoptDefaultValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Field::Slot::Builder::disownDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Field::Slot::Reader::getHadExplicitDefault() const { + return _reader.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} + +inline bool Field::Slot::Builder::getHadExplicitDefault() { + return _builder.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} +inline void Field::Slot::Builder::setHadExplicitDefault(bool value) { + _builder.setDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Field::Group::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Field::Group::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Field::Group::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline bool Field::Ordinal::Reader::isImplicit() const { + return which() == Field::Ordinal::IMPLICIT; +} +inline bool Field::Ordinal::Builder::isImplicit() { + return which() == Field::Ordinal::IMPLICIT; +} +inline ::capnp::Void Field::Ordinal::Reader::getImplicit() const { + KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Field::Ordinal::Builder::getImplicit() { + KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Field::Ordinal::Builder::setImplicit( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Field::Ordinal::IMPLICIT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Ordinal::Reader::isExplicit() const { + return which() == Field::Ordinal::EXPLICIT; +} +inline bool Field::Ordinal::Builder::isExplicit() { + return which() == Field::Ordinal::EXPLICIT; +} +inline ::uint16_t Field::Ordinal::Reader::getExplicit() const { + KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Field::Ordinal::Builder::getExplicit() { + KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline void Field::Ordinal::Builder::setExplicit( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Field::Ordinal::EXPLICIT); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, value); +} + +inline bool Enumerant::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Enumerant::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Enumerant::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Enumerant::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Enumerant::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Enumerant::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Enumerant::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Enumerant::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Enumerant::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Enumerant::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Enumerant::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Enumerant::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Enumerant::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Enumerant::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Enumerant::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Enumerant::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Enumerant::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Superclass::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Superclass::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Superclass::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Superclass::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Superclass::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Superclass::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Superclass::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Superclass::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Superclass::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Superclass::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Superclass::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Superclass::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Method::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Method::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Method::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Method::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Method::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Method::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Method::Reader::getParamStructType() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Method::Builder::getParamStructType() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setParamStructType( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Method::Reader::getResultStructType() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Method::Builder::getResultStructType() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setResultStructType( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Method::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Method::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Method::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasParamBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasParamBrand() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Method::Reader::getParamBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Method::Builder::getParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getParamBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void Method::Builder::setParamBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Method::Builder::initParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Method::Builder::adoptParamBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasResultBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasResultBrand() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Method::Reader::getResultBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Method::Builder::getResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getResultBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Method::Builder::setResultBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Method::Builder::initResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Method::Builder::adoptResultBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasImplicitParameters() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasImplicitParameters() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Method::Reader::getImplicitParameters() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::getImplicitParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::initImplicitParameters(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptImplicitParameters( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Method::Builder::disownImplicitParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Type::Which Type::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::Which Type::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Type::Reader::isVoid() const { + return which() == Type::VOID; +} +inline bool Type::Builder::isVoid() { + return which() == Type::VOID; +} +inline ::capnp::Void Type::Reader::getVoid() const { + KJ_IREQUIRE((which() == Type::VOID), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getVoid() { + KJ_IREQUIRE((which() == Type::VOID), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setVoid( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::VOID); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isBool() const { + return which() == Type::BOOL; +} +inline bool Type::Builder::isBool() { + return which() == Type::BOOL; +} +inline ::capnp::Void Type::Reader::getBool() const { + KJ_IREQUIRE((which() == Type::BOOL), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getBool() { + KJ_IREQUIRE((which() == Type::BOOL), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setBool( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::BOOL); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt8() const { + return which() == Type::INT8; +} +inline bool Type::Builder::isInt8() { + return which() == Type::INT8; +} +inline ::capnp::Void Type::Reader::getInt8() const { + KJ_IREQUIRE((which() == Type::INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt8() { + KJ_IREQUIRE((which() == Type::INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt16() const { + return which() == Type::INT16; +} +inline bool Type::Builder::isInt16() { + return which() == Type::INT16; +} +inline ::capnp::Void Type::Reader::getInt16() const { + KJ_IREQUIRE((which() == Type::INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt16() { + KJ_IREQUIRE((which() == Type::INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt32() const { + return which() == Type::INT32; +} +inline bool Type::Builder::isInt32() { + return which() == Type::INT32; +} +inline ::capnp::Void Type::Reader::getInt32() const { + KJ_IREQUIRE((which() == Type::INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt32() { + KJ_IREQUIRE((which() == Type::INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt64() const { + return which() == Type::INT64; +} +inline bool Type::Builder::isInt64() { + return which() == Type::INT64; +} +inline ::capnp::Void Type::Reader::getInt64() const { + KJ_IREQUIRE((which() == Type::INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt64() { + KJ_IREQUIRE((which() == Type::INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint8() const { + return which() == Type::UINT8; +} +inline bool Type::Builder::isUint8() { + return which() == Type::UINT8; +} +inline ::capnp::Void Type::Reader::getUint8() const { + KJ_IREQUIRE((which() == Type::UINT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint8() { + KJ_IREQUIRE((which() == Type::UINT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint16() const { + return which() == Type::UINT16; +} +inline bool Type::Builder::isUint16() { + return which() == Type::UINT16; +} +inline ::capnp::Void Type::Reader::getUint16() const { + KJ_IREQUIRE((which() == Type::UINT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint16() { + KJ_IREQUIRE((which() == Type::UINT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint32() const { + return which() == Type::UINT32; +} +inline bool Type::Builder::isUint32() { + return which() == Type::UINT32; +} +inline ::capnp::Void Type::Reader::getUint32() const { + KJ_IREQUIRE((which() == Type::UINT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint32() { + KJ_IREQUIRE((which() == Type::UINT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint64() const { + return which() == Type::UINT64; +} +inline bool Type::Builder::isUint64() { + return which() == Type::UINT64; +} +inline ::capnp::Void Type::Reader::getUint64() const { + KJ_IREQUIRE((which() == Type::UINT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint64() { + KJ_IREQUIRE((which() == Type::UINT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isFloat32() const { + return which() == Type::FLOAT32; +} +inline bool Type::Builder::isFloat32() { + return which() == Type::FLOAT32; +} +inline ::capnp::Void Type::Reader::getFloat32() const { + KJ_IREQUIRE((which() == Type::FLOAT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getFloat32() { + KJ_IREQUIRE((which() == Type::FLOAT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setFloat32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::FLOAT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isFloat64() const { + return which() == Type::FLOAT64; +} +inline bool Type::Builder::isFloat64() { + return which() == Type::FLOAT64; +} +inline ::capnp::Void Type::Reader::getFloat64() const { + KJ_IREQUIRE((which() == Type::FLOAT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getFloat64() { + KJ_IREQUIRE((which() == Type::FLOAT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setFloat64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::FLOAT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isText() const { + return which() == Type::TEXT; +} +inline bool Type::Builder::isText() { + return which() == Type::TEXT; +} +inline ::capnp::Void Type::Reader::getText() const { + KJ_IREQUIRE((which() == Type::TEXT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getText() { + KJ_IREQUIRE((which() == Type::TEXT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setText( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::TEXT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isData() const { + return which() == Type::DATA; +} +inline bool Type::Builder::isData() { + return which() == Type::DATA; +} +inline ::capnp::Void Type::Reader::getData() const { + KJ_IREQUIRE((which() == Type::DATA), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getData() { + KJ_IREQUIRE((which() == Type::DATA), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setData( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::DATA); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isList() const { + return which() == Type::LIST; +} +inline bool Type::Builder::isList() { + return which() == Type::LIST; +} +inline typename Type::List::Reader Type::Reader::getList() const { + KJ_IREQUIRE((which() == Type::LIST), + "Must check which() before get()ing a union member."); + return typename Type::List::Reader(_reader); +} +inline typename Type::List::Builder Type::Builder::getList() { + KJ_IREQUIRE((which() == Type::LIST), + "Must check which() before get()ing a union member."); + return typename Type::List::Builder(_builder); +} +inline typename Type::List::Builder Type::Builder::initList() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::LIST); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::List::Builder(_builder); +} +inline bool Type::Reader::isEnum() const { + return which() == Type::ENUM; +} +inline bool Type::Builder::isEnum() { + return which() == Type::ENUM; +} +inline typename Type::Enum::Reader Type::Reader::getEnum() const { + KJ_IREQUIRE((which() == Type::ENUM), + "Must check which() before get()ing a union member."); + return typename Type::Enum::Reader(_reader); +} +inline typename Type::Enum::Builder Type::Builder::getEnum() { + KJ_IREQUIRE((which() == Type::ENUM), + "Must check which() before get()ing a union member."); + return typename Type::Enum::Builder(_builder); +} +inline typename Type::Enum::Builder Type::Builder::initEnum() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::ENUM); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Enum::Builder(_builder); +} +inline bool Type::Reader::isStruct() const { + return which() == Type::STRUCT; +} +inline bool Type::Builder::isStruct() { + return which() == Type::STRUCT; +} +inline typename Type::Struct::Reader Type::Reader::getStruct() const { + KJ_IREQUIRE((which() == Type::STRUCT), + "Must check which() before get()ing a union member."); + return typename Type::Struct::Reader(_reader); +} +inline typename Type::Struct::Builder Type::Builder::getStruct() { + KJ_IREQUIRE((which() == Type::STRUCT), + "Must check which() before get()ing a union member."); + return typename Type::Struct::Builder(_builder); +} +inline typename Type::Struct::Builder Type::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::STRUCT); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Struct::Builder(_builder); +} +inline bool Type::Reader::isInterface() const { + return which() == Type::INTERFACE; +} +inline bool Type::Builder::isInterface() { + return which() == Type::INTERFACE; +} +inline typename Type::Interface::Reader Type::Reader::getInterface() const { + KJ_IREQUIRE((which() == Type::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Type::Interface::Reader(_reader); +} +inline typename Type::Interface::Builder Type::Builder::getInterface() { + KJ_IREQUIRE((which() == Type::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Type::Interface::Builder(_builder); +} +inline typename Type::Interface::Builder Type::Builder::initInterface() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INTERFACE); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Interface::Builder(_builder); +} +inline bool Type::Reader::isAnyPointer() const { + return which() == Type::ANY_POINTER; +} +inline bool Type::Builder::isAnyPointer() { + return which() == Type::ANY_POINTER; +} +inline typename Type::AnyPointer::Reader Type::Reader::getAnyPointer() const { + KJ_IREQUIRE((which() == Type::ANY_POINTER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Reader(_reader); +} +inline typename Type::AnyPointer::Builder Type::Builder::getAnyPointer() { + KJ_IREQUIRE((which() == Type::ANY_POINTER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Builder(_builder); +} +inline typename Type::AnyPointer::Builder Type::Builder::initAnyPointer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::ANY_POINTER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<4>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Builder(_builder); +} +inline bool Type::List::Reader::hasElementType() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::List::Builder::hasElementType() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Type::List::Reader::getElementType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Type::List::Builder::getElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Type::List::Pipeline::getElementType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::List::Builder::setElementType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Type::List::Builder::initElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::List::Builder::adoptElementType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Type::List::Builder::disownElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Enum::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Enum::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Enum::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Enum::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Enum::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Enum::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Enum::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Enum::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Enum::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Enum::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Enum::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Enum::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Struct::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Struct::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Struct::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Struct::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Struct::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Struct::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Struct::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Struct::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Struct::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Struct::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Struct::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Struct::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Interface::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Interface::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Interface::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Interface::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Interface::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Interface::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Interface::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Interface::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Interface::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Interface::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Interface::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Interface::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline bool Type::AnyPointer::Reader::isUnconstrained() const { + return which() == Type::AnyPointer::UNCONSTRAINED; +} +inline bool Type::AnyPointer::Builder::isUnconstrained() { + return which() == Type::AnyPointer::UNCONSTRAINED; +} +inline typename Type::AnyPointer::Unconstrained::Reader Type::AnyPointer::Reader::getUnconstrained() const { + KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Unconstrained::Reader(_reader); +} +inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::getUnconstrained() { + KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Unconstrained::Builder(_builder); +} +inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::initUnconstrained() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::UNCONSTRAINED); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Unconstrained::Builder(_builder); +} +inline bool Type::AnyPointer::Reader::isParameter() const { + return which() == Type::AnyPointer::PARAMETER; +} +inline bool Type::AnyPointer::Builder::isParameter() { + return which() == Type::AnyPointer::PARAMETER; +} +inline typename Type::AnyPointer::Parameter::Reader Type::AnyPointer::Reader::getParameter() const { + KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Parameter::Reader(_reader); +} +inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::getParameter() { + KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Parameter::Builder(_builder); +} +inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::initParameter() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::PARAMETER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Parameter::Builder(_builder); +} +inline bool Type::AnyPointer::Reader::isImplicitMethodParameter() const { + return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; +} +inline bool Type::AnyPointer::Builder::isImplicitMethodParameter() { + return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Reader Type::AnyPointer::Reader::getImplicitMethodParameter() const { + KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::ImplicitMethodParameter::Reader(_reader); +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::getImplicitMethodParameter() { + KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::initImplicitMethodParameter() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::IMPLICIT_METHOD_PARAMETER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); +} +inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isAnyKind() const { + return which() == Type::AnyPointer::Unconstrained::ANY_KIND; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isAnyKind() { + return which() == Type::AnyPointer::Unconstrained::ANY_KIND; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getAnyKind() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getAnyKind() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setAnyKind( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::ANY_KIND); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isStruct() const { + return which() == Type::AnyPointer::Unconstrained::STRUCT; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isStruct() { + return which() == Type::AnyPointer::Unconstrained::STRUCT; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getStruct() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getStruct() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setStruct( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::STRUCT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isList() const { + return which() == Type::AnyPointer::Unconstrained::LIST; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isList() { + return which() == Type::AnyPointer::Unconstrained::LIST; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getList() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getList() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setList( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::LIST); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isCapability() const { + return which() == Type::AnyPointer::Unconstrained::CAPABILITY; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isCapability() { + return which() == Type::AnyPointer::Unconstrained::CAPABILITY; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getCapability() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getCapability() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setCapability( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::CAPABILITY); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Type::AnyPointer::Parameter::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::AnyPointer::Parameter::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Parameter::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Type::AnyPointer::Parameter::Reader::getParameterIndex() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Type::AnyPointer::Parameter::Builder::getParameterIndex() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Parameter::Builder::setParameterIndex( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Reader::getParameterIndex() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Builder::getParameterIndex() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::ImplicitMethodParameter::Builder::setParameterIndex( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Reader::hasScopes() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Builder::hasScopes() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader Brand::Reader::getScopes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::getScopes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Builder::setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::initScopes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Brand::Builder::adoptScopes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> Brand::Builder::disownScopes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Brand::Scope::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Brand::Scope::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Scope::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Scope::Reader::isBind() const { + return which() == Brand::Scope::BIND; +} +inline bool Brand::Scope::Builder::isBind() { + return which() == Brand::Scope::BIND; +} +inline bool Brand::Scope::Reader::hasBind() const { + if (which() != Brand::Scope::BIND) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Scope::Builder::hasBind() { + if (which() != Brand::Scope::BIND) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader Brand::Scope::Reader::getBind() const { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::getBind() { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Scope::Builder::setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::initBind(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Brand::Scope::Builder::adoptBind( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> Brand::Scope::Builder::disownBind() { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Brand::Scope::Reader::isInherit() const { + return which() == Brand::Scope::INHERIT; +} +inline bool Brand::Scope::Builder::isInherit() { + return which() == Brand::Scope::INHERIT; +} +inline ::capnp::Void Brand::Scope::Reader::getInherit() const { + KJ_IREQUIRE((which() == Brand::Scope::INHERIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Brand::Scope::Builder::getInherit() { + KJ_IREQUIRE((which() == Brand::Scope::INHERIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Scope::Builder::setInherit( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::INHERIT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Brand::Binding::Reader::isUnbound() const { + return which() == Brand::Binding::UNBOUND; +} +inline bool Brand::Binding::Builder::isUnbound() { + return which() == Brand::Binding::UNBOUND; +} +inline ::capnp::Void Brand::Binding::Reader::getUnbound() const { + KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Brand::Binding::Builder::getUnbound() { + KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Binding::Builder::setUnbound( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::UNBOUND); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Binding::Reader::isType() const { + return which() == Brand::Binding::TYPE; +} +inline bool Brand::Binding::Builder::isType() { + return which() == Brand::Binding::TYPE; +} +inline bool Brand::Binding::Reader::hasType() const { + if (which() != Brand::Binding::TYPE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Binding::Builder::hasType() { + if (which() != Brand::Binding::TYPE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Brand::Binding::Reader::getType() const { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Brand::Binding::Builder::getType() { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Binding::Builder::setType( ::capnp::schema::Type::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Brand::Binding::Builder::initType() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Binding::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Brand::Binding::Builder::disownType() { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Value::Which Value::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Value::Which Value::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Value::Reader::isVoid() const { + return which() == Value::VOID; +} +inline bool Value::Builder::isVoid() { + return which() == Value::VOID; +} +inline ::capnp::Void Value::Reader::getVoid() const { + KJ_IREQUIRE((which() == Value::VOID), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Value::Builder::getVoid() { + KJ_IREQUIRE((which() == Value::VOID), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setVoid( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::VOID); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isBool() const { + return which() == Value::BOOL; +} +inline bool Value::Builder::isBool() { + return which() == Value::BOOL; +} +inline bool Value::Reader::getBool() const { + KJ_IREQUIRE((which() == Value::BOOL), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} + +inline bool Value::Builder::getBool() { + KJ_IREQUIRE((which() == Value::BOOL), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setBool(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::BOOL); + _builder.setDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt8() const { + return which() == Value::INT8; +} +inline bool Value::Builder::isInt8() { + return which() == Value::INT8; +} +inline ::int8_t Value::Reader::getInt8() const { + KJ_IREQUIRE((which() == Value::INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::int8_t Value::Builder::getInt8() { + KJ_IREQUIRE((which() == Value::INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt8( ::int8_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT8); + _builder.setDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt16() const { + return which() == Value::INT16; +} +inline bool Value::Builder::isInt16() { + return which() == Value::INT16; +} +inline ::int16_t Value::Reader::getInt16() const { + KJ_IREQUIRE((which() == Value::INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int16_t Value::Builder::getInt16() { + KJ_IREQUIRE((which() == Value::INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt16( ::int16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT16); + _builder.setDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt32() const { + return which() == Value::INT32; +} +inline bool Value::Builder::isInt32() { + return which() == Value::INT32; +} +inline ::int32_t Value::Reader::getInt32() const { + KJ_IREQUIRE((which() == Value::INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int32_t Value::Builder::getInt32() { + KJ_IREQUIRE((which() == Value::INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt32( ::int32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT32); + _builder.setDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt64() const { + return which() == Value::INT64; +} +inline bool Value::Builder::isInt64() { + return which() == Value::INT64; +} +inline ::int64_t Value::Reader::getInt64() const { + KJ_IREQUIRE((which() == Value::INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int64_t Value::Builder::getInt64() { + KJ_IREQUIRE((which() == Value::INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt64( ::int64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT64); + _builder.setDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint8() const { + return which() == Value::UINT8; +} +inline bool Value::Builder::isUint8() { + return which() == Value::UINT8; +} +inline ::uint8_t Value::Reader::getUint8() const { + KJ_IREQUIRE((which() == Value::UINT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t Value::Builder::getUint8() { + KJ_IREQUIRE((which() == Value::UINT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint8( ::uint8_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT8); + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint16() const { + return which() == Value::UINT16; +} +inline bool Value::Builder::isUint16() { + return which() == Value::UINT16; +} +inline ::uint16_t Value::Reader::getUint16() const { + KJ_IREQUIRE((which() == Value::UINT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Value::Builder::getUint16() { + KJ_IREQUIRE((which() == Value::UINT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint16( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT16); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint32() const { + return which() == Value::UINT32; +} +inline bool Value::Builder::isUint32() { + return which() == Value::UINT32; +} +inline ::uint32_t Value::Reader::getUint32() const { + KJ_IREQUIRE((which() == Value::UINT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Value::Builder::getUint32() { + KJ_IREQUIRE((which() == Value::UINT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint32( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT32); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint64() const { + return which() == Value::UINT64; +} +inline bool Value::Builder::isUint64() { + return which() == Value::UINT64; +} +inline ::uint64_t Value::Reader::getUint64() const { + KJ_IREQUIRE((which() == Value::UINT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Value::Builder::getUint64() { + KJ_IREQUIRE((which() == Value::UINT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint64( ::uint64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT64); + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isFloat32() const { + return which() == Value::FLOAT32; +} +inline bool Value::Builder::isFloat32() { + return which() == Value::FLOAT32; +} +inline float Value::Reader::getFloat32() const { + KJ_IREQUIRE((which() == Value::FLOAT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline float Value::Builder::getFloat32() { + KJ_IREQUIRE((which() == Value::FLOAT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setFloat32(float value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::FLOAT32); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isFloat64() const { + return which() == Value::FLOAT64; +} +inline bool Value::Builder::isFloat64() { + return which() == Value::FLOAT64; +} +inline double Value::Reader::getFloat64() const { + KJ_IREQUIRE((which() == Value::FLOAT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double Value::Builder::getFloat64() { + KJ_IREQUIRE((which() == Value::FLOAT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setFloat64(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::FLOAT64); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isText() const { + return which() == Value::TEXT; +} +inline bool Value::Builder::isText() { + return which() == Value::TEXT; +} +inline bool Value::Reader::hasText() const { + if (which() != Value::TEXT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasText() { + if (which() != Value::TEXT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Value::Reader::getText() const { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Value::Builder::getText() { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Value::Builder::setText( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Value::Builder::initText(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Value::Builder::adoptText( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Value::Builder::disownText() { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Value::Reader::isData() const { + return which() == Value::DATA; +} +inline bool Value::Builder::isData() { + return which() == Value::DATA; +} +inline bool Value::Reader::hasData() const { + if (which() != Value::DATA) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasData() { + if (which() != Value::DATA) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Data::Reader Value::Reader::getData() const { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Data::Builder Value::Builder::getData() { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Value::Builder::setData( ::capnp::Data::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + ::capnp::_::PointerHelpers< ::capnp::Data>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Data::Builder Value::Builder::initData(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + return ::capnp::_::PointerHelpers< ::capnp::Data>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Value::Builder::adoptData( + ::capnp::Orphan< ::capnp::Data>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + ::capnp::_::PointerHelpers< ::capnp::Data>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Data> Value::Builder::disownData() { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Value::Reader::isList() const { + return which() == Value::LIST; +} +inline bool Value::Builder::isList() { + return which() == Value::LIST; +} +inline bool Value::Reader::hasList() const { + if (which() != Value::LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasList() { + if (which() != Value::LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getList() const { + KJ_IREQUIRE((which() == Value::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getList() { + KJ_IREQUIRE((which() == Value::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initList() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::LIST); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Value::Reader::isEnum() const { + return which() == Value::ENUM; +} +inline bool Value::Builder::isEnum() { + return which() == Value::ENUM; +} +inline ::uint16_t Value::Reader::getEnum() const { + KJ_IREQUIRE((which() == Value::ENUM), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Value::Builder::getEnum() { + KJ_IREQUIRE((which() == Value::ENUM), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setEnum( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::ENUM); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isStruct() const { + return which() == Value::STRUCT; +} +inline bool Value::Builder::isStruct() { + return which() == Value::STRUCT; +} +inline bool Value::Reader::hasStruct() const { + if (which() != Value::STRUCT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasStruct() { + if (which() != Value::STRUCT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getStruct() const { + KJ_IREQUIRE((which() == Value::STRUCT), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getStruct() { + KJ_IREQUIRE((which() == Value::STRUCT), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::STRUCT); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Value::Reader::isInterface() const { + return which() == Value::INTERFACE; +} +inline bool Value::Builder::isInterface() { + return which() == Value::INTERFACE; +} +inline ::capnp::Void Value::Reader::getInterface() const { + KJ_IREQUIRE((which() == Value::INTERFACE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Value::Builder::getInterface() { + KJ_IREQUIRE((which() == Value::INTERFACE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInterface( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INTERFACE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isAnyPointer() const { + return which() == Value::ANY_POINTER; +} +inline bool Value::Builder::isAnyPointer() { + return which() == Value::ANY_POINTER; +} +inline bool Value::Reader::hasAnyPointer() const { + if (which() != Value::ANY_POINTER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasAnyPointer() { + if (which() != Value::ANY_POINTER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getAnyPointer() const { + KJ_IREQUIRE((which() == Value::ANY_POINTER), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getAnyPointer() { + KJ_IREQUIRE((which() == Value::ANY_POINTER), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initAnyPointer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::ANY_POINTER); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint64_t Annotation::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Annotation::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Annotation::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Annotation::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Annotation::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Annotation::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Annotation::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Annotation::Pipeline::getValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Annotation::Builder::setValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Annotation::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Annotation::Builder::adoptValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Annotation::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Annotation::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Annotation::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Annotation::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Annotation::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Annotation::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Annotation::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Annotation::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Annotation::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Annotation::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint16_t CapnpVersion::Reader::getMajor() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t CapnpVersion::Builder::getMajor() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMajor( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint8_t CapnpVersion::Reader::getMinor() const { + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t CapnpVersion::Builder::getMinor() { + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMinor( ::uint8_t value) { + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint8_t CapnpVersion::Reader::getMicro() const { + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t CapnpVersion::Builder::getMicro() { + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMicro( ::uint8_t value) { + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::Reader::hasNodes() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasNodes() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node>::Reader CodeGeneratorRequest::Reader::getNodes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::getNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::initNodes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::Builder::adoptNodes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> CodeGeneratorRequest::Builder::disownNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::Reader::hasRequestedFiles() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasRequestedFiles() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader CodeGeneratorRequest::Reader::getRequestedFiles() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::getRequestedFiles() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::initRequestedFiles(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::Builder::adoptRequestedFiles( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> CodeGeneratorRequest::Builder::disownRequestedFiles() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::Reader::hasCapnpVersion() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasCapnpVersion() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::CapnpVersion::Reader CodeGeneratorRequest::Reader::getCapnpVersion() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::CapnpVersion::Builder CodeGeneratorRequest::Builder::getCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::CapnpVersion::Pipeline CodeGeneratorRequest::Pipeline::getCapnpVersion() { + return ::capnp::schema::CapnpVersion::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void CodeGeneratorRequest::Builder::setCapnpVersion( ::capnp::schema::CapnpVersion::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::CapnpVersion::Builder CodeGeneratorRequest::Builder::initCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::adoptCapnpVersion( + ::capnp::Orphan< ::capnp::schema::CapnpVersion>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::CapnpVersion> CodeGeneratorRequest::Builder::disownCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::RequestedFile::Reader::hasFilename() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Builder::hasFilename() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Reader::getFilename() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::getFilename() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setFilename( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::initFilename(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::adoptFilename( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Builder::disownFilename() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::RequestedFile::Reader::hasImports() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Builder::hasImports() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader CodeGeneratorRequest::RequestedFile::Reader::getImports() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::getImports() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::initImports(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::adoptImports( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> CodeGeneratorRequest::RequestedFile::Builder::disownImports() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::RequestedFile::Import::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Import::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Import::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Import::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_a93fc509624c72d9_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/schema.h --- a/osx/include/capnp/schema.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/schema.h Mon May 22 10:01:37 2017 +0100 @@ -1,934 +1,934 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SCHEMA_H_ -#define CAPNP_SCHEMA_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#if CAPNP_LITE -#error "Reflection APIs, including this header, are not available in lite mode." -#endif - -#include - -namespace capnp { - -class Schema; -class StructSchema; -class EnumSchema; -class InterfaceSchema; -class ConstSchema; -class ListSchema; -class Type; - -template ()> struct SchemaType_ { typedef Schema Type; }; -template struct SchemaType_ { typedef schema::Type::Which Type; }; -template struct SchemaType_ { typedef schema::Type::Which Type; }; -template struct SchemaType_ { typedef EnumSchema Type; }; -template struct SchemaType_ { typedef StructSchema Type; }; -template struct SchemaType_ { typedef InterfaceSchema Type; }; -template struct SchemaType_ { typedef ListSchema Type; }; - -template -using SchemaType = typename SchemaType_::Type; -// SchemaType is the type of T's schema, e.g. StructSchema if T is a struct. - -namespace _ { // private -extern const RawSchema NULL_SCHEMA; -extern const RawSchema NULL_STRUCT_SCHEMA; -extern const RawSchema NULL_ENUM_SCHEMA; -extern const RawSchema NULL_INTERFACE_SCHEMA; -extern const RawSchema NULL_CONST_SCHEMA; -// The schema types default to these null (empty) schemas in case of error, especially when -// exceptions are disabled. -} // namespace _ (private) - -class Schema { - // Convenience wrapper around capnp::schema::Node. - -public: - inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {} - - template - static inline SchemaType from() { return SchemaType::template fromImpl(); } - // Get the Schema for a particular compiled-in type. - - schema::Node::Reader getProto() const; - // Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor - // has performance comparable to accessors of struct-typed fields on Reader classes.) - - kj::ArrayPtr asUncheckedMessage() const; - // Get the encoded schema node content as a single message segment. It is safe to read as an - // unchecked message. - - Schema getDependency(uint64_t id) const KJ_DEPRECATED("Does not handle generics correctly."); - // DEPRECATED: This method cannot correctly account for generic type parameter bindings that - // may apply to the dependency. Instead of using this method, use a method of the Schema API - // that corresponds to the exact kind of dependency. For example, to get a field type, use - // StructSchema::Field::getType(). - // - // Gets the Schema for one of this Schema's dependencies. For example, if this Schema is for a - // struct, you could look up the schema for one of its fields' types. Throws an exception if this - // schema doesn't actually depend on the given id. - // - // Note that not all type IDs found in the schema node are considered "dependencies" -- only the - // ones that are needed to implement the dynamic API are. That includes: - // - Field types. - // - Group types. - // - scopeId for group nodes, but NOT otherwise. - // - Method parameter and return types. - // - // The following are NOT considered dependencies: - // - Nested nodes. - // - scopeId for a non-group node. - // - Annotations. - // - // To obtain schemas for those, you would need a SchemaLoader. - - bool isBranded() const; - // Returns true if this schema represents a non-default parameterization of this type. - - Schema getGeneric() const; - // Get the version of this schema with any brands removed. - - class BrandArgumentList; - BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const; - // Gets the values bound to the brand parameters at the given scope. - - StructSchema asStruct() const; - EnumSchema asEnum() const; - InterfaceSchema asInterface() const; - ConstSchema asConst() const; - // Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use - // getProto() to determine type, e.g. getProto().isStruct(). - - inline bool operator==(const Schema& other) const { return raw == other.raw; } - inline bool operator!=(const Schema& other) const { return raw != other.raw; } - // Determine whether two Schemas are wrapping the exact same underlying data, by identity. If - // you want to check if two Schemas represent the same type (but possibly different versions of - // it), compare their IDs instead. - - template - void requireUsableAs() const; - // Throws an exception if a value with this Schema cannot safely be cast to a native value of - // the given type. This passes if either: - // - *this == from() - // - This schema was loaded with SchemaLoader, the type ID matches typeId(), and - // loadCompiledTypeAndDependencies() was called on the SchemaLoader. - - kj::StringPtr getShortDisplayName() const; - // Get the short version of the node's display name. - -private: - const _::RawBrandedSchema* raw; - - inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) { - KJ_IREQUIRE(raw->lazyInitializer == nullptr, - "Must call ensureInitialized() on RawSchema before constructing Schema."); - } - - template static inline Schema fromImpl() { - return Schema(&_::rawSchema()); - } - - void requireUsableAs(const _::RawSchema* expected) const; - - uint32_t getSchemaOffset(const schema::Value::Reader& value) const; - - Type getBrandBinding(uint64_t scopeId, uint index) const; - // Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the - // parameter is not bound. - // - // TODO(someday): Public interface for iterating over all bindings? - - Schema getDependency(uint64_t id, uint location) const; - // Look up schema for a particular dependency of this schema. `location` is the dependency - // location number as defined in _::RawBrandedSchema. - - Type interpretType(schema::Type::Reader proto, uint location) const; - // Interpret a schema::Type in the given location within the schema, compiling it into a - // Type object. - - friend class StructSchema; - friend class EnumSchema; - friend class InterfaceSchema; - friend class ConstSchema; - friend class ListSchema; - friend class SchemaLoader; - friend class Type; - friend kj::StringTree _::structString( - _::StructReader reader, const _::RawBrandedSchema& schema); - friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema); -}; - -kj::StringPtr KJ_STRINGIFY(const Schema& schema); - -class Schema::BrandArgumentList { - // A list of generic parameter bindings for parameters of some particular type. Note that since - // parameters on an outer type apply to all inner types as well, a deeply-nested type can have - // multiple BrandArgumentLists that apply to it. - // - // A BrandArgumentList only represents the arguments that the client of the type specified. Since - // new parameters can be added over time, this list may not cover all defined parameters for the - // type. Missing parameters should be treated as AnyPointer. This class's implementation of - // operator[] already does this for you; out-of-bounds access will safely return AnyPointer. - -public: - inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {} - - inline uint size() const { return size_; } - Type operator[](uint index) const; - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - uint64_t scopeId; - uint size_; - bool isUnbound; - const _::RawBrandedSchema::Binding* bindings; - - inline BrandArgumentList(uint64_t scopeId, bool isUnbound) - : scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {} - inline BrandArgumentList(uint64_t scopeId, uint size, - const _::RawBrandedSchema::Binding* bindings) - : scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {} - - friend class Schema; -}; - -// ------------------------------------------------------------------- - -class StructSchema: public Schema { -public: - inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {} - - class Field; - class FieldList; - class FieldSubset; - - FieldList getFields() const; - // List top-level fields of this struct. This list will contain top-level groups (including - // named unions) but not the members of those groups. The list does, however, contain the - // members of the unnamed union, if there is one. - - FieldSubset getUnionFields() const; - // If the field contains an unnamed union, get a list of fields in the union, ordered by - // ordinal. Since discriminant values are assigned sequentially by ordinal, you may index this - // list by discriminant value. - - FieldSubset getNonUnionFields() const; - // Get the fields of this struct which are not in an unnamed union, ordered by ordinal. - - kj::Maybe findFieldByName(kj::StringPtr name) const; - // Find the field with the given name, or return null if there is no such field. If the struct - // contains an unnamed union, then this will find fields of that union in addition to fields - // of the outer struct, since they exist in the same namespace. It will not, however, find - // members of groups (including named unions) -- you must first look up the group itself, - // then dig into its type. - - Field getFieldByName(kj::StringPtr name) const; - // Like findFieldByName() but throws an exception on failure. - - kj::Maybe getFieldByDiscriminant(uint16_t discriminant) const; - // Finds the field whose `discriminantValue` is equal to the given value, or returns null if - // there is no such field. (If the schema does not represent a union or a struct containing - // an unnamed union, then this always returns null.) - -private: - StructSchema(Schema base): Schema(base) {} - template static inline StructSchema fromImpl() { - return StructSchema(Schema(&_::rawBrandedSchema())); - } - friend class Schema; - friend class Type; -}; - -class StructSchema::Field { -public: - Field() = default; - - inline schema::Field::Reader getProto() const { return proto; } - inline StructSchema getContainingStruct() const { return parent; } - - inline uint getIndex() const { return index; } - // Get the index of this field within the containing struct or union. - - Type getType() const; - // Get the type of this field. Note that this is preferred over getProto().getType() as this - // method will apply generics. - - uint32_t getDefaultValueSchemaOffset() const; - // For struct, list, and object fields, returns the offset, in words, within the first segment of - // the struct's schema, where this field's default value pointer is located. The schema is - // always stored as a single-segment unchecked message, which in turn means that the default - // value pointer itself can be treated as the root of an unchecked message -- if you know where - // to find it, which is what this method helps you with. - // - // For blobs, returns the offset of the beginning of the blob's content within the first segment - // of the struct's schema. - // - // This is primarily useful for code generators. The C++ code generator, for example, embeds - // the entire schema as a raw word array within the generated code. Of course, to implement - // field accessors, it needs access to those fields' default values. Embedding separate copies - // of those default values would be redundant since they are already included in the schema, but - // seeking through the schema at runtime to find the default values would be ugly. Instead, - // the code generator can use getDefaultValueSchemaOffset() to find the offset of the default - // value within the schema, and can simply apply that offset at runtime. - // - // If the above does not make sense, you probably don't need this method. - - inline bool operator==(const Field& other) const; - inline bool operator!=(const Field& other) const { return !(*this == other); } - -private: - StructSchema parent; - uint index; - schema::Field::Reader proto; - - inline Field(StructSchema parent, uint index, schema::Field::Reader proto) - : parent(parent), index(index), proto(proto) {} - - friend class StructSchema; -}; - -kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field); - -class StructSchema::FieldList { -public: - FieldList() = default; // empty list - - inline uint size() const { return list.size(); } - inline Field operator[](uint index) const { return Field(parent, index, list[index]); } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - StructSchema parent; - List::Reader list; - - inline FieldList(StructSchema parent, List::Reader list) - : parent(parent), list(list) {} - - friend class StructSchema; -}; - -class StructSchema::FieldSubset { -public: - FieldSubset() = default; // empty list - - inline uint size() const { return size_; } - inline Field operator[](uint index) const { - return Field(parent, indices[index], list[indices[index]]); - } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - StructSchema parent; - List::Reader list; - const uint16_t* indices; - uint size_; - - inline FieldSubset(StructSchema parent, List::Reader list, - const uint16_t* indices, uint size) - : parent(parent), list(list), indices(indices), size_(size) {} - - friend class StructSchema; -}; - -// ------------------------------------------------------------------- - -class EnumSchema: public Schema { -public: - inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {} - - class Enumerant; - class EnumerantList; - - EnumerantList getEnumerants() const; - - kj::Maybe findEnumerantByName(kj::StringPtr name) const; - - Enumerant getEnumerantByName(kj::StringPtr name) const; - // Like findEnumerantByName() but throws an exception on failure. - -private: - EnumSchema(Schema base): Schema(base) {} - template static inline EnumSchema fromImpl() { - return EnumSchema(Schema(&_::rawBrandedSchema())); - } - friend class Schema; - friend class Type; -}; - -class EnumSchema::Enumerant { -public: - Enumerant() = default; - - inline schema::Enumerant::Reader getProto() const { return proto; } - inline EnumSchema getContainingEnum() const { return parent; } - - inline uint16_t getOrdinal() const { return ordinal; } - inline uint getIndex() const { return ordinal; } - - inline bool operator==(const Enumerant& other) const; - inline bool operator!=(const Enumerant& other) const { return !(*this == other); } - -private: - EnumSchema parent; - uint16_t ordinal; - schema::Enumerant::Reader proto; - - inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto) - : parent(parent), ordinal(ordinal), proto(proto) {} - - friend class EnumSchema; -}; - -class EnumSchema::EnumerantList { -public: - EnumerantList() = default; // empty list - - inline uint size() const { return list.size(); } - inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - EnumSchema parent; - List::Reader list; - - inline EnumerantList(EnumSchema parent, List::Reader list) - : parent(parent), list(list) {} - - friend class EnumSchema; -}; - -// ------------------------------------------------------------------- - -class InterfaceSchema: public Schema { -public: - inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {} - - class Method; - class MethodList; - - MethodList getMethods() const; - - kj::Maybe findMethodByName(kj::StringPtr name) const; - - Method getMethodByName(kj::StringPtr name) const; - // Like findMethodByName() but throws an exception on failure. - - class SuperclassList; - - SuperclassList getSuperclasses() const; - // Get the immediate superclasses of this type, after applying generics. - - bool extends(InterfaceSchema other) const; - // Returns true if `other` is a superclass of this interface (including if `other == *this`). - - kj::Maybe findSuperclass(uint64_t typeId) const; - // Find the superclass of this interface with the given type ID. Returns null if the interface - // extends no such type. - -private: - InterfaceSchema(Schema base): Schema(base) {} - template static inline InterfaceSchema fromImpl() { - return InterfaceSchema(Schema(&_::rawBrandedSchema())); - } - friend class Schema; - friend class Type; - - kj::Maybe findMethodByName(kj::StringPtr name, uint& counter) const; - bool extends(InterfaceSchema other, uint& counter) const; - kj::Maybe findSuperclass(uint64_t typeId, uint& counter) const; - // We protect against malicious schemas with large or cyclic hierarchies by cutting off the - // search when the counter reaches a threshold. -}; - -class InterfaceSchema::Method { -public: - Method() = default; - - inline schema::Method::Reader getProto() const { return proto; } - inline InterfaceSchema getContainingInterface() const { return parent; } - - inline uint16_t getOrdinal() const { return ordinal; } - inline uint getIndex() const { return ordinal; } - - StructSchema getParamType() const; - StructSchema getResultType() const; - // Get the parameter and result types, including substituting generic parameters. - - inline bool operator==(const Method& other) const; - inline bool operator!=(const Method& other) const { return !(*this == other); } - -private: - InterfaceSchema parent; - uint16_t ordinal; - schema::Method::Reader proto; - - inline Method(InterfaceSchema parent, uint16_t ordinal, - schema::Method::Reader proto) - : parent(parent), ordinal(ordinal), proto(proto) {} - - friend class InterfaceSchema; -}; - -class InterfaceSchema::MethodList { -public: - MethodList() = default; // empty list - - inline uint size() const { return list.size(); } - inline Method operator[](uint index) const { return Method(parent, index, list[index]); } - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - InterfaceSchema parent; - List::Reader list; - - inline MethodList(InterfaceSchema parent, List::Reader list) - : parent(parent), list(list) {} - - friend class InterfaceSchema; -}; - -class InterfaceSchema::SuperclassList { -public: - SuperclassList() = default; // empty list - - inline uint size() const { return list.size(); } - InterfaceSchema operator[](uint index) const; - - typedef _::IndexingIterator Iterator; - inline Iterator begin() const { return Iterator(this, 0); } - inline Iterator end() const { return Iterator(this, size()); } - -private: - InterfaceSchema parent; - List::Reader list; - - inline SuperclassList(InterfaceSchema parent, List::Reader list) - : parent(parent), list(list) {} - - friend class InterfaceSchema; -}; - -// ------------------------------------------------------------------- - -class ConstSchema: public Schema { - // Represents a constant declaration. - // - // `ConstSchema` can be implicitly cast to DynamicValue to read its value. - -public: - inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {} - - template - ReaderFor as() const; - // Read the constant's value. This is a convenience method equivalent to casting the ConstSchema - // to a DynamicValue and then calling its `as()` method. For dependency reasons, this method - // is defined in , which you must #include explicitly. - - uint32_t getValueSchemaOffset() const; - // Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer - // type, this gets the offset from the beginning of the constant's schema node to a pointer - // representing the constant value. - - Type getType() const; - -private: - ConstSchema(Schema base): Schema(base) {} - friend class Schema; -}; - -// ------------------------------------------------------------------- - -class Type { -public: - struct BrandParameter { - uint64_t scopeId; - uint index; - }; - struct ImplicitParameter { - uint index; - }; - - inline Type(); - inline Type(schema::Type::Which primitive); - inline Type(StructSchema schema); - inline Type(EnumSchema schema); - inline Type(InterfaceSchema schema); - inline Type(ListSchema schema); - inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind); - inline Type(BrandParameter param); - inline Type(ImplicitParameter param); - - template - inline static Type from(); - - inline schema::Type::Which which() const; - - StructSchema asStruct() const; - EnumSchema asEnum() const; - InterfaceSchema asInterface() const; - ListSchema asList() const; - // Each of these methods may only be called if which() returns the corresponding type. - - kj::Maybe getBrandParameter() const; - // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular - // AnyPointer and not a parameter. - - kj::Maybe getImplicitParameter() const; - // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular - // AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods. - - inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const; - // Only callable if which() returns ANY_POINTER. - - inline bool isVoid() const; - inline bool isBool() const; - inline bool isInt8() const; - inline bool isInt16() const; - inline bool isInt32() const; - inline bool isInt64() const; - inline bool isUInt8() const; - inline bool isUInt16() const; - inline bool isUInt32() const; - inline bool isUInt64() const; - inline bool isFloat32() const; - inline bool isFloat64() const; - inline bool isText() const; - inline bool isData() const; - inline bool isList() const; - inline bool isEnum() const; - inline bool isStruct() const; - inline bool isInterface() const; - inline bool isAnyPointer() const; - - bool operator==(const Type& other) const; - inline bool operator!=(const Type& other) const { return !(*this == other); } - - size_t hashCode() const; - - inline Type wrapInList(uint depth = 1) const; - // Return the Type formed by wrapping this type in List() `depth` times. - - inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema); - // For internal use. - -private: - schema::Type::Which baseType; // type not including applications of List() - uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ... - - bool isImplicitParam; - // If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId - // must be zero, and paramIndex indicates the parameter index. - - union { - uint16_t paramIndex; - // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the - // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID - // of the scope where the parameter was defined. - - schema::Type::AnyPointer::Unconstrained::Which anyPointerKind; - // If scopeId is zero and isImplicitParam is false. - }; - - union { - const _::RawBrandedSchema* schema; // if type is struct, enum, interface... - uint64_t scopeId; // if type is AnyPointer but it's actually a type parameter... - }; - - Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema) - : baseType(baseType), listDepth(listDepth), schema(schema) { - KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER); - } - - void requireUsableAs(Type expected) const; - - friend class ListSchema; // only for requireUsableAs() -}; - -// ------------------------------------------------------------------- - -class ListSchema { - // ListSchema is a little different because list types are not described by schema nodes. So, - // ListSchema doesn't subclass Schema. - -public: - ListSchema() = default; - - static ListSchema of(schema::Type::Which primitiveType); - static ListSchema of(StructSchema elementType); - static ListSchema of(EnumSchema elementType); - static ListSchema of(InterfaceSchema elementType); - static ListSchema of(ListSchema elementType); - static ListSchema of(Type elementType); - // Construct the schema for a list of the given type. - - static ListSchema of(schema::Type::Reader elementType, Schema context) - KJ_DEPRECATED("Does not handle generics correctly."); - // DEPRECATED: This method cannot correctly account for generic type parameter bindings that - // may apply to the input type. Instead of using this method, use a method of the Schema API - // that corresponds to the exact kind of dependency. For example, to get a field type, use - // StructSchema::Field::getType(). - // - // Construct from an element type schema. Requires a context which can handle getDependency() - // requests for any type ID found in the schema. - - Type getElementType() const; - - inline schema::Type::Which whichElementType() const; - // Get the element type's "which()". ListSchema does not actually store a schema::Type::Reader - // describing the element type, but if it did, this would be equivalent to calling - // .getBody().which() on that type. - - StructSchema getStructElementType() const; - EnumSchema getEnumElementType() const; - InterfaceSchema getInterfaceElementType() const; - ListSchema getListElementType() const; - // Get the schema for complex element types. Each of these throws an exception if the element - // type is not of the requested kind. - - inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; } - inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; } - - template - void requireUsableAs() const; - -private: - Type elementType; - - inline explicit ListSchema(Type elementType): elementType(elementType) {} - - template - struct FromImpl; - template static inline ListSchema fromImpl() { - return FromImpl::get(); - } - - void requireUsableAs(ListSchema expected) const; - - friend class Schema; -}; - -// ======================================================================================= -// inline implementation - -template <> inline schema::Type::Which Schema::from() { return schema::Type::VOID; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::BOOL; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::INT8; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::INT16; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::INT32; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::INT64; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT8; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT16; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT32; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT64; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT32; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT64; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::TEXT; } -template <> inline schema::Type::Which Schema::from() { return schema::Type::DATA; } - -inline Schema Schema::getDependency(uint64_t id) const { - return getDependency(id, 0); -} - -inline bool Schema::isBranded() const { - return raw != &raw->generic->defaultBrand; -} - -inline Schema Schema::getGeneric() const { - return Schema(&raw->generic->defaultBrand); -} - -template -inline void Schema::requireUsableAs() const { - requireUsableAs(&_::rawSchema()); -} - -inline bool StructSchema::Field::operator==(const Field& other) const { - return parent == other.parent && index == other.index; -} -inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const { - return parent == other.parent && ordinal == other.ordinal; -} -inline bool InterfaceSchema::Method::operator==(const Method& other) const { - return parent == other.parent && ordinal == other.ordinal; -} - -inline ListSchema ListSchema::of(StructSchema elementType) { - return ListSchema(Type(elementType)); -} -inline ListSchema ListSchema::of(EnumSchema elementType) { - return ListSchema(Type(elementType)); -} -inline ListSchema ListSchema::of(InterfaceSchema elementType) { - return ListSchema(Type(elementType)); -} -inline ListSchema ListSchema::of(ListSchema elementType) { - return ListSchema(Type(elementType)); -} -inline ListSchema ListSchema::of(Type elementType) { - return ListSchema(elementType); -} - -inline Type ListSchema::getElementType() const { - return elementType; -} - -inline schema::Type::Which ListSchema::whichElementType() const { - return elementType.which(); -} - -inline StructSchema ListSchema::getStructElementType() const { - return elementType.asStruct(); -} - -inline EnumSchema ListSchema::getEnumElementType() const { - return elementType.asEnum(); -} - -inline InterfaceSchema ListSchema::getInterfaceElementType() const { - return elementType.asInterface(); -} - -inline ListSchema ListSchema::getListElementType() const { - return elementType.asList(); -} - -template -inline void ListSchema::requireUsableAs() const { - static_assert(kind() == Kind::LIST, - "ListSchema::requireUsableAs() requires T is a list type."); - requireUsableAs(Schema::from()); -} - -inline void ListSchema::requireUsableAs(ListSchema expected) const { - elementType.requireUsableAs(expected.elementType); -} - -template -struct ListSchema::FromImpl> { - static inline ListSchema get() { return of(Schema::from()); } -}; - -inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {} -inline Type::Type(schema::Type::Which primitive) - : baseType(primitive), listDepth(0), isImplicitParam(false) { - KJ_IREQUIRE(primitive != schema::Type::STRUCT && - primitive != schema::Type::ENUM && - primitive != schema::Type::INTERFACE && - primitive != schema::Type::LIST); - if (primitive == schema::Type::ANY_POINTER) { - scopeId = 0; - anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND; - } else { - schema = nullptr; - } -} -inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema) - : baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) { - KJ_IREQUIRE(derived == schema::Type::STRUCT || - derived == schema::Type::ENUM || - derived == schema::Type::INTERFACE); -} - -inline Type::Type(StructSchema schema) - : baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {} -inline Type::Type(EnumSchema schema) - : baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {} -inline Type::Type(InterfaceSchema schema) - : baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {} -inline Type::Type(ListSchema schema) - : Type(schema.getElementType()) { ++listDepth; } -inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind) - : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), - anyPointerKind(anyPointerKind), scopeId(0) {} -inline Type::Type(BrandParameter param) - : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), - paramIndex(param.index), scopeId(param.scopeId) {} -inline Type::Type(ImplicitParameter param) - : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true), - paramIndex(param.index), scopeId(0) {} - -inline schema::Type::Which Type::which() const { - return listDepth > 0 ? schema::Type::LIST : baseType; -} - -inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const { - KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER); - return !isImplicitParam && scopeId == 0 ? anyPointerKind - : schema::Type::AnyPointer::Unconstrained::ANY_KIND; -} - -template -inline Type Type::from() { return Type(Schema::from()); } - -inline bool Type::isVoid () const { return baseType == schema::Type::VOID && listDepth == 0; } -inline bool Type::isBool () const { return baseType == schema::Type::BOOL && listDepth == 0; } -inline bool Type::isInt8 () const { return baseType == schema::Type::INT8 && listDepth == 0; } -inline bool Type::isInt16 () const { return baseType == schema::Type::INT16 && listDepth == 0; } -inline bool Type::isInt32 () const { return baseType == schema::Type::INT32 && listDepth == 0; } -inline bool Type::isInt64 () const { return baseType == schema::Type::INT64 && listDepth == 0; } -inline bool Type::isUInt8 () const { return baseType == schema::Type::UINT8 && listDepth == 0; } -inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16 && listDepth == 0; } -inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32 && listDepth == 0; } -inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64 && listDepth == 0; } -inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32 && listDepth == 0; } -inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64 && listDepth == 0; } -inline bool Type::isText () const { return baseType == schema::Type::TEXT && listDepth == 0; } -inline bool Type::isData () const { return baseType == schema::Type::DATA && listDepth == 0; } -inline bool Type::isList () const { return listDepth > 0; } -inline bool Type::isEnum () const { return baseType == schema::Type::ENUM && listDepth == 0; } -inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT && listDepth == 0; } -inline bool Type::isInterface() const { - return baseType == schema::Type::INTERFACE && listDepth == 0; -} -inline bool Type::isAnyPointer() const { - return baseType == schema::Type::ANY_POINTER && listDepth == 0; -} - -inline Type Type::wrapInList(uint depth) const { - Type result = *this; - result.listDepth += depth; - return result; -} - -} // namespace capnp - -#endif // CAPNP_SCHEMA_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_H_ +#define CAPNP_SCHEMA_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#if CAPNP_LITE +#error "Reflection APIs, including this header, are not available in lite mode." +#endif + +#include + +namespace capnp { + +class Schema; +class StructSchema; +class EnumSchema; +class InterfaceSchema; +class ConstSchema; +class ListSchema; +class Type; + +template ()> struct SchemaType_ { typedef Schema Type; }; +template struct SchemaType_ { typedef schema::Type::Which Type; }; +template struct SchemaType_ { typedef schema::Type::Which Type; }; +template struct SchemaType_ { typedef EnumSchema Type; }; +template struct SchemaType_ { typedef StructSchema Type; }; +template struct SchemaType_ { typedef InterfaceSchema Type; }; +template struct SchemaType_ { typedef ListSchema Type; }; + +template +using SchemaType = typename SchemaType_::Type; +// SchemaType is the type of T's schema, e.g. StructSchema if T is a struct. + +namespace _ { // private +extern const RawSchema NULL_SCHEMA; +extern const RawSchema NULL_STRUCT_SCHEMA; +extern const RawSchema NULL_ENUM_SCHEMA; +extern const RawSchema NULL_INTERFACE_SCHEMA; +extern const RawSchema NULL_CONST_SCHEMA; +// The schema types default to these null (empty) schemas in case of error, especially when +// exceptions are disabled. +} // namespace _ (private) + +class Schema { + // Convenience wrapper around capnp::schema::Node. + +public: + inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {} + + template + static inline SchemaType from() { return SchemaType::template fromImpl(); } + // Get the Schema for a particular compiled-in type. + + schema::Node::Reader getProto() const; + // Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor + // has performance comparable to accessors of struct-typed fields on Reader classes.) + + kj::ArrayPtr asUncheckedMessage() const; + // Get the encoded schema node content as a single message segment. It is safe to read as an + // unchecked message. + + Schema getDependency(uint64_t id) const KJ_DEPRECATED("Does not handle generics correctly."); + // DEPRECATED: This method cannot correctly account for generic type parameter bindings that + // may apply to the dependency. Instead of using this method, use a method of the Schema API + // that corresponds to the exact kind of dependency. For example, to get a field type, use + // StructSchema::Field::getType(). + // + // Gets the Schema for one of this Schema's dependencies. For example, if this Schema is for a + // struct, you could look up the schema for one of its fields' types. Throws an exception if this + // schema doesn't actually depend on the given id. + // + // Note that not all type IDs found in the schema node are considered "dependencies" -- only the + // ones that are needed to implement the dynamic API are. That includes: + // - Field types. + // - Group types. + // - scopeId for group nodes, but NOT otherwise. + // - Method parameter and return types. + // + // The following are NOT considered dependencies: + // - Nested nodes. + // - scopeId for a non-group node. + // - Annotations. + // + // To obtain schemas for those, you would need a SchemaLoader. + + bool isBranded() const; + // Returns true if this schema represents a non-default parameterization of this type. + + Schema getGeneric() const; + // Get the version of this schema with any brands removed. + + class BrandArgumentList; + BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const; + // Gets the values bound to the brand parameters at the given scope. + + StructSchema asStruct() const; + EnumSchema asEnum() const; + InterfaceSchema asInterface() const; + ConstSchema asConst() const; + // Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use + // getProto() to determine type, e.g. getProto().isStruct(). + + inline bool operator==(const Schema& other) const { return raw == other.raw; } + inline bool operator!=(const Schema& other) const { return raw != other.raw; } + // Determine whether two Schemas are wrapping the exact same underlying data, by identity. If + // you want to check if two Schemas represent the same type (but possibly different versions of + // it), compare their IDs instead. + + template + void requireUsableAs() const; + // Throws an exception if a value with this Schema cannot safely be cast to a native value of + // the given type. This passes if either: + // - *this == from() + // - This schema was loaded with SchemaLoader, the type ID matches typeId(), and + // loadCompiledTypeAndDependencies() was called on the SchemaLoader. + + kj::StringPtr getShortDisplayName() const; + // Get the short version of the node's display name. + +private: + const _::RawBrandedSchema* raw; + + inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) { + KJ_IREQUIRE(raw->lazyInitializer == nullptr, + "Must call ensureInitialized() on RawSchema before constructing Schema."); + } + + template static inline Schema fromImpl() { + return Schema(&_::rawSchema()); + } + + void requireUsableAs(const _::RawSchema* expected) const; + + uint32_t getSchemaOffset(const schema::Value::Reader& value) const; + + Type getBrandBinding(uint64_t scopeId, uint index) const; + // Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the + // parameter is not bound. + // + // TODO(someday): Public interface for iterating over all bindings? + + Schema getDependency(uint64_t id, uint location) const; + // Look up schema for a particular dependency of this schema. `location` is the dependency + // location number as defined in _::RawBrandedSchema. + + Type interpretType(schema::Type::Reader proto, uint location) const; + // Interpret a schema::Type in the given location within the schema, compiling it into a + // Type object. + + friend class StructSchema; + friend class EnumSchema; + friend class InterfaceSchema; + friend class ConstSchema; + friend class ListSchema; + friend class SchemaLoader; + friend class Type; + friend kj::StringTree _::structString( + _::StructReader reader, const _::RawBrandedSchema& schema); + friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema); +}; + +kj::StringPtr KJ_STRINGIFY(const Schema& schema); + +class Schema::BrandArgumentList { + // A list of generic parameter bindings for parameters of some particular type. Note that since + // parameters on an outer type apply to all inner types as well, a deeply-nested type can have + // multiple BrandArgumentLists that apply to it. + // + // A BrandArgumentList only represents the arguments that the client of the type specified. Since + // new parameters can be added over time, this list may not cover all defined parameters for the + // type. Missing parameters should be treated as AnyPointer. This class's implementation of + // operator[] already does this for you; out-of-bounds access will safely return AnyPointer. + +public: + inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {} + + inline uint size() const { return size_; } + Type operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + uint64_t scopeId; + uint size_; + bool isUnbound; + const _::RawBrandedSchema::Binding* bindings; + + inline BrandArgumentList(uint64_t scopeId, bool isUnbound) + : scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {} + inline BrandArgumentList(uint64_t scopeId, uint size, + const _::RawBrandedSchema::Binding* bindings) + : scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {} + + friend class Schema; +}; + +// ------------------------------------------------------------------- + +class StructSchema: public Schema { +public: + inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {} + + class Field; + class FieldList; + class FieldSubset; + + FieldList getFields() const; + // List top-level fields of this struct. This list will contain top-level groups (including + // named unions) but not the members of those groups. The list does, however, contain the + // members of the unnamed union, if there is one. + + FieldSubset getUnionFields() const; + // If the field contains an unnamed union, get a list of fields in the union, ordered by + // ordinal. Since discriminant values are assigned sequentially by ordinal, you may index this + // list by discriminant value. + + FieldSubset getNonUnionFields() const; + // Get the fields of this struct which are not in an unnamed union, ordered by ordinal. + + kj::Maybe findFieldByName(kj::StringPtr name) const; + // Find the field with the given name, or return null if there is no such field. If the struct + // contains an unnamed union, then this will find fields of that union in addition to fields + // of the outer struct, since they exist in the same namespace. It will not, however, find + // members of groups (including named unions) -- you must first look up the group itself, + // then dig into its type. + + Field getFieldByName(kj::StringPtr name) const; + // Like findFieldByName() but throws an exception on failure. + + kj::Maybe getFieldByDiscriminant(uint16_t discriminant) const; + // Finds the field whose `discriminantValue` is equal to the given value, or returns null if + // there is no such field. (If the schema does not represent a union or a struct containing + // an unnamed union, then this always returns null.) + +private: + StructSchema(Schema base): Schema(base) {} + template static inline StructSchema fromImpl() { + return StructSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; +}; + +class StructSchema::Field { +public: + Field() = default; + + inline schema::Field::Reader getProto() const { return proto; } + inline StructSchema getContainingStruct() const { return parent; } + + inline uint getIndex() const { return index; } + // Get the index of this field within the containing struct or union. + + Type getType() const; + // Get the type of this field. Note that this is preferred over getProto().getType() as this + // method will apply generics. + + uint32_t getDefaultValueSchemaOffset() const; + // For struct, list, and object fields, returns the offset, in words, within the first segment of + // the struct's schema, where this field's default value pointer is located. The schema is + // always stored as a single-segment unchecked message, which in turn means that the default + // value pointer itself can be treated as the root of an unchecked message -- if you know where + // to find it, which is what this method helps you with. + // + // For blobs, returns the offset of the beginning of the blob's content within the first segment + // of the struct's schema. + // + // This is primarily useful for code generators. The C++ code generator, for example, embeds + // the entire schema as a raw word array within the generated code. Of course, to implement + // field accessors, it needs access to those fields' default values. Embedding separate copies + // of those default values would be redundant since they are already included in the schema, but + // seeking through the schema at runtime to find the default values would be ugly. Instead, + // the code generator can use getDefaultValueSchemaOffset() to find the offset of the default + // value within the schema, and can simply apply that offset at runtime. + // + // If the above does not make sense, you probably don't need this method. + + inline bool operator==(const Field& other) const; + inline bool operator!=(const Field& other) const { return !(*this == other); } + +private: + StructSchema parent; + uint index; + schema::Field::Reader proto; + + inline Field(StructSchema parent, uint index, schema::Field::Reader proto) + : parent(parent), index(index), proto(proto) {} + + friend class StructSchema; +}; + +kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field); + +class StructSchema::FieldList { +public: + FieldList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Field operator[](uint index) const { return Field(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + StructSchema parent; + List::Reader list; + + inline FieldList(StructSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class StructSchema; +}; + +class StructSchema::FieldSubset { +public: + FieldSubset() = default; // empty list + + inline uint size() const { return size_; } + inline Field operator[](uint index) const { + return Field(parent, indices[index], list[indices[index]]); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + StructSchema parent; + List::Reader list; + const uint16_t* indices; + uint size_; + + inline FieldSubset(StructSchema parent, List::Reader list, + const uint16_t* indices, uint size) + : parent(parent), list(list), indices(indices), size_(size) {} + + friend class StructSchema; +}; + +// ------------------------------------------------------------------- + +class EnumSchema: public Schema { +public: + inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {} + + class Enumerant; + class EnumerantList; + + EnumerantList getEnumerants() const; + + kj::Maybe findEnumerantByName(kj::StringPtr name) const; + + Enumerant getEnumerantByName(kj::StringPtr name) const; + // Like findEnumerantByName() but throws an exception on failure. + +private: + EnumSchema(Schema base): Schema(base) {} + template static inline EnumSchema fromImpl() { + return EnumSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; +}; + +class EnumSchema::Enumerant { +public: + Enumerant() = default; + + inline schema::Enumerant::Reader getProto() const { return proto; } + inline EnumSchema getContainingEnum() const { return parent; } + + inline uint16_t getOrdinal() const { return ordinal; } + inline uint getIndex() const { return ordinal; } + + inline bool operator==(const Enumerant& other) const; + inline bool operator!=(const Enumerant& other) const { return !(*this == other); } + +private: + EnumSchema parent; + uint16_t ordinal; + schema::Enumerant::Reader proto; + + inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto) + : parent(parent), ordinal(ordinal), proto(proto) {} + + friend class EnumSchema; +}; + +class EnumSchema::EnumerantList { +public: + EnumerantList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + EnumSchema parent; + List::Reader list; + + inline EnumerantList(EnumSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class EnumSchema; +}; + +// ------------------------------------------------------------------- + +class InterfaceSchema: public Schema { +public: + inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {} + + class Method; + class MethodList; + + MethodList getMethods() const; + + kj::Maybe findMethodByName(kj::StringPtr name) const; + + Method getMethodByName(kj::StringPtr name) const; + // Like findMethodByName() but throws an exception on failure. + + class SuperclassList; + + SuperclassList getSuperclasses() const; + // Get the immediate superclasses of this type, after applying generics. + + bool extends(InterfaceSchema other) const; + // Returns true if `other` is a superclass of this interface (including if `other == *this`). + + kj::Maybe findSuperclass(uint64_t typeId) const; + // Find the superclass of this interface with the given type ID. Returns null if the interface + // extends no such type. + +private: + InterfaceSchema(Schema base): Schema(base) {} + template static inline InterfaceSchema fromImpl() { + return InterfaceSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; + + kj::Maybe findMethodByName(kj::StringPtr name, uint& counter) const; + bool extends(InterfaceSchema other, uint& counter) const; + kj::Maybe findSuperclass(uint64_t typeId, uint& counter) const; + // We protect against malicious schemas with large or cyclic hierarchies by cutting off the + // search when the counter reaches a threshold. +}; + +class InterfaceSchema::Method { +public: + Method() = default; + + inline schema::Method::Reader getProto() const { return proto; } + inline InterfaceSchema getContainingInterface() const { return parent; } + + inline uint16_t getOrdinal() const { return ordinal; } + inline uint getIndex() const { return ordinal; } + + StructSchema getParamType() const; + StructSchema getResultType() const; + // Get the parameter and result types, including substituting generic parameters. + + inline bool operator==(const Method& other) const; + inline bool operator!=(const Method& other) const { return !(*this == other); } + +private: + InterfaceSchema parent; + uint16_t ordinal; + schema::Method::Reader proto; + + inline Method(InterfaceSchema parent, uint16_t ordinal, + schema::Method::Reader proto) + : parent(parent), ordinal(ordinal), proto(proto) {} + + friend class InterfaceSchema; +}; + +class InterfaceSchema::MethodList { +public: + MethodList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Method operator[](uint index) const { return Method(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + InterfaceSchema parent; + List::Reader list; + + inline MethodList(InterfaceSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class InterfaceSchema; +}; + +class InterfaceSchema::SuperclassList { +public: + SuperclassList() = default; // empty list + + inline uint size() const { return list.size(); } + InterfaceSchema operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + InterfaceSchema parent; + List::Reader list; + + inline SuperclassList(InterfaceSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class InterfaceSchema; +}; + +// ------------------------------------------------------------------- + +class ConstSchema: public Schema { + // Represents a constant declaration. + // + // `ConstSchema` can be implicitly cast to DynamicValue to read its value. + +public: + inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {} + + template + ReaderFor as() const; + // Read the constant's value. This is a convenience method equivalent to casting the ConstSchema + // to a DynamicValue and then calling its `as()` method. For dependency reasons, this method + // is defined in , which you must #include explicitly. + + uint32_t getValueSchemaOffset() const; + // Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer + // type, this gets the offset from the beginning of the constant's schema node to a pointer + // representing the constant value. + + Type getType() const; + +private: + ConstSchema(Schema base): Schema(base) {} + friend class Schema; +}; + +// ------------------------------------------------------------------- + +class Type { +public: + struct BrandParameter { + uint64_t scopeId; + uint index; + }; + struct ImplicitParameter { + uint index; + }; + + inline Type(); + inline Type(schema::Type::Which primitive); + inline Type(StructSchema schema); + inline Type(EnumSchema schema); + inline Type(InterfaceSchema schema); + inline Type(ListSchema schema); + inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind); + inline Type(BrandParameter param); + inline Type(ImplicitParameter param); + + template + inline static Type from(); + + inline schema::Type::Which which() const; + + StructSchema asStruct() const; + EnumSchema asEnum() const; + InterfaceSchema asInterface() const; + ListSchema asList() const; + // Each of these methods may only be called if which() returns the corresponding type. + + kj::Maybe getBrandParameter() const; + // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular + // AnyPointer and not a parameter. + + kj::Maybe getImplicitParameter() const; + // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular + // AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods. + + inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const; + // Only callable if which() returns ANY_POINTER. + + inline bool isVoid() const; + inline bool isBool() const; + inline bool isInt8() const; + inline bool isInt16() const; + inline bool isInt32() const; + inline bool isInt64() const; + inline bool isUInt8() const; + inline bool isUInt16() const; + inline bool isUInt32() const; + inline bool isUInt64() const; + inline bool isFloat32() const; + inline bool isFloat64() const; + inline bool isText() const; + inline bool isData() const; + inline bool isList() const; + inline bool isEnum() const; + inline bool isStruct() const; + inline bool isInterface() const; + inline bool isAnyPointer() const; + + bool operator==(const Type& other) const; + inline bool operator!=(const Type& other) const { return !(*this == other); } + + size_t hashCode() const; + + inline Type wrapInList(uint depth = 1) const; + // Return the Type formed by wrapping this type in List() `depth` times. + + inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema); + // For internal use. + +private: + schema::Type::Which baseType; // type not including applications of List() + uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ... + + bool isImplicitParam; + // If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId + // must be zero, and paramIndex indicates the parameter index. + + union { + uint16_t paramIndex; + // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the + // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID + // of the scope where the parameter was defined. + + schema::Type::AnyPointer::Unconstrained::Which anyPointerKind; + // If scopeId is zero and isImplicitParam is false. + }; + + union { + const _::RawBrandedSchema* schema; // if type is struct, enum, interface... + uint64_t scopeId; // if type is AnyPointer but it's actually a type parameter... + }; + + Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema) + : baseType(baseType), listDepth(listDepth), schema(schema) { + KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER); + } + + void requireUsableAs(Type expected) const; + + friend class ListSchema; // only for requireUsableAs() +}; + +// ------------------------------------------------------------------- + +class ListSchema { + // ListSchema is a little different because list types are not described by schema nodes. So, + // ListSchema doesn't subclass Schema. + +public: + ListSchema() = default; + + static ListSchema of(schema::Type::Which primitiveType); + static ListSchema of(StructSchema elementType); + static ListSchema of(EnumSchema elementType); + static ListSchema of(InterfaceSchema elementType); + static ListSchema of(ListSchema elementType); + static ListSchema of(Type elementType); + // Construct the schema for a list of the given type. + + static ListSchema of(schema::Type::Reader elementType, Schema context) + KJ_DEPRECATED("Does not handle generics correctly."); + // DEPRECATED: This method cannot correctly account for generic type parameter bindings that + // may apply to the input type. Instead of using this method, use a method of the Schema API + // that corresponds to the exact kind of dependency. For example, to get a field type, use + // StructSchema::Field::getType(). + // + // Construct from an element type schema. Requires a context which can handle getDependency() + // requests for any type ID found in the schema. + + Type getElementType() const; + + inline schema::Type::Which whichElementType() const; + // Get the element type's "which()". ListSchema does not actually store a schema::Type::Reader + // describing the element type, but if it did, this would be equivalent to calling + // .getBody().which() on that type. + + StructSchema getStructElementType() const; + EnumSchema getEnumElementType() const; + InterfaceSchema getInterfaceElementType() const; + ListSchema getListElementType() const; + // Get the schema for complex element types. Each of these throws an exception if the element + // type is not of the requested kind. + + inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; } + inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; } + + template + void requireUsableAs() const; + +private: + Type elementType; + + inline explicit ListSchema(Type elementType): elementType(elementType) {} + + template + struct FromImpl; + template static inline ListSchema fromImpl() { + return FromImpl::get(); + } + + void requireUsableAs(ListSchema expected) const; + + friend class Schema; +}; + +// ======================================================================================= +// inline implementation + +template <> inline schema::Type::Which Schema::from() { return schema::Type::VOID; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::BOOL; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT8; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT16; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT8; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT16; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::TEXT; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::DATA; } + +inline Schema Schema::getDependency(uint64_t id) const { + return getDependency(id, 0); +} + +inline bool Schema::isBranded() const { + return raw != &raw->generic->defaultBrand; +} + +inline Schema Schema::getGeneric() const { + return Schema(&raw->generic->defaultBrand); +} + +template +inline void Schema::requireUsableAs() const { + requireUsableAs(&_::rawSchema()); +} + +inline bool StructSchema::Field::operator==(const Field& other) const { + return parent == other.parent && index == other.index; +} +inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const { + return parent == other.parent && ordinal == other.ordinal; +} +inline bool InterfaceSchema::Method::operator==(const Method& other) const { + return parent == other.parent && ordinal == other.ordinal; +} + +inline ListSchema ListSchema::of(StructSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(EnumSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(InterfaceSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(ListSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(Type elementType) { + return ListSchema(elementType); +} + +inline Type ListSchema::getElementType() const { + return elementType; +} + +inline schema::Type::Which ListSchema::whichElementType() const { + return elementType.which(); +} + +inline StructSchema ListSchema::getStructElementType() const { + return elementType.asStruct(); +} + +inline EnumSchema ListSchema::getEnumElementType() const { + return elementType.asEnum(); +} + +inline InterfaceSchema ListSchema::getInterfaceElementType() const { + return elementType.asInterface(); +} + +inline ListSchema ListSchema::getListElementType() const { + return elementType.asList(); +} + +template +inline void ListSchema::requireUsableAs() const { + static_assert(kind() == Kind::LIST, + "ListSchema::requireUsableAs() requires T is a list type."); + requireUsableAs(Schema::from()); +} + +inline void ListSchema::requireUsableAs(ListSchema expected) const { + elementType.requireUsableAs(expected.elementType); +} + +template +struct ListSchema::FromImpl> { + static inline ListSchema get() { return of(Schema::from()); } +}; + +inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {} +inline Type::Type(schema::Type::Which primitive) + : baseType(primitive), listDepth(0), isImplicitParam(false) { + KJ_IREQUIRE(primitive != schema::Type::STRUCT && + primitive != schema::Type::ENUM && + primitive != schema::Type::INTERFACE && + primitive != schema::Type::LIST); + if (primitive == schema::Type::ANY_POINTER) { + scopeId = 0; + anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND; + } else { + schema = nullptr; + } +} +inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema) + : baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) { + KJ_IREQUIRE(derived == schema::Type::STRUCT || + derived == schema::Type::ENUM || + derived == schema::Type::INTERFACE); +} + +inline Type::Type(StructSchema schema) + : baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {} +inline Type::Type(EnumSchema schema) + : baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {} +inline Type::Type(InterfaceSchema schema) + : baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {} +inline Type::Type(ListSchema schema) + : Type(schema.getElementType()) { ++listDepth; } +inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), + anyPointerKind(anyPointerKind), scopeId(0) {} +inline Type::Type(BrandParameter param) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), + paramIndex(param.index), scopeId(param.scopeId) {} +inline Type::Type(ImplicitParameter param) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true), + paramIndex(param.index), scopeId(0) {} + +inline schema::Type::Which Type::which() const { + return listDepth > 0 ? schema::Type::LIST : baseType; +} + +inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const { + KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER); + return !isImplicitParam && scopeId == 0 ? anyPointerKind + : schema::Type::AnyPointer::Unconstrained::ANY_KIND; +} + +template +inline Type Type::from() { return Type(Schema::from()); } + +inline bool Type::isVoid () const { return baseType == schema::Type::VOID && listDepth == 0; } +inline bool Type::isBool () const { return baseType == schema::Type::BOOL && listDepth == 0; } +inline bool Type::isInt8 () const { return baseType == schema::Type::INT8 && listDepth == 0; } +inline bool Type::isInt16 () const { return baseType == schema::Type::INT16 && listDepth == 0; } +inline bool Type::isInt32 () const { return baseType == schema::Type::INT32 && listDepth == 0; } +inline bool Type::isInt64 () const { return baseType == schema::Type::INT64 && listDepth == 0; } +inline bool Type::isUInt8 () const { return baseType == schema::Type::UINT8 && listDepth == 0; } +inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16 && listDepth == 0; } +inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32 && listDepth == 0; } +inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64 && listDepth == 0; } +inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32 && listDepth == 0; } +inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64 && listDepth == 0; } +inline bool Type::isText () const { return baseType == schema::Type::TEXT && listDepth == 0; } +inline bool Type::isData () const { return baseType == schema::Type::DATA && listDepth == 0; } +inline bool Type::isList () const { return listDepth > 0; } +inline bool Type::isEnum () const { return baseType == schema::Type::ENUM && listDepth == 0; } +inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT && listDepth == 0; } +inline bool Type::isInterface() const { + return baseType == schema::Type::INTERFACE && listDepth == 0; +} +inline bool Type::isAnyPointer() const { + return baseType == schema::Type::ANY_POINTER && listDepth == 0; +} + +inline Type Type::wrapInList(uint depth) const { + Type result = *this; + result.listDepth += depth; + return result; +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/serialize-async.h --- a/osx/include/capnp/serialize-async.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/serialize-async.h Mon May 22 10:01:37 2017 +0100 @@ -1,64 +1,64 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SERIALIZE_ASYNC_H_ -#define CAPNP_SERIALIZE_ASYNC_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include "message.h" - -namespace capnp { - -kj::Promise> readMessage( - kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); -// Read a message asynchronously. -// -// `input` must remain valid until the returned promise resolves (or is canceled). -// -// `scratchSpace`, if provided, must remain valid until the returned MessageReader is destroyed. - -kj::Promise>> tryReadMessage( - kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); -// Like `readMessage` but returns null on EOF. - -kj::Promise writeMessage(kj::AsyncOutputStream& output, - kj::ArrayPtr> segments) - KJ_WARN_UNUSED_RESULT; -kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) - KJ_WARN_UNUSED_RESULT; -// Write asynchronously. The parameters must remain valid until the returned promise resolves. - -// ======================================================================================= -// inline implementation details - -inline kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) { - return writeMessage(output, builder.getSegmentsForOutput()); -} - -} // namespace capnp - -#endif // CAPNP_SERIALIZE_ASYNC_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_ASYNC_H_ +#define CAPNP_SERIALIZE_ASYNC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "message.h" + +namespace capnp { + +kj::Promise> readMessage( + kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Read a message asynchronously. +// +// `input` must remain valid until the returned promise resolves (or is canceled). +// +// `scratchSpace`, if provided, must remain valid until the returned MessageReader is destroyed. + +kj::Promise>> tryReadMessage( + kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Like `readMessage` but returns null on EOF. + +kj::Promise writeMessage(kj::AsyncOutputStream& output, + kj::ArrayPtr> segments) + KJ_WARN_UNUSED_RESULT; +kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) + KJ_WARN_UNUSED_RESULT; +// Write asynchronously. The parameters must remain valid until the returned promise resolves. + +// ======================================================================================= +// inline implementation details + +inline kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) { + return writeMessage(output, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_ASYNC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/serialize-packed.h --- a/osx/include/capnp/serialize-packed.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/serialize-packed.h Mon May 22 10:01:37 2017 +0100 @@ -1,130 +1,130 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SERIALIZE_PACKED_H_ -#define CAPNP_SERIALIZE_PACKED_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "serialize.h" - -namespace capnp { - -namespace _ { // private - -class PackedInputStream: public kj::InputStream { - // An input stream that unpacks packed data with a picky constraint: The caller must read data - // in the exact same size and sequence as the data was written to PackedOutputStream. - -public: - explicit PackedInputStream(kj::BufferedInputStream& inner); - KJ_DISALLOW_COPY(PackedInputStream); - ~PackedInputStream() noexcept(false); - - // implements InputStream ------------------------------------------ - size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; - void skip(size_t bytes) override; - -private: - kj::BufferedInputStream& inner; -}; - -class PackedOutputStream: public kj::OutputStream { -public: - explicit PackedOutputStream(kj::BufferedOutputStream& inner); - KJ_DISALLOW_COPY(PackedOutputStream); - ~PackedOutputStream() noexcept(false); - - // implements OutputStream ----------------------------------------- - void write(const void* buffer, size_t bytes) override; - -private: - kj::BufferedOutputStream& inner; -}; - -} // namespace _ (private) - -class PackedMessageReader: private _::PackedInputStream, public InputStreamMessageReader { -public: - PackedMessageReader(kj::BufferedInputStream& inputStream, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); - KJ_DISALLOW_COPY(PackedMessageReader); - ~PackedMessageReader() noexcept(false); -}; - -class PackedFdMessageReader: private kj::FdInputStream, private kj::BufferedInputStreamWrapper, - public PackedMessageReader { -public: - PackedFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); - // Read message from a file descriptor, without taking ownership of the descriptor. - // Note that if you want to reuse the descriptor after the reader is destroyed, you'll need to - // seek it, since otherwise the position is unspecified. - - PackedFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); - // Read a message from a file descriptor, taking ownership of the descriptor. - - KJ_DISALLOW_COPY(PackedFdMessageReader); - - ~PackedFdMessageReader() noexcept(false); -}; - -void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder); -void writePackedMessage(kj::BufferedOutputStream& output, - kj::ArrayPtr> segments); -// Write a packed message to a buffered output stream. - -void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder); -void writePackedMessage(kj::OutputStream& output, - kj::ArrayPtr> segments); -// Write a packed message to an unbuffered output stream. If you intend to write multiple messages -// in succession, consider wrapping your output in a buffered stream in order to reduce system -// call overhead. - -void writePackedMessageToFd(int fd, MessageBuilder& builder); -void writePackedMessageToFd(int fd, kj::ArrayPtr> segments); -// Write a single packed message to the file descriptor. - -size_t computeUnpackedSizeInWords(kj::ArrayPtr packedBytes); -// Computes the number of words to which the given packed bytes will unpack. Not intended for use -// in performance-sensitive situations. - -// ======================================================================================= -// inline stuff - -inline void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder) { - writePackedMessage(output, builder.getSegmentsForOutput()); -} - -inline void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder) { - writePackedMessage(output, builder.getSegmentsForOutput()); -} - -inline void writePackedMessageToFd(int fd, MessageBuilder& builder) { - writePackedMessageToFd(fd, builder.getSegmentsForOutput()); -} - -} // namespace capnp - -#endif // CAPNP_SERIALIZE_PACKED_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_PACKED_H_ +#define CAPNP_SERIALIZE_PACKED_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "serialize.h" + +namespace capnp { + +namespace _ { // private + +class PackedInputStream: public kj::InputStream { + // An input stream that unpacks packed data with a picky constraint: The caller must read data + // in the exact same size and sequence as the data was written to PackedOutputStream. + +public: + explicit PackedInputStream(kj::BufferedInputStream& inner); + KJ_DISALLOW_COPY(PackedInputStream); + ~PackedInputStream() noexcept(false); + + // implements InputStream ------------------------------------------ + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + kj::BufferedInputStream& inner; +}; + +class PackedOutputStream: public kj::OutputStream { +public: + explicit PackedOutputStream(kj::BufferedOutputStream& inner); + KJ_DISALLOW_COPY(PackedOutputStream); + ~PackedOutputStream() noexcept(false); + + // implements OutputStream ----------------------------------------- + void write(const void* buffer, size_t bytes) override; + +private: + kj::BufferedOutputStream& inner; +}; + +} // namespace _ (private) + +class PackedMessageReader: private _::PackedInputStream, public InputStreamMessageReader { +public: + PackedMessageReader(kj::BufferedInputStream& inputStream, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + KJ_DISALLOW_COPY(PackedMessageReader); + ~PackedMessageReader() noexcept(false); +}; + +class PackedFdMessageReader: private kj::FdInputStream, private kj::BufferedInputStreamWrapper, + public PackedMessageReader { +public: + PackedFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + // Read message from a file descriptor, without taking ownership of the descriptor. + // Note that if you want to reuse the descriptor after the reader is destroyed, you'll need to + // seek it, since otherwise the position is unspecified. + + PackedFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + // Read a message from a file descriptor, taking ownership of the descriptor. + + KJ_DISALLOW_COPY(PackedFdMessageReader); + + ~PackedFdMessageReader() noexcept(false); +}; + +void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder); +void writePackedMessage(kj::BufferedOutputStream& output, + kj::ArrayPtr> segments); +// Write a packed message to a buffered output stream. + +void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder); +void writePackedMessage(kj::OutputStream& output, + kj::ArrayPtr> segments); +// Write a packed message to an unbuffered output stream. If you intend to write multiple messages +// in succession, consider wrapping your output in a buffered stream in order to reduce system +// call overhead. + +void writePackedMessageToFd(int fd, MessageBuilder& builder); +void writePackedMessageToFd(int fd, kj::ArrayPtr> segments); +// Write a single packed message to the file descriptor. + +size_t computeUnpackedSizeInWords(kj::ArrayPtr packedBytes); +// Computes the number of words to which the given packed bytes will unpack. Not intended for use +// in performance-sensitive situations. + +// ======================================================================================= +// inline stuff + +inline void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder.getSegmentsForOutput()); +} + +inline void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder.getSegmentsForOutput()); +} + +inline void writePackedMessageToFd(int fd, MessageBuilder& builder) { + writePackedMessageToFd(fd, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_PACKED_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/serialize-text.h --- a/osx/include/capnp/serialize-text.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/serialize-text.h Mon May 22 10:01:37 2017 +0100 @@ -1,96 +1,96 @@ -// Copyright (c) 2015 Philip Quinn. -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_SERIALIZE_TEXT_H_ -#define CAPNP_SERIALIZE_TEXT_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include "dynamic.h" -#include "orphan.h" -#include "schema.h" - -namespace capnp { - -class TextCodec { - // Reads and writes Cap'n Proto objects in a plain text format (as used in the schema - // language for constants, and read/written by the 'decode' and 'encode' commands of - // the capnp tool). - // - // This format is useful for debugging or human input, but it is not a robust alternative - // to the binary format. Changes to a schema's types or names that are permitted in a - // schema's binary evolution will likely break messages stored in this format. - // - // Note that definitions or references (to constants, other fields, or files) are not - // permitted in this format. To evaluate declarations with the full expressiveness of the - // schema language, see `capnp::SchemaParser`. - // - // Requires linking with the capnpc library. - -public: - TextCodec(); - ~TextCodec() noexcept(true); - - void setPrettyPrint(bool enabled); - // If enabled, pads the output of `encode()` with spaces and newlines to make it more - // human-readable. - - template - kj::String encode(T&& value) const; - kj::String encode(DynamicValue::Reader value) const; - // Encode any Cap'n Proto value. - - template - Orphan decode(kj::StringPtr input, Orphanage orphanage) const; - // Decode a text message into a Cap'n Proto object of type T, allocated in the given - // orphanage. Any errors parsing the input or assigning the fields of T are thrown as - // exceptions. - - void decode(kj::StringPtr input, DynamicStruct::Builder output) const; - // Decode a text message for a struct into the given builder. Any errors parsing the - // input or assigning the fields of the output are thrown as exceptions. - - // TODO(someday): expose some control over the error handling? -private: - Orphan decode(kj::StringPtr input, Type type, Orphanage orphanage) const; - - bool prettyPrint; -}; - -// ======================================================================================= -// inline stuff - -template -inline kj::String TextCodec::encode(T&& value) const { - return encode(DynamicValue::Reader(ReaderFor>(kj::fwd(value)))); -} - -template -inline Orphan TextCodec::decode(kj::StringPtr input, Orphanage orphanage) const { - return decode(input, Type::from(), orphanage).template releaseAs(); -} - -} // namespace capnp - -#endif // CAPNP_SERIALIZE_TEXT_H_ +// Copyright (c) 2015 Philip Quinn. +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_TEXT_H_ +#define CAPNP_SERIALIZE_TEXT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "dynamic.h" +#include "orphan.h" +#include "schema.h" + +namespace capnp { + +class TextCodec { + // Reads and writes Cap'n Proto objects in a plain text format (as used in the schema + // language for constants, and read/written by the 'decode' and 'encode' commands of + // the capnp tool). + // + // This format is useful for debugging or human input, but it is not a robust alternative + // to the binary format. Changes to a schema's types or names that are permitted in a + // schema's binary evolution will likely break messages stored in this format. + // + // Note that definitions or references (to constants, other fields, or files) are not + // permitted in this format. To evaluate declarations with the full expressiveness of the + // schema language, see `capnp::SchemaParser`. + // + // Requires linking with the capnpc library. + +public: + TextCodec(); + ~TextCodec() noexcept(true); + + void setPrettyPrint(bool enabled); + // If enabled, pads the output of `encode()` with spaces and newlines to make it more + // human-readable. + + template + kj::String encode(T&& value) const; + kj::String encode(DynamicValue::Reader value) const; + // Encode any Cap'n Proto value. + + template + Orphan decode(kj::StringPtr input, Orphanage orphanage) const; + // Decode a text message into a Cap'n Proto object of type T, allocated in the given + // orphanage. Any errors parsing the input or assigning the fields of T are thrown as + // exceptions. + + void decode(kj::StringPtr input, DynamicStruct::Builder output) const; + // Decode a text message for a struct into the given builder. Any errors parsing the + // input or assigning the fields of the output are thrown as exceptions. + + // TODO(someday): expose some control over the error handling? +private: + Orphan decode(kj::StringPtr input, Type type, Orphanage orphanage) const; + + bool prettyPrint; +}; + +// ======================================================================================= +// inline stuff + +template +inline kj::String TextCodec::encode(T&& value) const { + return encode(DynamicValue::Reader(ReaderFor>(kj::fwd(value)))); +} + +template +inline Orphan TextCodec::decode(kj::StringPtr input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_TEXT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/serialize.h --- a/osx/include/capnp/serialize.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/serialize.h Mon May 22 10:01:37 2017 +0100 @@ -1,237 +1,237 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file implements a simple serialization format for Cap'n Proto messages. The format -// is as follows: -// -// * 32-bit little-endian segment count (4 bytes). -// * 32-bit little-endian size of each segment (4*(segment count) bytes). -// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even -// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.) -// * Data from each segment, in order (8*sum(segment sizes) bytes) -// -// This format has some important properties: -// - It is self-delimiting, so multiple messages may be written to a stream without any external -// delimiter. -// - The total size and position of each segment can be determined by reading only the first part -// of the message, allowing lazy and random-access reading of the segment data. -// - A message is always at least 8 bytes. -// - A single-segment message can be read entirely in two system calls with no buffering. -// - A multi-segment message can be read entirely in three system calls with no buffering. -// - The format is appropriate for mmap()ing since all data is aligned. - -#ifndef CAPNP_SERIALIZE_H_ -#define CAPNP_SERIALIZE_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "message.h" -#include - -namespace capnp { - -class FlatArrayMessageReader: public MessageReader { - // Parses a message from a flat array. Note that it makes sense to use this together with mmap() - // for extremely fast parsing. - -public: - FlatArrayMessageReader(kj::ArrayPtr array, ReaderOptions options = ReaderOptions()); - // The array must remain valid until the MessageReader is destroyed. - - kj::ArrayPtr getSegment(uint id) override; - - const word* getEnd() const { return end; } - // Get a pointer just past the end of the message as determined by reading the message header. - // This could actually be before the end of the input array. This pointer is useful e.g. if - // you know that the input array has extra stuff appended after the message and you want to - // get at it. - -private: - // Optimize for single-segment case. - kj::ArrayPtr segment0; - kj::Array> moreSegments; - const word* end; -}; - -kj::ArrayPtr initMessageBuilderFromFlatArrayCopy( - kj::ArrayPtr array, MessageBuilder& target, - ReaderOptions options = ReaderOptions()); -// Convenience function which reads a message using `FlatArrayMessageReader` then copies the -// content into the target `MessageBuilder`, verifying that the message structure is valid -// (although not necessarily that it matches the desired schema). -// -// Returns an ArrayPtr containing any words left over in the array after consuming the whole -// message. This is useful when reading multiple messages that have been concatenated. See also -// FlatArrayMessageReader::getEnd(). -// -// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one -// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not -// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) - -kj::Array messageToFlatArray(MessageBuilder& builder); -// Constructs a flat array containing the entire content of the given message. -// -// To output the message as bytes, use `.asBytes()` on the returned word array. Keep in mind that -// `asBytes()` returns an ArrayPtr, so you have to save the Array as well to prevent it from being -// deleted. For example: -// -// kj::Array words = messageToFlatArray(myMessage); -// kj::ArrayPtr bytes = words.asBytes(); -// write(fd, bytes.begin(), bytes.size()); - -kj::Array messageToFlatArray(kj::ArrayPtr> segments); -// Version of messageToFlatArray that takes a raw segment array. - -size_t computeSerializedSizeInWords(MessageBuilder& builder); -// Returns the size, in words, that will be needed to serialize the message, including the header. - -size_t computeSerializedSizeInWords(kj::ArrayPtr> segments); -// Version of computeSerializedSizeInWords that takes a raw segment array. - -size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr messagePrefix); -// Given a prefix of a serialized message, try to determine the expected total size of the message, -// in words. The returned size is based on the information known so far; it may be an underestimate -// if the prefix doesn't contain the full segment table. -// -// If the returned value is greater than `messagePrefix.size()`, then the message is not yet -// complete and the app cannot parse it yet. If the returned value is less than or equal to -// `messagePrefix.size()`, then the returned value is the exact total size of the message; any -// remaining bytes are part of the next message. -// -// This function is useful when reading messages from a stream in an asynchronous way, but when -// using the full KJ async infrastructure would be too difficult. Each time bytes are received, -// use this function to determine if an entire message is ready to be parsed. - -// ======================================================================================= - -class InputStreamMessageReader: public MessageReader { - // A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader - // for a subclass specific to file descriptors. - -public: - InputStreamMessageReader(kj::InputStream& inputStream, - ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); - ~InputStreamMessageReader() noexcept(false); - - // implements MessageReader ---------------------------------------- - kj::ArrayPtr getSegment(uint id) override; - -private: - kj::InputStream& inputStream; - byte* readPos; - - // Optimize for single-segment case. - kj::ArrayPtr segment0; - kj::Array> moreSegments; - - kj::Array ownedSpace; - // Only if scratchSpace wasn't big enough. - - kj::UnwindDetector unwindDetector; -}; - -void readMessageCopy(kj::InputStream& input, MessageBuilder& target, - ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); -// Convenience function which reads a message using `InputStreamMessageReader` then copies the -// content into the target `MessageBuilder`, verifying that the message structure is valid -// (although not necessarily that it matches the desired schema). -// -// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one -// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not -// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) - -void writeMessage(kj::OutputStream& output, MessageBuilder& builder); -// Write the message to the given output stream. - -void writeMessage(kj::OutputStream& output, kj::ArrayPtr> segments); -// Write the segment array to the given output stream. - -// ======================================================================================= -// Specializations for reading from / writing to file descriptors. - -class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader { - // A MessageReader that reads from a steam-based file descriptor. - -public: - StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr) - : FdInputStream(fd), InputStreamMessageReader(*this, options, scratchSpace) {} - // Read message from a file descriptor, without taking ownership of the descriptor. - - StreamFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr) - : FdInputStream(kj::mv(fd)), InputStreamMessageReader(*this, options, scratchSpace) {} - // Read a message from a file descriptor, taking ownership of the descriptor. - - ~StreamFdMessageReader() noexcept(false); -}; - -void readMessageCopyFromFd(int fd, MessageBuilder& target, - ReaderOptions options = ReaderOptions(), - kj::ArrayPtr scratchSpace = nullptr); -// Convenience function which reads a message using `StreamFdMessageReader` then copies the -// content into the target `MessageBuilder`, verifying that the message structure is valid -// (although not necessarily that it matches the desired schema). -// -// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one -// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not -// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) - -void writeMessageToFd(int fd, MessageBuilder& builder); -// Write the message to the given file descriptor. -// -// This function throws an exception on any I/O error. If your code is not exception-safe, be sure -// you catch this exception at the call site. If throwing an exception is not acceptable, you -// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). - -void writeMessageToFd(int fd, kj::ArrayPtr> segments); -// Write the segment array to the given file descriptor. -// -// This function throws an exception on any I/O error. If your code is not exception-safe, be sure -// you catch this exception at the call site. If throwing an exception is not acceptable, you -// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). - -// ======================================================================================= -// inline stuff - -inline kj::Array messageToFlatArray(MessageBuilder& builder) { - return messageToFlatArray(builder.getSegmentsForOutput()); -} - -inline size_t computeSerializedSizeInWords(MessageBuilder& builder) { - return computeSerializedSizeInWords(builder.getSegmentsForOutput()); -} - -inline void writeMessage(kj::OutputStream& output, MessageBuilder& builder) { - writeMessage(output, builder.getSegmentsForOutput()); -} - -inline void writeMessageToFd(int fd, MessageBuilder& builder) { - writeMessageToFd(fd, builder.getSegmentsForOutput()); -} - -} // namespace capnp - -#endif // SERIALIZE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file implements a simple serialization format for Cap'n Proto messages. The format +// is as follows: +// +// * 32-bit little-endian segment count (4 bytes). +// * 32-bit little-endian size of each segment (4*(segment count) bytes). +// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even +// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.) +// * Data from each segment, in order (8*sum(segment sizes) bytes) +// +// This format has some important properties: +// - It is self-delimiting, so multiple messages may be written to a stream without any external +// delimiter. +// - The total size and position of each segment can be determined by reading only the first part +// of the message, allowing lazy and random-access reading of the segment data. +// - A message is always at least 8 bytes. +// - A single-segment message can be read entirely in two system calls with no buffering. +// - A multi-segment message can be read entirely in three system calls with no buffering. +// - The format is appropriate for mmap()ing since all data is aligned. + +#ifndef CAPNP_SERIALIZE_H_ +#define CAPNP_SERIALIZE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "message.h" +#include + +namespace capnp { + +class FlatArrayMessageReader: public MessageReader { + // Parses a message from a flat array. Note that it makes sense to use this together with mmap() + // for extremely fast parsing. + +public: + FlatArrayMessageReader(kj::ArrayPtr array, ReaderOptions options = ReaderOptions()); + // The array must remain valid until the MessageReader is destroyed. + + kj::ArrayPtr getSegment(uint id) override; + + const word* getEnd() const { return end; } + // Get a pointer just past the end of the message as determined by reading the message header. + // This could actually be before the end of the input array. This pointer is useful e.g. if + // you know that the input array has extra stuff appended after the message and you want to + // get at it. + +private: + // Optimize for single-segment case. + kj::ArrayPtr segment0; + kj::Array> moreSegments; + const word* end; +}; + +kj::ArrayPtr initMessageBuilderFromFlatArrayCopy( + kj::ArrayPtr array, MessageBuilder& target, + ReaderOptions options = ReaderOptions()); +// Convenience function which reads a message using `FlatArrayMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// Returns an ArrayPtr containing any words left over in the array after consuming the whole +// message. This is useful when reading multiple messages that have been concatenated. See also +// FlatArrayMessageReader::getEnd(). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +kj::Array messageToFlatArray(MessageBuilder& builder); +// Constructs a flat array containing the entire content of the given message. +// +// To output the message as bytes, use `.asBytes()` on the returned word array. Keep in mind that +// `asBytes()` returns an ArrayPtr, so you have to save the Array as well to prevent it from being +// deleted. For example: +// +// kj::Array words = messageToFlatArray(myMessage); +// kj::ArrayPtr bytes = words.asBytes(); +// write(fd, bytes.begin(), bytes.size()); + +kj::Array messageToFlatArray(kj::ArrayPtr> segments); +// Version of messageToFlatArray that takes a raw segment array. + +size_t computeSerializedSizeInWords(MessageBuilder& builder); +// Returns the size, in words, that will be needed to serialize the message, including the header. + +size_t computeSerializedSizeInWords(kj::ArrayPtr> segments); +// Version of computeSerializedSizeInWords that takes a raw segment array. + +size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr messagePrefix); +// Given a prefix of a serialized message, try to determine the expected total size of the message, +// in words. The returned size is based on the information known so far; it may be an underestimate +// if the prefix doesn't contain the full segment table. +// +// If the returned value is greater than `messagePrefix.size()`, then the message is not yet +// complete and the app cannot parse it yet. If the returned value is less than or equal to +// `messagePrefix.size()`, then the returned value is the exact total size of the message; any +// remaining bytes are part of the next message. +// +// This function is useful when reading messages from a stream in an asynchronous way, but when +// using the full KJ async infrastructure would be too difficult. Each time bytes are received, +// use this function to determine if an entire message is ready to be parsed. + +// ======================================================================================= + +class InputStreamMessageReader: public MessageReader { + // A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader + // for a subclass specific to file descriptors. + +public: + InputStreamMessageReader(kj::InputStream& inputStream, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + ~InputStreamMessageReader() noexcept(false); + + // implements MessageReader ---------------------------------------- + kj::ArrayPtr getSegment(uint id) override; + +private: + kj::InputStream& inputStream; + byte* readPos; + + // Optimize for single-segment case. + kj::ArrayPtr segment0; + kj::Array> moreSegments; + + kj::Array ownedSpace; + // Only if scratchSpace wasn't big enough. + + kj::UnwindDetector unwindDetector; +}; + +void readMessageCopy(kj::InputStream& input, MessageBuilder& target, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Convenience function which reads a message using `InputStreamMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +void writeMessage(kj::OutputStream& output, MessageBuilder& builder); +// Write the message to the given output stream. + +void writeMessage(kj::OutputStream& output, kj::ArrayPtr> segments); +// Write the segment array to the given output stream. + +// ======================================================================================= +// Specializations for reading from / writing to file descriptors. + +class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader { + // A MessageReader that reads from a steam-based file descriptor. + +public: + StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : FdInputStream(fd), InputStreamMessageReader(*this, options, scratchSpace) {} + // Read message from a file descriptor, without taking ownership of the descriptor. + + StreamFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : FdInputStream(kj::mv(fd)), InputStreamMessageReader(*this, options, scratchSpace) {} + // Read a message from a file descriptor, taking ownership of the descriptor. + + ~StreamFdMessageReader() noexcept(false); +}; + +void readMessageCopyFromFd(int fd, MessageBuilder& target, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Convenience function which reads a message using `StreamFdMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +void writeMessageToFd(int fd, MessageBuilder& builder); +// Write the message to the given file descriptor. +// +// This function throws an exception on any I/O error. If your code is not exception-safe, be sure +// you catch this exception at the call site. If throwing an exception is not acceptable, you +// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). + +void writeMessageToFd(int fd, kj::ArrayPtr> segments); +// Write the segment array to the given file descriptor. +// +// This function throws an exception on any I/O error. If your code is not exception-safe, be sure +// you catch this exception at the call site. If throwing an exception is not acceptable, you +// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). + +// ======================================================================================= +// inline stuff + +inline kj::Array messageToFlatArray(MessageBuilder& builder) { + return messageToFlatArray(builder.getSegmentsForOutput()); +} + +inline size_t computeSerializedSizeInWords(MessageBuilder& builder) { + return computeSerializedSizeInWords(builder.getSegmentsForOutput()); +} + +inline void writeMessage(kj::OutputStream& output, MessageBuilder& builder) { + writeMessage(output, builder.getSegmentsForOutput()); +} + +inline void writeMessageToFd(int fd, MessageBuilder& builder) { + writeMessageToFd(fd, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // SERIALIZE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/test-import.capnp --- a/osx/include/capnp/test-import.capnp Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xf36d7b330303c66e; - -using Test = import "test.capnp"; - -struct TestImport { - field @0 :Test.TestAllTypes; -} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/test-import2.capnp --- a/osx/include/capnp/test-import2.capnp Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xc64a3bf0338a124a; - -using Import1 = import "/capnp/schema.capnp"; -using Import2 = import "test-import.capnp"; -using Import3 = import "test.capnp"; - -struct TestImport2 { - foo @0 :Import3.TestAllTypes; - bar @1 :Import1.Node; - baz @2 :Import2.TestImport; -} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/test-util.h --- a/osx/include/capnp/test-util.h Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,323 +0,0 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_TEST_UTIL_H_ -#define CAPNP_TEST_UTIL_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include -#include -#include "blob.h" -#include - -#if !CAPNP_LITE -#include "dynamic.h" -#endif // !CAPNP_LITE - -#if KJ_NO_EXCEPTIONS -#undef EXPECT_ANY_THROW -#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".") -#endif - -#define EXPECT_NONFATAL_FAILURE(code) \ - EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr); - -#ifdef KJ_DEBUG -#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW -#else -#define EXPECT_DEBUG_ANY_THROW(EXP) -#endif - -// TODO(cleanup): Auto-generate stringification functions for union discriminants. -namespace capnproto_test { -namespace capnp { -namespace test { -inline kj::String KJ_STRINGIFY(TestUnion::Union0::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestUnion::Union1::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestUnion::Union2::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestUnion::Union3::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestUnnamedUnion::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestGroups::Groups::Which which) { - return kj::str(static_cast(which)); -} -inline kj::String KJ_STRINGIFY(TestInterleavedGroups::Group1::Which which) { - return kj::str(static_cast(which)); -} -} // namespace test -} // namespace capnp -} // namespace capnproto_test - -namespace capnp { -namespace _ { // private - -inline Data::Reader data(const char* str) { - return Data::Reader(reinterpret_cast(str), strlen(str)); -} - -namespace test = capnproto_test::capnp::test; - -// We don't use "using namespace" to pull these in because then things would still compile -// correctly if they were generated in the global namespace. -using ::capnproto_test::capnp::test::TestAllTypes; -using ::capnproto_test::capnp::test::TestDefaults; -using ::capnproto_test::capnp::test::TestEnum; -using ::capnproto_test::capnp::test::TestUnion; -using ::capnproto_test::capnp::test::TestUnionDefaults; -using ::capnproto_test::capnp::test::TestNestedTypes; -using ::capnproto_test::capnp::test::TestUsing; -using ::capnproto_test::capnp::test::TestListDefaults; - -void initTestMessage(TestAllTypes::Builder builder); -void initTestMessage(TestDefaults::Builder builder); -void initTestMessage(TestListDefaults::Builder builder); - -void checkTestMessage(TestAllTypes::Builder builder); -void checkTestMessage(TestDefaults::Builder builder); -void checkTestMessage(TestListDefaults::Builder builder); - -void checkTestMessage(TestAllTypes::Reader reader); -void checkTestMessage(TestDefaults::Reader reader); -void checkTestMessage(TestListDefaults::Reader reader); - -void checkTestMessageAllZero(TestAllTypes::Builder builder); -void checkTestMessageAllZero(TestAllTypes::Reader reader); - -#if !CAPNP_LITE -void initDynamicTestMessage(DynamicStruct::Builder builder); -void initDynamicTestLists(DynamicStruct::Builder builder); -void checkDynamicTestMessage(DynamicStruct::Builder builder); -void checkDynamicTestLists(DynamicStruct::Builder builder); -void checkDynamicTestMessage(DynamicStruct::Reader reader); -void checkDynamicTestLists(DynamicStruct::Reader reader); -void checkDynamicTestMessageAllZero(DynamicStruct::Builder builder); -void checkDynamicTestMessageAllZero(DynamicStruct::Reader reader); -#endif // !CAPNP_LITE - -template -inline void checkElement(T a, T b) { - EXPECT_EQ(a, b); -} - -template <> -inline void checkElement(float a, float b) { - EXPECT_FLOAT_EQ(a, b); -} - -template <> -inline void checkElement(double a, double b) { - EXPECT_DOUBLE_EQ(a, b); -} - -template -void checkList(T reader, std::initializer_list expected) { - ASSERT_EQ(expected.size(), reader.size()); - for (uint i = 0; i < expected.size(); i++) { - checkElement(expected.begin()[i], reader[i]); - } -} - -template -void checkList(T reader, std::initializer_list expected) { - ASSERT_EQ(expected.size(), reader.size()); - for (uint i = 0; i < expected.size(); i++) { - checkElement(expected.begin()[i], reader[i]); - } -} - -inline void checkList(List::Reader reader, - std::initializer_list expectedData, - std::initializer_list expectedPointers) { - ASSERT_EQ(expectedData.size(), reader.size()); - for (uint i = 0; i < expectedData.size(); i++) { - EXPECT_EQ(expectedData.begin()[i], reader[i].getOld1()); - EXPECT_EQ(expectedPointers.begin()[i], reader[i].getOld2()); - } -} - -// Hack because as<>() is a template-parameter-dependent lookup everywhere below... -#define as template as - -template void expectPrimitiveEq(T a, T b) { EXPECT_EQ(a, b); } -inline void expectPrimitiveEq(float a, float b) { EXPECT_FLOAT_EQ(a, b); } -inline void expectPrimitiveEq(double a, double b) { EXPECT_DOUBLE_EQ(a, b); } -inline void expectPrimitiveEq(Text::Reader a, Text::Builder b) { EXPECT_EQ(a, b); } -inline void expectPrimitiveEq(Data::Reader a, Data::Builder b) { EXPECT_EQ(a, b); } - -#if !CAPNP_LITE -template -void checkList(T reader, std::initializer_list> expected) { - auto list = reader.as(); - ASSERT_EQ(expected.size(), list.size()); - for (uint i = 0; i < expected.size(); i++) { - expectPrimitiveEq(expected.begin()[i], list[i].as()); - } - - auto typed = reader.as>(); - ASSERT_EQ(expected.size(), typed.size()); - for (uint i = 0; i < expected.size(); i++) { - expectPrimitiveEq(expected.begin()[i], typed[i]); - } -} -#endif // !CAPNP_LITE - -#undef as - -// ======================================================================================= -// Interface implementations. - -#if !CAPNP_LITE - -class TestInterfaceImpl final: public test::TestInterface::Server { -public: - TestInterfaceImpl(int& callCount); - - kj::Promise foo(FooContext context) override; - - kj::Promise baz(BazContext context) override; - -private: - int& callCount; -}; - -class TestExtendsImpl final: public test::TestExtends2::Server { -public: - TestExtendsImpl(int& callCount); - - kj::Promise foo(FooContext context) override; - - kj::Promise grault(GraultContext context) override; - -private: - int& callCount; -}; - -class TestPipelineImpl final: public test::TestPipeline::Server { -public: - TestPipelineImpl(int& callCount); - - kj::Promise getCap(GetCapContext context) override; - -private: - int& callCount; -}; - -class TestCallOrderImpl final: public test::TestCallOrder::Server { -public: - kj::Promise getCallSequence(GetCallSequenceContext context) override; - -private: - uint count = 0; -}; - -class TestTailCallerImpl final: public test::TestTailCaller::Server { -public: - TestTailCallerImpl(int& callCount); - - kj::Promise foo(FooContext context) override; - -private: - int& callCount; -}; - -class TestTailCalleeImpl final: public test::TestTailCallee::Server { -public: - TestTailCalleeImpl(int& callCount); - - kj::Promise foo(FooContext context) override; - -private: - int& callCount; -}; - -class TestMoreStuffImpl final: public test::TestMoreStuff::Server { -public: - TestMoreStuffImpl(int& callCount, int& handleCount); - - kj::Promise getCallSequence(GetCallSequenceContext context) override; - - kj::Promise callFoo(CallFooContext context) override; - - kj::Promise callFooWhenResolved(CallFooWhenResolvedContext context) override; - - kj::Promise neverReturn(NeverReturnContext context) override; - - kj::Promise hold(HoldContext context) override; - - kj::Promise callHeld(CallHeldContext context) override; - - kj::Promise getHeld(GetHeldContext context) override; - - kj::Promise echo(EchoContext context) override; - - kj::Promise expectCancel(ExpectCancelContext context) override; - - kj::Promise getHandle(GetHandleContext context) override; - - kj::Promise getNull(GetNullContext context) override; - -private: - int& callCount; - int& handleCount; - test::TestInterface::Client clientToHold = nullptr; - - kj::Promise loop(uint depth, test::TestInterface::Client cap, ExpectCancelContext context); -}; - -class TestCapDestructor final: public test::TestInterface::Server { - // Implementation of TestInterface that notifies when it is destroyed. - -public: - TestCapDestructor(kj::Own>&& fulfiller) - : fulfiller(kj::mv(fulfiller)), impl(dummy) {} - - ~TestCapDestructor() { - fulfiller->fulfill(); - } - - kj::Promise foo(FooContext context) { - return impl.foo(context); - } - -private: - kj::Own> fulfiller; - int dummy = 0; - TestInterfaceImpl impl; -}; - -#endif // !CAPNP_LITE - -} // namespace _ (private) -} // namespace capnp - -#endif // TEST_UTIL_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/capnp/test.capnp --- a/osx/include/capnp/test.capnp Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,931 +0,0 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xd508eebdc2dc42b8; - -using Cxx = import "c++.capnp"; - -# Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified -# names for stuff in the capnproto namespace. -$Cxx.namespace("capnproto_test::capnp::test"); - -enum TestEnum { - foo @0; - bar @1; - baz @2; - qux @3; - quux @4; - corge @5; - grault @6; - garply @7; -} - -struct TestAllTypes { - voidField @0 : Void; - boolField @1 : Bool; - int8Field @2 : Int8; - int16Field @3 : Int16; - int32Field @4 : Int32; - int64Field @5 : Int64; - uInt8Field @6 : UInt8; - uInt16Field @7 : UInt16; - uInt32Field @8 : UInt32; - uInt64Field @9 : UInt64; - float32Field @10 : Float32; - float64Field @11 : Float64; - textField @12 : Text; - dataField @13 : Data; - structField @14 : TestAllTypes; - enumField @15 : TestEnum; - interfaceField @16 : Void; # TODO - - voidList @17 : List(Void); - boolList @18 : List(Bool); - int8List @19 : List(Int8); - int16List @20 : List(Int16); - int32List @21 : List(Int32); - int64List @22 : List(Int64); - uInt8List @23 : List(UInt8); - uInt16List @24 : List(UInt16); - uInt32List @25 : List(UInt32); - uInt64List @26 : List(UInt64); - float32List @27 : List(Float32); - float64List @28 : List(Float64); - textList @29 : List(Text); - dataList @30 : List(Data); - structList @31 : List(TestAllTypes); - enumList @32 : List(TestEnum); - interfaceList @33 : List(Void); # TODO -} - -struct TestDefaults { - voidField @0 : Void = void; - boolField @1 : Bool = true; - int8Field @2 : Int8 = -123; - int16Field @3 : Int16 = -12345; - int32Field @4 : Int32 = -12345678; - int64Field @5 : Int64 = -123456789012345; - uInt8Field @6 : UInt8 = 234; - uInt16Field @7 : UInt16 = 45678; - uInt32Field @8 : UInt32 = 3456789012; - uInt64Field @9 : UInt64 = 12345678901234567890; - float32Field @10 : Float32 = 1234.5; - float64Field @11 : Float64 = -123e45; - textField @12 : Text = "foo"; - dataField @13 : Data = 0x"62 61 72"; # "bar" - structField @14 : TestAllTypes = ( - voidField = void, - boolField = true, - int8Field = -12, - int16Field = 3456, - int32Field = -78901234, - int64Field = 56789012345678, - uInt8Field = 90, - uInt16Field = 1234, - uInt32Field = 56789012, - uInt64Field = 345678901234567890, - float32Field = -1.25e-10, - float64Field = 345, - textField = "baz", - dataField = "qux", - structField = ( - textField = "nested", - structField = (textField = "really nested")), - enumField = baz, - # interfaceField can't have a default - - voidList = [void, void, void], - boolList = [false, true, false, true, true], - int8List = [12, -34, -0x80, 0x7f], - int16List = [1234, -5678, -0x8000, 0x7fff], - int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], - int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], - uInt8List = [12, 34, 0, 0xff], - uInt16List = [1234, 5678, 0, 0xffff], - uInt32List = [12345678, 90123456, 0, 0xffffffff], - uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], - float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], - float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], - textList = ["quux", "corge", "grault"], - dataList = ["garply", "waldo", "fred"], - structList = [ - (textField = "x structlist 1"), - (textField = "x structlist 2"), - (textField = "x structlist 3")], - enumList = [qux, bar, grault] - # interfaceList can't have a default - ); - enumField @15 : TestEnum = corge; - interfaceField @16 : Void; # TODO - - voidList @17 : List(Void) = [void, void, void, void, void, void]; - boolList @18 : List(Bool) = [true, false, false, true]; - int8List @19 : List(Int8) = [111, -111]; - int16List @20 : List(Int16) = [11111, -11111]; - int32List @21 : List(Int32) = [111111111, -111111111]; - int64List @22 : List(Int64) = [1111111111111111111, -1111111111111111111]; - uInt8List @23 : List(UInt8) = [111, 222] ; - uInt16List @24 : List(UInt16) = [33333, 44444]; - uInt32List @25 : List(UInt32) = [3333333333]; - uInt64List @26 : List(UInt64) = [11111111111111111111]; - float32List @27 : List(Float32) = [5555.5, inf, -inf, nan]; - float64List @28 : List(Float64) = [7777.75, inf, -inf, nan]; - textList @29 : List(Text) = ["plugh", "xyzzy", "thud"]; - dataList @30 : List(Data) = ["oops", "exhausted", "rfc3092"]; - structList @31 : List(TestAllTypes) = [ - (textField = "structlist 1"), - (textField = "structlist 2"), - (textField = "structlist 3")]; - enumList @32 : List(TestEnum) = [foo, garply]; - interfaceList @33 : List(Void); # TODO -} - -struct TestAnyPointer { - anyPointerField @0 :AnyPointer; - - # Do not add any other fields here! Some tests rely on anyPointerField being the last pointer - # in the struct. -} - -struct TestAnyOthers { - anyStructField @0 :AnyStruct; - anyListField @1 :AnyList; - capabilityField @2 :Capability; -} - -struct TestOutOfOrder { - foo @3 :Text; - bar @2 :Text; - baz @8 :Text; - qux @0 :Text; - quux @6 :Text; - corge @4 :Text; - grault @1 :Text; - garply @7 :Text; - waldo @5 :Text; -} - -struct TestUnion { - union0 @0! :union { - # Pack union 0 under ideal conditions: there is no unused padding space prior to it. - u0f0s0 @4: Void; - u0f0s1 @5: Bool; - u0f0s8 @6: Int8; - u0f0s16 @7: Int16; - u0f0s32 @8: Int32; - u0f0s64 @9: Int64; - u0f0sp @10: Text; - - # Pack more stuff into union0 -- should go in same space. - u0f1s0 @11: Void; - u0f1s1 @12: Bool; - u0f1s8 @13: Int8; - u0f1s16 @14: Int16; - u0f1s32 @15: Int32; - u0f1s64 @16: Int64; - u0f1sp @17: Text; - } - - # Pack one bit in order to make pathological situation for union1. - bit0 @18: Bool; - - union1 @1! :union { - # Pack pathologically bad case. Each field takes up new space. - u1f0s0 @19: Void; - u1f0s1 @20: Bool; - u1f1s1 @21: Bool; - u1f0s8 @22: Int8; - u1f1s8 @23: Int8; - u1f0s16 @24: Int16; - u1f1s16 @25: Int16; - u1f0s32 @26: Int32; - u1f1s32 @27: Int32; - u1f0s64 @28: Int64; - u1f1s64 @29: Int64; - u1f0sp @30: Text; - u1f1sp @31: Text; - - # Pack more stuff into union1 -- each should go into the same space as corresponding u1f0s*. - u1f2s0 @32: Void; - u1f2s1 @33: Bool; - u1f2s8 @34: Int8; - u1f2s16 @35: Int16; - u1f2s32 @36: Int32; - u1f2s64 @37: Int64; - u1f2sp @38: Text; - } - - # Fill in the rest of that bitfield from earlier. - bit2 @39: Bool; - bit3 @40: Bool; - bit4 @41: Bool; - bit5 @42: Bool; - bit6 @43: Bool; - bit7 @44: Bool; - - # Interleave two unions to be really annoying. - # Also declare in reverse order to make sure union discriminant values are sorted by field number - # and not by declaration order. - union2 @2! :union { - u2f0s64 @54: Int64; - u2f0s32 @52: Int32; - u2f0s16 @50: Int16; - u2f0s8 @47: Int8; - u2f0s1 @45: Bool; - } - - union3 @3! :union { - u3f0s64 @55: Int64; - u3f0s32 @53: Int32; - u3f0s16 @51: Int16; - u3f0s8 @48: Int8; - u3f0s1 @46: Bool; - } - - byte0 @49: UInt8; -} - -struct TestUnnamedUnion { - before @0 :Text; - - union { - foo @1 :UInt16; - bar @3 :UInt32; - } - - middle @2 :UInt16; - - after @4 :Text; -} - -struct TestUnionInUnion { - # There is no reason to ever do this. - outer :union { - inner :union { - foo @0 :Int32; - bar @1 :Int32; - } - baz @2 :Int32; - } -} - -struct TestGroups { - groups :union { - foo :group { - corge @0 :Int32; - grault @2 :Int64; - garply @8 :Text; - } - bar :group { - corge @3 :Int32; - grault @4 :Text; - garply @5 :Int64; - } - baz :group { - corge @1 :Int32; - grault @6 :Text; - garply @7 :Text; - } - } -} - -struct TestInterleavedGroups { - group1 :group { - foo @0 :UInt32; - bar @2 :UInt64; - union { - qux @4 :UInt16; - corge :group { - grault @6 :UInt64; - garply @8 :UInt16; - plugh @14 :Text; - xyzzy @16 :Text; - } - - fred @12 :Text; - } - - waldo @10 :Text; - } - - group2 :group { - foo @1 :UInt32; - bar @3 :UInt64; - union { - qux @5 :UInt16; - corge :group { - grault @7 :UInt64; - garply @9 :UInt16; - plugh @15 :Text; - xyzzy @17 :Text; - } - - fred @13 :Text; - } - - waldo @11 :Text; - } -} - -struct TestUnionDefaults { - s16s8s64s8Set @0 :TestUnion = - (union0 = (u0f0s16 = 321), union1 = (u1f0s8 = 123), union2 = (u2f0s64 = 12345678901234567), - union3 = (u3f0s8 = 55)); - s0sps1s32Set @1 :TestUnion = - (union0 = (u0f1s0 = void), union1 = (u1f0sp = "foo"), union2 = (u2f0s1 = true), - union3 = (u3f0s32 = 12345678)); - - unnamed1 @2 :TestUnnamedUnion = (foo = 123); - unnamed2 @3 :TestUnnamedUnion = (bar = 321, before = "foo", after = "bar"); -} - -struct TestNestedTypes { - enum NestedEnum { - foo @0; - bar @1; - } - - struct NestedStruct { - enum NestedEnum { - baz @0; - qux @1; - quux @2; - } - - outerNestedEnum @0 :TestNestedTypes.NestedEnum = bar; - innerNestedEnum @1 :NestedEnum = quux; - } - - nestedStruct @0 :NestedStruct; - - outerNestedEnum @1 :NestedEnum = bar; - innerNestedEnum @2 :NestedStruct.NestedEnum = quux; -} - -struct TestUsing { - using OuterNestedEnum = TestNestedTypes.NestedEnum; - using TestNestedTypes.NestedStruct.NestedEnum; - - outerNestedEnum @1 :OuterNestedEnum = bar; - innerNestedEnum @0 :NestedEnum = quux; -} - -struct TestLists { - # Small structs, when encoded as list, will be encoded as primitive lists rather than struct - # lists, to save space. - struct Struct0 { f @0 :Void; } - struct Struct1 { f @0 :Bool; } - struct Struct8 { f @0 :UInt8; } - struct Struct16 { f @0 :UInt16; } - struct Struct32 { f @0 :UInt32; } - struct Struct64 { f @0 :UInt64; } - struct StructP { f @0 :Text; } - - # Versions of the above which cannot be encoded as primitive lists. - struct Struct0c { f @0 :Void; pad @1 :Text; } - struct Struct1c { f @0 :Bool; pad @1 :Text; } - struct Struct8c { f @0 :UInt8; pad @1 :Text; } - struct Struct16c { f @0 :UInt16; pad @1 :Text; } - struct Struct32c { f @0 :UInt32; pad @1 :Text; } - struct Struct64c { f @0 :UInt64; pad @1 :Text; } - struct StructPc { f @0 :Text; pad @1 :UInt64; } - - list0 @0 :List(Struct0); - list1 @1 :List(Struct1); - list8 @2 :List(Struct8); - list16 @3 :List(Struct16); - list32 @4 :List(Struct32); - list64 @5 :List(Struct64); - listP @6 :List(StructP); - - int32ListList @7 :List(List(Int32)); - textListList @8 :List(List(Text)); - structListList @9 :List(List(TestAllTypes)); -} - -struct TestFieldZeroIsBit { - bit @0 :Bool; - secondBit @1 :Bool = true; - thirdField @2 :UInt8 = 123; -} - -struct TestListDefaults { - lists @0 :TestLists = ( - list0 = [(f = void), (f = void)], - list1 = [(f = true), (f = false), (f = true), (f = true)], - list8 = [(f = 123), (f = 45)], - list16 = [(f = 12345), (f = 6789)], - list32 = [(f = 123456789), (f = 234567890)], - list64 = [(f = 1234567890123456), (f = 2345678901234567)], - listP = [(f = "foo"), (f = "bar")], - int32ListList = [[1, 2, 3], [4, 5], [12341234]], - textListList = [["foo", "bar"], ["baz"], ["qux", "corge"]], - structListList = [[(int32Field = 123), (int32Field = 456)], [(int32Field = 789)]]); -} - -struct TestLateUnion { - # Test what happens if the unions are not the first ordinals in the struct. At one point this - # was broken for the dynamic API. - - foo @0 :Int32; - bar @1 :Text; - baz @2 :Int16; - - theUnion @3! :union { - qux @4 :Text; - corge @5 :List(Int32); - grault @6 :Float32; - } - - anotherUnion @7! :union { - qux @8 :Text; - corge @9 :List(Int32); - grault @10 :Float32; - } -} - -struct TestOldVersion { - # A subset of TestNewVersion. - old1 @0 :Int64; - old2 @1 :Text; - old3 @2 :TestOldVersion; -} - -struct TestNewVersion { - # A superset of TestOldVersion. - old1 @0 :Int64; - old2 @1 :Text; - old3 @2 :TestNewVersion; - new1 @3 :Int64 = 987; - new2 @4 :Text = "baz"; -} - -struct TestOldUnionVersion { - union { - a @0 :Void; - b @1 :UInt64; - } -} - -struct TestNewUnionVersion { - union { - a :union { - a0 @0 :Void; - a1 @2 :UInt64; - } - b @1 :UInt64; - } -} - -struct TestStructUnion { - un @0! :union { - struct @1 :SomeStruct; - object @2 :TestAnyPointer; - } - - struct SomeStruct { - someText @0 :Text; - moreText @1 :Text; - } -} - -struct TestPrintInlineStructs { - someText @0 :Text; - - structList @1 :List(InlineStruct); - struct InlineStruct { - int32Field @0 :Int32; - textField @1 :Text; - } -} - -struct TestWholeFloatDefault { - # At one point, these failed to compile in C++ because it would produce literals like "123f", - # which is not valid; it needs to be "123.0f". - field @0 :Float32 = 123; - bigField @1 :Float32 = 2e30; - const constant :Float32 = 456; - const bigConstant :Float32 = 4e30; -} - -struct TestGenerics(Foo, Bar) { - foo @0 :Foo; - rev @1 :TestGenerics(Bar, Foo); - - union { - uv @2:Void; - ug :group { - ugfoo @3:Int32; - } - } - - struct Inner { - foo @0 :Foo; - bar @1 :Bar; - } - - struct Inner2(Baz) { - bar @0 :Bar; - baz @1 :Baz; - innerBound @2 :Inner; - innerUnbound @3 :TestGenerics.Inner; - - struct DeepNest(Qux) { - foo @0 :Foo; - bar @1 :Bar; - baz @2 :Baz; - qux @3 :Qux; - } - } - - interface Interface(Qux) { - call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestAnyPointer)); - } - - annotation ann(struct) :Foo; - - using AliasFoo = Foo; - using AliasInner = Inner; - using AliasInner2 = Inner2; - using AliasInner2Text = Inner2(Text); - using AliasRev = TestGenerics(Bar, Foo); - - struct UseAliases { - foo @0 :AliasFoo; - inner @1 :AliasInner; - inner2 @2 :AliasInner2; - inner2Bind @3 :AliasInner2(Text); - inner2Text @4 :AliasInner2Text; - revFoo @5 :AliasRev.AliasFoo; - } -} - -struct TestGenericsWrapper(Foo, Bar) { - value @0 :TestGenerics(Foo, Bar); -} - -struct TestGenericsWrapper2 { - value @0 :TestGenericsWrapper(Text, TestAllTypes); -} - -interface TestImplicitMethodParams { - call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); -} - -interface TestImplicitMethodParamsInGeneric(V) { - call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); -} - -struct TestGenericsUnion(Foo, Bar) { - # At one point this failed to compile. - - union { - foo @0 :Foo; - bar @1 :Bar; - } -} - -struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { - basic @0 :TestGenerics(TestAllTypes, TestAnyPointer); - inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner; - inner2 @2 :TestGenerics(TestAllTypes, TestAnyPointer).Inner2(Text); - unspecified @3 :TestGenerics; - unspecifiedInner @4 :TestGenerics.Inner2(Text); - wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer); - cap @18 :TestGenerics(TestInterface, Text); - genericCap @19 :TestGenerics(TestAllTypes, List(UInt32)).Interface(Data); - - default @5 :TestGenerics(TestAllTypes, Text) = - (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); - defaultInner @6 :TestGenerics(TestAllTypes, Text).Inner = - (foo = (int16Field = 123), bar = "text"); - defaultUser @7 :TestUseGenerics = (basic = (foo = (int16Field = 123))); - defaultWrapper @9 :TestGenericsWrapper(Text, TestAllTypes) = - (value = (foo = "text", rev = (foo = (int16Field = 321)))); - defaultWrapper2 @10 :TestGenericsWrapper2 = - (value = (value = (foo = "text", rev = (foo = (int16Field = 321))))); - - aliasFoo @11 :TestGenerics(TestAllTypes, TestAnyPointer).AliasFoo = (int16Field = 123); - aliasInner @12 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner - = (foo = (int16Field = 123)); - aliasInner2 @13 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2 - = (innerBound = (foo = (int16Field = 123))); - aliasInner2Bind @14 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2(List(UInt32)) - = (baz = [12, 34], innerBound = (foo = (int16Field = 123))); - aliasInner2Text @15 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2Text - = (baz = "text", innerBound = (foo = (int16Field = 123))); - aliasRev @16 :TestGenerics(TestAnyPointer, Text).AliasRev.AliasFoo = "text"; - - useAliases @17 :TestGenerics(TestAllTypes, List(UInt32)).UseAliases = ( - foo = (int16Field = 123), - inner = (foo = (int16Field = 123)), - inner2 = (innerBound = (foo = (int16Field = 123))), - inner2Bind = (baz = "text", innerBound = (foo = (int16Field = 123))), - inner2Text = (baz = "text", innerBound = (foo = (int16Field = 123))), - revFoo = [12, 34, 56]); -} - -struct TestEmptyStruct {} - -struct TestConstants { - const voidConst :Void = void; - const boolConst :Bool = true; - const int8Const :Int8 = -123; - const int16Const :Int16 = -12345; - const int32Const :Int32 = -12345678; - const int64Const :Int64 = -123456789012345; - const uint8Const :UInt8 = 234; - const uint16Const :UInt16 = 45678; - const uint32Const :UInt32 = 3456789012; - const uint64Const :UInt64 = 12345678901234567890; - const float32Const :Float32 = 1234.5; - const float64Const :Float64 = -123e45; - const textConst :Text = "foo"; - const dataConst :Data = "bar"; - const structConst :TestAllTypes = ( - voidField = void, - boolField = true, - int8Field = -12, - int16Field = 3456, - int32Field = -78901234, - int64Field = 56789012345678, - uInt8Field = 90, - uInt16Field = 1234, - uInt32Field = 56789012, - uInt64Field = 345678901234567890, - float32Field = -1.25e-10, - float64Field = 345, - textField = "baz", - dataField = "qux", - structField = ( - textField = "nested", - structField = (textField = "really nested")), - enumField = baz, - # interfaceField can't have a default - - voidList = [void, void, void], - boolList = [false, true, false, true, true], - int8List = [12, -34, -0x80, 0x7f], - int16List = [1234, -5678, -0x8000, 0x7fff], - int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], - int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], - uInt8List = [12, 34, 0, 0xff], - uInt16List = [1234, 5678, 0, 0xffff], - uInt32List = [12345678, 90123456, 0, 0xffffffff], - uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], - float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], - float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], - textList = ["quux", "corge", "grault"], - dataList = ["garply", "waldo", "fred"], - structList = [ - (textField = "x structlist 1"), - (textField = "x structlist 2"), - (textField = "x structlist 3")], - enumList = [qux, bar, grault] - # interfaceList can't have a default - ); - const enumConst :TestEnum = corge; - - const voidListConst :List(Void) = [void, void, void, void, void, void]; - const boolListConst :List(Bool) = [true, false, false, true]; - const int8ListConst :List(Int8) = [111, -111]; - const int16ListConst :List(Int16) = [11111, -11111]; - const int32ListConst :List(Int32) = [111111111, -111111111]; - const int64ListConst :List(Int64) = [1111111111111111111, -1111111111111111111]; - const uint8ListConst :List(UInt8) = [111, 222] ; - const uint16ListConst :List(UInt16) = [33333, 44444]; - const uint32ListConst :List(UInt32) = [3333333333]; - const uint64ListConst :List(UInt64) = [11111111111111111111]; - const float32ListConst :List(Float32) = [5555.5, inf, -inf, nan]; - const float64ListConst :List(Float64) = [7777.75, inf, -inf, nan]; - const textListConst :List(Text) = ["plugh", "xyzzy", "thud"]; - const dataListConst :List(Data) = ["oops", "exhausted", "rfc3092"]; - const structListConst :List(TestAllTypes) = [ - (textField = "structlist 1"), - (textField = "structlist 2"), - (textField = "structlist 3")]; - const enumListConst :List(TestEnum) = [foo, garply]; -} - -const globalInt :UInt32 = 12345; -const globalText :Text = "foobar"; -const globalStruct :TestAllTypes = (int32Field = 54321); -const globalPrintableStruct :TestPrintInlineStructs = (someText = "foo"); -const derivedConstant :TestAllTypes = ( - uInt32Field = .globalInt, - textField = TestConstants.textConst, - structField = TestConstants.structConst, - int16List = TestConstants.int16ListConst, - structList = TestConstants.structListConst); - -const genericConstant :TestGenerics(TestAllTypes, Text) = - (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); - -const embeddedData :Data = embed "testdata/packed"; -const embeddedText :Text = embed "testdata/short.txt"; -const embeddedStruct :TestAllTypes = embed "testdata/binary"; - -interface TestInterface { - foo @0 (i :UInt32, j :Bool) -> (x :Text); - bar @1 () -> (); - baz @2 (s: TestAllTypes); -} - -interface TestExtends extends(TestInterface) { - qux @0 (); - corge @1 TestAllTypes -> (); - grault @2 () -> TestAllTypes; -} - -interface TestExtends2 extends(TestExtends) {} - -interface TestPipeline { - getCap @0 (n: UInt32, inCap :TestInterface) -> (s: Text, outBox :Box); - testPointers @1 (cap :TestInterface, obj :AnyPointer, list :List(TestInterface)) -> (); - - struct Box { - cap @0 :TestInterface; - } -} - -interface TestCallOrder { - getCallSequence @0 (expected: UInt32) -> (n: UInt32); - # First call returns 0, next returns 1, ... - # - # The input `expected` is ignored but useful for disambiguating debug logs. -} - -interface TestTailCallee { - struct TailResult { - i @0 :UInt32; - t @1 :Text; - c @2 :TestCallOrder; - } - - foo @0 (i :Int32, t :Text) -> TailResult; -} - -interface TestTailCaller { - foo @0 (i :Int32, callee :TestTailCallee) -> TestTailCallee.TailResult; -} - -interface TestHandle {} - -interface TestMoreStuff extends(TestCallOrder) { - # Catch-all type that contains lots of testing methods. - - callFoo @0 (cap :TestInterface) -> (s: Text); - # Call `cap.foo()`, check the result, and return "bar". - - callFooWhenResolved @1 (cap :TestInterface) -> (s: Text); - # Like callFoo but waits for `cap` to resolve first. - - neverReturn @2 (cap :TestInterface) -> (capCopy :TestInterface); - # Doesn't return. You should cancel it. - - hold @3 (cap :TestInterface) -> (); - # Returns immediately but holds on to the capability. - - callHeld @4 () -> (s: Text); - # Calls the capability previously held using `hold` (and keeps holding it). - - getHeld @5 () -> (cap :TestInterface); - # Returns the capability previously held using `hold` (and keeps holding it). - - echo @6 (cap :TestCallOrder) -> (cap :TestCallOrder); - # Just returns the input cap. - - expectCancel @7 (cap :TestInterface) -> (); - # evalLater()-loops forever, holding `cap`. Must be canceled. - - methodWithDefaults @8 (a :Text, b :UInt32 = 123, c :Text = "foo") -> (d :Text, e :Text = "bar"); - - getHandle @9 () -> (handle :TestHandle); - # Get a new handle. Tests have an out-of-band way to check the current number of live handles, so - # this can be used to test garbage collection. - - getNull @10 () -> (nullCap :TestMoreStuff); - # Always returns a null capability. -} - -interface TestMembrane { - makeThing @0 () -> (thing :Thing); - callPassThrough @1 (thing :Thing, tailCall :Bool) -> Result; - callIntercept @2 (thing :Thing, tailCall :Bool) -> Result; - loopback @3 (thing :Thing) -> (thing :Thing); - - interface Thing { - passThrough @0 () -> Result; - intercept @1 () -> Result; - } - - struct Result { - text @0 :Text; - } -} - -struct TestContainMembrane { - cap @0 :TestMembrane.Thing; - list @1 :List(TestMembrane.Thing); -} - -struct TestTransferCap { - list @0 :List(Element); - struct Element { - text @0 :Text; - cap @1 :TestInterface; - } -} - -interface TestKeywordMethods { - delete @0 (); - class @1 (); - void @2 (); - return @3 (); -} - -interface TestAuthenticatedBootstrap(VatId) { - getCallerId @0 () -> (caller :VatId); -} - -struct TestSturdyRef { - hostId @0 :TestSturdyRefHostId; - objectId @1 :AnyPointer; -} - -struct TestSturdyRefHostId { - host @0 :Text; -} - -struct TestSturdyRefObjectId { - tag @0 :Tag; - enum Tag { - testInterface @0; - testExtends @1; - testPipeline @2; - testTailCallee @3; - testTailCaller @4; - testMoreStuff @5; - } -} - -struct TestProvisionId {} -struct TestRecipientId {} -struct TestThirdPartyCapId {} -struct TestJoinResult {} - -struct TestNameAnnotation $Cxx.name("RenamedStruct") { - union { - badFieldName @0 :Bool $Cxx.name("goodFieldName"); - bar @1 :Int8; - } - - enum BadlyNamedEnum $Cxx.name("RenamedEnum") { - foo @0; - bar @1; - baz @2 $Cxx.name("qux"); - } - - anotherBadFieldName @2 :BadlyNamedEnum $Cxx.name("anotherGoodFieldName"); - - struct NestedStruct $Cxx.name("RenamedNestedStruct") { - badNestedFieldName @0 :Bool $Cxx.name("goodNestedFieldName"); - anotherBadNestedFieldName @1 :NestedStruct $Cxx.name("anotherGoodNestedFieldName"); - - enum DeeplyNestedEnum $Cxx.name("RenamedDeeplyNestedEnum") { - quux @0; - corge @1; - grault @2 $Cxx.name("garply"); - } - } - - badlyNamedUnion :union $Cxx.name("renamedUnion") { - badlyNamedGroup :group $Cxx.name("renamedGroup") { - foo @3 :Void; - bar @4 :Void; - } - baz @5 :NestedStruct $Cxx.name("qux"); - } -} - -interface TestNameAnnotationInterface $Cxx.name("RenamedInterface") { - badlyNamedMethod @0 (badlyNamedParam :UInt8 $Cxx.name("renamedParam")) $Cxx.name("renamedMethod"); -} diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/arena.h --- a/osx/include/kj/arena.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/arena.h Mon May 22 10:01:37 2017 +0100 @@ -1,213 +1,213 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ARENA_H_ -#define KJ_ARENA_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "memory.h" -#include "array.h" -#include "string.h" - -namespace kj { - -class Arena { - // A class which allows several objects to be allocated in contiguous chunks of memory, then - // frees them all at once. - // - // Allocating from the same Arena in multiple threads concurrently is NOT safe, because making - // it safe would require atomic operations that would slow down allocation even when - // single-threaded. If you need to use arena allocation in a multithreaded context, consider - // allocating thread-local arenas. - -public: - explicit Arena(size_t chunkSizeHint = 1024); - // Create an Arena. `chunkSizeHint` hints at where to start when allocating chunks, but is only - // a hint -- the Arena will, for example, allocate progressively larger chunks as time goes on, - // in order to reduce overall allocation overhead. - - explicit Arena(ArrayPtr scratch); - // Allocates from the given scratch space first, only resorting to the heap when it runs out. - - KJ_DISALLOW_COPY(Arena); - ~Arena() noexcept(false); - - template - T& allocate(Params&&... params); - template - ArrayPtr allocateArray(size_t size); - // Allocate an object or array of type T. If T has a non-trivial destructor, that destructor - // will be run during the Arena's destructor. Such destructors are run in opposite order of - // allocation. Note that these methods must maintain a list of destructors to call, which has - // overhead, but this overhead only applies if T has a non-trivial destructor. - - template - Own allocateOwn(Params&&... params); - template - Array allocateOwnArray(size_t size); - template - ArrayBuilder allocateOwnArrayBuilder(size_t capacity); - // Allocate an object or array of type T. Destructors are executed when the returned Own - // or Array goes out-of-scope, which must happen before the Arena is destroyed. This variant - // is useful when you need to control when the destructor is called. This variant also avoids - // the need for the Arena itself to keep track of destructors to call later, which may make it - // slightly more efficient. - - template - inline T& copy(T&& value) { return allocate>(kj::fwd(value)); } - // Allocate a copy of the given value in the arena. This is just a shortcut for calling the - // type's copy (or move) constructor. - - StringPtr copyString(StringPtr content); - // Make a copy of the given string inside the arena, and return a pointer to the copy. - -private: - struct ChunkHeader { - ChunkHeader* next; - byte* pos; // first unallocated byte in this chunk - byte* end; // end of this chunk - }; - struct ObjectHeader { - void (*destructor)(void*); - ObjectHeader* next; - }; - - size_t nextChunkSize; - ChunkHeader* chunkList = nullptr; - ObjectHeader* objectList = nullptr; - - ChunkHeader* currentChunk = nullptr; - - void cleanup(); - // Run all destructors, leaving the above pointers null. If a destructor throws, the State is - // left in a consistent state, such that if cleanup() is called again, it will pick up where - // it left off. - - void* allocateBytes(size_t amount, uint alignment, bool hasDisposer); - // Allocate the given number of bytes. `hasDisposer` must be true if `setDisposer()` may be - // called on this pointer later. - - void* allocateBytesInternal(size_t amount, uint alignment); - // Try to allocate the given number of bytes without taking a lock. Fails if and only if there - // is no space left in the current chunk. - - void setDestructor(void* ptr, void (*destructor)(void*)); - // Schedule the given destructor to be executed when the Arena is destroyed. `ptr` must be a - // pointer previously returned by an `allocateBytes()` call for which `hasDisposer` was true. - - template - static void destroyArray(void* pointer) { - size_t elementCount = *reinterpret_cast(pointer); - constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); - DestructorOnlyArrayDisposer::instance.disposeImpl( - reinterpret_cast(pointer) + prefixSize, - sizeof(T), elementCount, elementCount, &destroyObject); - } - - template - static void destroyObject(void* pointer) { - dtor(*reinterpret_cast(pointer)); - } -}; - -// ======================================================================================= -// Inline implementation details - -template -T& Arena::allocate(Params&&... params) { - T& result = *reinterpret_cast(allocateBytes( - sizeof(T), alignof(T), !__has_trivial_destructor(T))); - if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { - ctor(result, kj::fwd(params)...); - } - if (!__has_trivial_destructor(T)) { - setDestructor(&result, &destroyObject); - } - return result; -} - -template -ArrayPtr Arena::allocateArray(size_t size) { - if (__has_trivial_destructor(T)) { - ArrayPtr result = - arrayPtr(reinterpret_cast(allocateBytes( - sizeof(T) * size, alignof(T), false)), size); - if (!__has_trivial_constructor(T)) { - for (size_t i = 0; i < size; i++) { - ctor(result[i]); - } - } - return result; - } else { - // Allocate with a 64-bit prefix in which we store the array size. - constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); - void* base = allocateBytes(sizeof(T) * size + prefixSize, alignof(T), true); - size_t& tag = *reinterpret_cast(base); - ArrayPtr result = - arrayPtr(reinterpret_cast(reinterpret_cast(base) + prefixSize), size); - setDestructor(base, &destroyArray); - - if (__has_trivial_constructor(T)) { - tag = size; - } else { - // In case of constructor exceptions, we need the tag to end up storing the number of objects - // that were successfully constructed, so that they'll be properly destroyed. - tag = 0; - for (size_t i = 0; i < size; i++) { - ctor(result[i]); - tag = i + 1; - } - } - return result; - } -} - -template -Own Arena::allocateOwn(Params&&... params) { - T& result = *reinterpret_cast(allocateBytes(sizeof(T), alignof(T), false)); - if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { - ctor(result, kj::fwd(params)...); - } - return Own(&result, DestructorOnlyDisposer::instance); -} - -template -Array Arena::allocateOwnArray(size_t size) { - ArrayBuilder result = allocateOwnArrayBuilder(size); - for (size_t i = 0; i < size; i++) { - result.add(); - } - return result.finish(); -} - -template -ArrayBuilder Arena::allocateOwnArrayBuilder(size_t capacity) { - return ArrayBuilder( - reinterpret_cast(allocateBytes(sizeof(T) * capacity, alignof(T), false)), - capacity, DestructorOnlyArrayDisposer::instance); -} - -} // namespace kj - -#endif // KJ_ARENA_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ARENA_H_ +#define KJ_ARENA_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" +#include "array.h" +#include "string.h" + +namespace kj { + +class Arena { + // A class which allows several objects to be allocated in contiguous chunks of memory, then + // frees them all at once. + // + // Allocating from the same Arena in multiple threads concurrently is NOT safe, because making + // it safe would require atomic operations that would slow down allocation even when + // single-threaded. If you need to use arena allocation in a multithreaded context, consider + // allocating thread-local arenas. + +public: + explicit Arena(size_t chunkSizeHint = 1024); + // Create an Arena. `chunkSizeHint` hints at where to start when allocating chunks, but is only + // a hint -- the Arena will, for example, allocate progressively larger chunks as time goes on, + // in order to reduce overall allocation overhead. + + explicit Arena(ArrayPtr scratch); + // Allocates from the given scratch space first, only resorting to the heap when it runs out. + + KJ_DISALLOW_COPY(Arena); + ~Arena() noexcept(false); + + template + T& allocate(Params&&... params); + template + ArrayPtr allocateArray(size_t size); + // Allocate an object or array of type T. If T has a non-trivial destructor, that destructor + // will be run during the Arena's destructor. Such destructors are run in opposite order of + // allocation. Note that these methods must maintain a list of destructors to call, which has + // overhead, but this overhead only applies if T has a non-trivial destructor. + + template + Own allocateOwn(Params&&... params); + template + Array allocateOwnArray(size_t size); + template + ArrayBuilder allocateOwnArrayBuilder(size_t capacity); + // Allocate an object or array of type T. Destructors are executed when the returned Own + // or Array goes out-of-scope, which must happen before the Arena is destroyed. This variant + // is useful when you need to control when the destructor is called. This variant also avoids + // the need for the Arena itself to keep track of destructors to call later, which may make it + // slightly more efficient. + + template + inline T& copy(T&& value) { return allocate>(kj::fwd(value)); } + // Allocate a copy of the given value in the arena. This is just a shortcut for calling the + // type's copy (or move) constructor. + + StringPtr copyString(StringPtr content); + // Make a copy of the given string inside the arena, and return a pointer to the copy. + +private: + struct ChunkHeader { + ChunkHeader* next; + byte* pos; // first unallocated byte in this chunk + byte* end; // end of this chunk + }; + struct ObjectHeader { + void (*destructor)(void*); + ObjectHeader* next; + }; + + size_t nextChunkSize; + ChunkHeader* chunkList = nullptr; + ObjectHeader* objectList = nullptr; + + ChunkHeader* currentChunk = nullptr; + + void cleanup(); + // Run all destructors, leaving the above pointers null. If a destructor throws, the State is + // left in a consistent state, such that if cleanup() is called again, it will pick up where + // it left off. + + void* allocateBytes(size_t amount, uint alignment, bool hasDisposer); + // Allocate the given number of bytes. `hasDisposer` must be true if `setDisposer()` may be + // called on this pointer later. + + void* allocateBytesInternal(size_t amount, uint alignment); + // Try to allocate the given number of bytes without taking a lock. Fails if and only if there + // is no space left in the current chunk. + + void setDestructor(void* ptr, void (*destructor)(void*)); + // Schedule the given destructor to be executed when the Arena is destroyed. `ptr` must be a + // pointer previously returned by an `allocateBytes()` call for which `hasDisposer` was true. + + template + static void destroyArray(void* pointer) { + size_t elementCount = *reinterpret_cast(pointer); + constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); + DestructorOnlyArrayDisposer::instance.disposeImpl( + reinterpret_cast(pointer) + prefixSize, + sizeof(T), elementCount, elementCount, &destroyObject); + } + + template + static void destroyObject(void* pointer) { + dtor(*reinterpret_cast(pointer)); + } +}; + +// ======================================================================================= +// Inline implementation details + +template +T& Arena::allocate(Params&&... params) { + T& result = *reinterpret_cast(allocateBytes( + sizeof(T), alignof(T), !__has_trivial_destructor(T))); + if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { + ctor(result, kj::fwd(params)...); + } + if (!__has_trivial_destructor(T)) { + setDestructor(&result, &destroyObject); + } + return result; +} + +template +ArrayPtr Arena::allocateArray(size_t size) { + if (__has_trivial_destructor(T)) { + ArrayPtr result = + arrayPtr(reinterpret_cast(allocateBytes( + sizeof(T) * size, alignof(T), false)), size); + if (!__has_trivial_constructor(T)) { + for (size_t i = 0; i < size; i++) { + ctor(result[i]); + } + } + return result; + } else { + // Allocate with a 64-bit prefix in which we store the array size. + constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); + void* base = allocateBytes(sizeof(T) * size + prefixSize, alignof(T), true); + size_t& tag = *reinterpret_cast(base); + ArrayPtr result = + arrayPtr(reinterpret_cast(reinterpret_cast(base) + prefixSize), size); + setDestructor(base, &destroyArray); + + if (__has_trivial_constructor(T)) { + tag = size; + } else { + // In case of constructor exceptions, we need the tag to end up storing the number of objects + // that were successfully constructed, so that they'll be properly destroyed. + tag = 0; + for (size_t i = 0; i < size; i++) { + ctor(result[i]); + tag = i + 1; + } + } + return result; + } +} + +template +Own Arena::allocateOwn(Params&&... params) { + T& result = *reinterpret_cast(allocateBytes(sizeof(T), alignof(T), false)); + if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { + ctor(result, kj::fwd(params)...); + } + return Own(&result, DestructorOnlyDisposer::instance); +} + +template +Array Arena::allocateOwnArray(size_t size) { + ArrayBuilder result = allocateOwnArrayBuilder(size); + for (size_t i = 0; i < size; i++) { + result.add(); + } + return result.finish(); +} + +template +ArrayBuilder Arena::allocateOwnArrayBuilder(size_t capacity) { + return ArrayBuilder( + reinterpret_cast(allocateBytes(sizeof(T) * capacity, alignof(T), false)), + capacity, DestructorOnlyArrayDisposer::instance); +} + +} // namespace kj + +#endif // KJ_ARENA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/array.h --- a/osx/include/kj/array.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/array.h Mon May 22 10:01:37 2017 +0100 @@ -1,723 +1,813 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ARRAY_H_ -#define KJ_ARRAY_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" -#include -#include - -namespace kj { - -// ======================================================================================= -// ArrayDisposer -- Implementation details. - -class ArrayDisposer { - // Much like Disposer from memory.h. - -protected: - // Do not declare a destructor, as doing so will force a global initializer for - // HeapArrayDisposer::instance. - - virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const = 0; - // Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr - // if the elements have trivial destructors. `capacity` is the amount of space that was - // allocated while `elementCount` is the number of elements that were actually constructed; - // these are always the same number for Array but may be different when using ArrayBuilder. - -public: - - template - void dispose(T* firstElement, size_t elementCount, size_t capacity) const; - // Helper wrapper around disposeImpl(). - // - // Callers must not call dispose() on the same array twice, even if the first call throws - // an exception. - -private: - template - struct Dispose_; -}; - -class ExceptionSafeArrayUtil { - // Utility class that assists in constructing or destroying elements of an array, where the - // constructor or destructor could throw exceptions. In case of an exception, - // ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been - // constructed but not destroyed. Remember that destructors that throw exceptions are required - // to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more - // than one exception will be thrown (and the program will not terminate). - -public: - inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount, - void (*destroyElement)(void*)) - : pos(reinterpret_cast(ptr) + elementSize * constructedElementCount), - elementSize(elementSize), constructedElementCount(constructedElementCount), - destroyElement(destroyElement) {} - KJ_DISALLOW_COPY(ExceptionSafeArrayUtil); - - inline ~ExceptionSafeArrayUtil() noexcept(false) { - if (constructedElementCount > 0) destroyAll(); - } - - void construct(size_t count, void (*constructElement)(void*)); - // Construct the given number of elements. - - void destroyAll(); - // Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope - // to ensure that one element throwing an exception does not prevent the others from being - // destroyed. - - void release() { constructedElementCount = 0; } - // Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements. - // Call this after you've successfully finished constructing. - -private: - byte* pos; - size_t elementSize; - size_t constructedElementCount; - void (*destroyElement)(void*); -}; - -class DestructorOnlyArrayDisposer: public ArrayDisposer { -public: - static const DestructorOnlyArrayDisposer instance; - - void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const override; -}; - -class NullArrayDisposer: public ArrayDisposer { - // An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't - // actually own its content. - -public: - static const NullArrayDisposer instance; - - void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const override; -}; - -// ======================================================================================= -// Array - -template -class Array { - // An owned array which will automatically be disposed of (using an ArrayDisposer) in the - // destructor. Can be moved, but not copied. Much like Own, but for arrays rather than - // single objects. - -public: - inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {} - inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {} - inline Array(Array&& other) noexcept - : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { - other.ptr = nullptr; - other.size_ = 0; - } - inline Array(Array>&& other) noexcept - : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { - other.ptr = nullptr; - other.size_ = 0; - } - inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer) - : ptr(firstElement), size_(size), disposer(&disposer) {} - - KJ_DISALLOW_COPY(Array); - inline ~Array() noexcept { dispose(); } - - inline operator ArrayPtr() { - return ArrayPtr(ptr, size_); - } - inline operator ArrayPtr() const { - return ArrayPtr(ptr, size_); - } - inline ArrayPtr asPtr() { - return ArrayPtr(ptr, size_); - } - inline ArrayPtr asPtr() const { - return ArrayPtr(ptr, size_); - } - - inline size_t size() const { return size_; } - inline T& operator[](size_t index) const { - KJ_IREQUIRE(index < size_, "Out-of-bounds Array access."); - return ptr[index]; - } - - inline const T* begin() const { return ptr; } - inline const T* end() const { return ptr + size_; } - inline const T& front() const { return *ptr; } - inline const T& back() const { return *(ptr + size_ - 1); } - inline T* begin() { return ptr; } - inline T* end() { return ptr + size_; } - inline T& front() { return *ptr; } - inline T& back() { return *(ptr + size_ - 1); } - - inline ArrayPtr slice(size_t start, size_t end) { - KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); - return ArrayPtr(ptr + start, end - start); - } - inline ArrayPtr slice(size_t start, size_t end) const { - KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); - return ArrayPtr(ptr + start, end - start); - } - - inline ArrayPtr asBytes() const { return asPtr().asBytes(); } - inline ArrayPtr> asBytes() { return asPtr().asBytes(); } - inline ArrayPtr asChars() const { return asPtr().asChars(); } - inline ArrayPtr> asChars() { return asPtr().asChars(); } - - inline Array> releaseAsBytes() { - // Like asBytes() but transfers ownership. - static_assert(sizeof(T) == sizeof(byte), - "releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars)."); - Array> result( - reinterpret_cast*>(ptr), size_, *disposer); - ptr = nullptr; - size_ = 0; - return result; - } - inline Array> releaseAsChars() { - // Like asChars() but transfers ownership. - static_assert(sizeof(T) == sizeof(PropagateConst), - "releaseAsChars() only possible on arrays with char-size elements (e.g. bytes)."); - Array> result( - reinterpret_cast*>(ptr), size_, *disposer); - ptr = nullptr; - size_ = 0; - return result; - } - - inline bool operator==(decltype(nullptr)) const { return size_ == 0; } - inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } - - inline Array& operator=(decltype(nullptr)) { - dispose(); - return *this; - } - - inline Array& operator=(Array&& other) { - dispose(); - ptr = other.ptr; - size_ = other.size_; - disposer = other.disposer; - other.ptr = nullptr; - other.size_ = 0; - return *this; - } - -private: - T* ptr; - size_t size_; - const ArrayDisposer* disposer; - - inline void dispose() { - // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly - // dispose again. - T* ptrCopy = ptr; - size_t sizeCopy = size_; - if (ptrCopy != nullptr) { - ptr = nullptr; - size_ = 0; - disposer->dispose(ptrCopy, sizeCopy, sizeCopy); - } - } - - template - friend class Array; -}; - -namespace _ { // private - -class HeapArrayDisposer final: public ArrayDisposer { -public: - template - static T* allocate(size_t count); - template - static T* allocateUninitialized(size_t count); - - static const HeapArrayDisposer instance; - -private: - static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity, - void (*constructElement)(void*), void (*destroyElement)(void*)); - // Allocates and constructs the array. Both function pointers are null if the constructor is - // trivial, otherwise destroyElement is null if the constructor doesn't throw. - - virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const override; - - template - struct Allocate_; -}; - -} // namespace _ (private) - -template -inline Array heapArray(size_t size) { - // Much like `heap()` from memory.h, allocates a new array on the heap. - - return Array(_::HeapArrayDisposer::allocate(size), size, - _::HeapArrayDisposer::instance); -} - -template Array heapArray(const T* content, size_t size); -template Array heapArray(ArrayPtr content); -template Array heapArray(ArrayPtr content); -template Array heapArray(Iterator begin, Iterator end); -template Array heapArray(std::initializer_list init); -// Allocate a heap array containing a copy of the given content. - -template -Array heapArrayFromIterable(Container&& a) { return heapArray(a.begin(), a.end()); } -template -Array heapArrayFromIterable(Array&& a) { return mv(a); } - -// ======================================================================================= -// ArrayBuilder - -template -class ArrayBuilder { - // Class which lets you build an Array specifying the exact constructor arguments for each - // element, rather than starting by default-constructing them. - -public: - ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} - ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} - explicit ArrayBuilder(RemoveConst* firstElement, size_t capacity, - const ArrayDisposer& disposer) - : ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity), - disposer(&disposer) {} - ArrayBuilder(ArrayBuilder&& other) - : ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) { - other.ptr = nullptr; - other.pos = nullptr; - other.endPtr = nullptr; - } - KJ_DISALLOW_COPY(ArrayBuilder); - inline ~ArrayBuilder() noexcept(false) { dispose(); } - - inline operator ArrayPtr() { - return arrayPtr(ptr, pos); - } - inline operator ArrayPtr() const { - return arrayPtr(ptr, pos); - } - inline ArrayPtr asPtr() { - return arrayPtr(ptr, pos); - } - inline ArrayPtr asPtr() const { - return arrayPtr(ptr, pos); - } - - inline size_t size() const { return pos - ptr; } - inline size_t capacity() const { return endPtr - ptr; } - inline T& operator[](size_t index) const { - KJ_IREQUIRE(index < implicitCast(pos - ptr), "Out-of-bounds Array access."); - return ptr[index]; - } - - inline const T* begin() const { return ptr; } - inline const T* end() const { return pos; } - inline const T& front() const { return *ptr; } - inline const T& back() const { return *(pos - 1); } - inline T* begin() { return ptr; } - inline T* end() { return pos; } - inline T& front() { return *ptr; } - inline T& back() { return *(pos - 1); } - - ArrayBuilder& operator=(ArrayBuilder&& other) { - dispose(); - ptr = other.ptr; - pos = other.pos; - endPtr = other.endPtr; - disposer = other.disposer; - other.ptr = nullptr; - other.pos = nullptr; - other.endPtr = nullptr; - return *this; - } - ArrayBuilder& operator=(decltype(nullptr)) { - dispose(); - return *this; - } - - template - T& add(Params&&... params) { - KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder."); - ctor(*pos, kj::fwd(params)...); - return *pos++; - } - - template - void addAll(Container&& container) { - addAll(container.begin(), container.end()); - } - - template - void addAll(Iterator start, Iterator end); - - void removeLast() { - KJ_IREQUIRE(pos > ptr, "No elements present to remove."); - kj::dtor(*--pos); - } - - Array finish() { - // We could safely remove this check if we assume that the disposer implementation doesn't - // need to know the original capacity, as is thes case with HeapArrayDisposer since it uses - // operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity - // in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this - // check might catch bugs. Probably people should use Vector if they want to build arrays - // without knowing the final size in advance. - KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely."); - Array result(reinterpret_cast(ptr), pos - ptr, *disposer); - ptr = nullptr; - pos = nullptr; - endPtr = nullptr; - return result; - } - - inline bool isFull() const { - return pos == endPtr; - } - -private: - T* ptr; - RemoveConst* pos; - T* endPtr; - const ArrayDisposer* disposer; - - inline void dispose() { - // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly - // dispose again. - T* ptrCopy = ptr; - T* posCopy = pos; - T* endCopy = endPtr; - if (ptrCopy != nullptr) { - ptr = nullptr; - pos = nullptr; - endPtr = nullptr; - disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy); - } - } -}; - -template -inline ArrayBuilder heapArrayBuilder(size_t size) { - // Like `heapArray()` but does not default-construct the elements. You must construct them - // manually by calling `add()`. - - return ArrayBuilder(_::HeapArrayDisposer::allocateUninitialized>(size), - size, _::HeapArrayDisposer::instance); -} - -// ======================================================================================= -// Inline Arrays - -template -class FixedArray { - // A fixed-width array whose storage is allocated inline rather than on the heap. - -public: - inline size_t size() const { return fixedSize; } - inline T* begin() { return content; } - inline T* end() { return content + fixedSize; } - inline const T* begin() const { return content; } - inline const T* end() const { return content + fixedSize; } - - inline operator ArrayPtr() { - return arrayPtr(content, fixedSize); - } - inline operator ArrayPtr() const { - return arrayPtr(content, fixedSize); - } - - inline T& operator[](size_t index) { return content[index]; } - inline const T& operator[](size_t index) const { return content[index]; } - -private: - T content[fixedSize]; -}; - -template -class CappedArray { - // Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit - // specified by the template parameter. - // - // TODO(someday): Don't construct elements past currentSize? - -public: - inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {} - inline explicit constexpr CappedArray(size_t s): currentSize(s) {} - - inline size_t size() const { return currentSize; } - inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; } - inline T* begin() { return content; } - inline T* end() { return content + currentSize; } - inline const T* begin() const { return content; } - inline const T* end() const { return content + currentSize; } - - inline operator ArrayPtr() { - return arrayPtr(content, currentSize); - } - inline operator ArrayPtr() const { - return arrayPtr(content, currentSize); - } - - inline T& operator[](size_t index) { return content[index]; } - inline const T& operator[](size_t index) const { return content[index]; } - -private: - size_t currentSize; - T content[fixedSize]; -}; - -// ======================================================================================= -// KJ_MAP - -#define KJ_MAP(elementName, array) \ - ::kj::_::Mapper(array) * [&](decltype(*(array).begin()) elementName) -// Applies some function to every element of an array, returning an Array of the results, with -// nice syntax. Example: -// -// StringPtr foo = "abcd"; -// Array bar = KJ_MAP(c, foo) -> char { return c + 1; }; -// KJ_ASSERT(str(bar) == "bcde"); - -namespace _ { // private - -template -struct Mapper { - T array; - Mapper(T&& array): array(kj::fwd(array)) {} - template - auto operator*(Func&& func) -> Array { - auto builder = heapArrayBuilder(array.size()); - for (auto iter = array.begin(); iter != array.end(); ++iter) { - builder.add(func(*iter)); - } - return builder.finish(); - } -}; - -} // namespace _ (private) - -// ======================================================================================= -// Inline implementation details - -template -struct ArrayDisposer::Dispose_ { - static void dispose(T* firstElement, size_t elementCount, size_t capacity, - const ArrayDisposer& disposer) { - disposer.disposeImpl(const_cast*>(firstElement), - sizeof(T), elementCount, capacity, nullptr); - } -}; -template -struct ArrayDisposer::Dispose_ { - static void destruct(void* ptr) { - kj::dtor(*reinterpret_cast(ptr)); - } - - static void dispose(T* firstElement, size_t elementCount, size_t capacity, - const ArrayDisposer& disposer) { - disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct); - } -}; - -template -void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const { - Dispose_::dispose(firstElement, elementCount, capacity, *this); -} - -namespace _ { // private - -template -struct HeapArrayDisposer::Allocate_ { - static T* allocate(size_t elementCount, size_t capacity) { - return reinterpret_cast(allocateImpl( - sizeof(T), elementCount, capacity, nullptr, nullptr)); - } -}; -template -struct HeapArrayDisposer::Allocate_ { - static void construct(void* ptr) { - kj::ctor(*reinterpret_cast(ptr)); - } - static T* allocate(size_t elementCount, size_t capacity) { - return reinterpret_cast(allocateImpl( - sizeof(T), elementCount, capacity, &construct, nullptr)); - } -}; -template -struct HeapArrayDisposer::Allocate_ { - static void construct(void* ptr) { - kj::ctor(*reinterpret_cast(ptr)); - } - static void destruct(void* ptr) { - kj::dtor(*reinterpret_cast(ptr)); - } - static T* allocate(size_t elementCount, size_t capacity) { - return reinterpret_cast(allocateImpl( - sizeof(T), elementCount, capacity, &construct, &destruct)); - } -}; - -template -T* HeapArrayDisposer::allocate(size_t count) { - return Allocate_::allocate(count, count); -} - -template -T* HeapArrayDisposer::allocateUninitialized(size_t count) { - return Allocate_::allocate(0, count); -} - -template ()> -struct CopyConstructArray_; - -template -struct CopyConstructArray_ { - static inline T* apply(T* __restrict__ pos, T* start, T* end) { - memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); - return pos + (end - start); - } -}; - -template -struct CopyConstructArray_ { - static inline T* apply(T* __restrict__ pos, const T* start, const T* end) { - memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); - return pos + (end - start); - } -}; - -template -struct CopyConstructArray_ { - static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) { - // Since both the copy constructor and assignment operator are trivial, we know that assignment - // is equivalent to copy-constructing. So we can make this case somewhat easier for the - // compiler to optimize. - while (start != end) { - *pos++ = *start++; - } - return pos; - } -}; - -template -struct CopyConstructArray_ { - struct ExceptionGuard { - T* start; - T* pos; - inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {} - ~ExceptionGuard() noexcept(false) { - while (pos > start) { - dtor(*--pos); - } - } - }; - - static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { - // Verify that T can be *implicitly* constructed from the source values. - if (false) implicitCast(*start); - - if (noexcept(T(*start))) { - while (start != end) { - ctor(*pos++, *start++); - } - return pos; - } else { - // Crap. This is complicated. - ExceptionGuard guard(pos); - while (start != end) { - ctor(*guard.pos, *start++); - ++guard.pos; - } - guard.start = guard.pos; - return guard.pos; - } - } -}; - -template -inline T* copyConstructArray(T* dst, Iterator start, Iterator end) { - return CopyConstructArray_>::apply(dst, start, end); -} - -} // namespace _ (private) - -template -template -void ArrayBuilder::addAll(Iterator start, Iterator end) { - pos = _::copyConstructArray(pos, start, end); -} - -template -Array heapArray(const T* content, size_t size) { - ArrayBuilder builder = heapArrayBuilder(size); - builder.addAll(content, content + size); - return builder.finish(); -} - -template -Array heapArray(T* content, size_t size) { - ArrayBuilder builder = heapArrayBuilder(size); - builder.addAll(content, content + size); - return builder.finish(); -} - -template -Array heapArray(ArrayPtr content) { - ArrayBuilder builder = heapArrayBuilder(content.size()); - builder.addAll(content); - return builder.finish(); -} - -template -Array heapArray(ArrayPtr content) { - ArrayBuilder builder = heapArrayBuilder(content.size()); - builder.addAll(content); - return builder.finish(); -} - -template Array -heapArray(Iterator begin, Iterator end) { - ArrayBuilder builder = heapArrayBuilder(end - begin); - builder.addAll(begin, end); - return builder.finish(); -} - -template -inline Array heapArray(std::initializer_list init) { - return heapArray(init.begin(), init.end()); -} - -} // namespace kj - -#endif // KJ_ARRAY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ARRAY_H_ +#define KJ_ARRAY_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" +#include +#include + +namespace kj { + +// ======================================================================================= +// ArrayDisposer -- Implementation details. + +class ArrayDisposer { + // Much like Disposer from memory.h. + +protected: + // Do not declare a destructor, as doing so will force a global initializer for + // HeapArrayDisposer::instance. + + virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const = 0; + // Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr + // if the elements have trivial destructors. `capacity` is the amount of space that was + // allocated while `elementCount` is the number of elements that were actually constructed; + // these are always the same number for Array but may be different when using ArrayBuilder. + +public: + + template + void dispose(T* firstElement, size_t elementCount, size_t capacity) const; + // Helper wrapper around disposeImpl(). + // + // Callers must not call dispose() on the same array twice, even if the first call throws + // an exception. + +private: + template + struct Dispose_; +}; + +class ExceptionSafeArrayUtil { + // Utility class that assists in constructing or destroying elements of an array, where the + // constructor or destructor could throw exceptions. In case of an exception, + // ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been + // constructed but not destroyed. Remember that destructors that throw exceptions are required + // to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more + // than one exception will be thrown (and the program will not terminate). + +public: + inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount, + void (*destroyElement)(void*)) + : pos(reinterpret_cast(ptr) + elementSize * constructedElementCount), + elementSize(elementSize), constructedElementCount(constructedElementCount), + destroyElement(destroyElement) {} + KJ_DISALLOW_COPY(ExceptionSafeArrayUtil); + + inline ~ExceptionSafeArrayUtil() noexcept(false) { + if (constructedElementCount > 0) destroyAll(); + } + + void construct(size_t count, void (*constructElement)(void*)); + // Construct the given number of elements. + + void destroyAll(); + // Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope + // to ensure that one element throwing an exception does not prevent the others from being + // destroyed. + + void release() { constructedElementCount = 0; } + // Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements. + // Call this after you've successfully finished constructing. + +private: + byte* pos; + size_t elementSize; + size_t constructedElementCount; + void (*destroyElement)(void*); +}; + +class DestructorOnlyArrayDisposer: public ArrayDisposer { +public: + static const DestructorOnlyArrayDisposer instance; + + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; +}; + +class NullArrayDisposer: public ArrayDisposer { + // An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't + // actually own its content. + +public: + static const NullArrayDisposer instance; + + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; +}; + +// ======================================================================================= +// Array + +template +class Array { + // An owned array which will automatically be disposed of (using an ArrayDisposer) in the + // destructor. Can be moved, but not copied. Much like Own, but for arrays rather than + // single objects. + +public: + inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {} + inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {} + inline Array(Array&& other) noexcept + : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { + other.ptr = nullptr; + other.size_ = 0; + } + inline Array(Array>&& other) noexcept + : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { + other.ptr = nullptr; + other.size_ = 0; + } + inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer) + : ptr(firstElement), size_(size), disposer(&disposer) {} + + KJ_DISALLOW_COPY(Array); + inline ~Array() noexcept { dispose(); } + + inline operator ArrayPtr() { + return ArrayPtr(ptr, size_); + } + inline operator ArrayPtr() const { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asPtr() { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asPtr() const { + return ArrayPtr(ptr, size_); + } + + inline size_t size() const { return size_; } + inline T& operator[](size_t index) const { + KJ_IREQUIRE(index < size_, "Out-of-bounds Array access."); + return ptr[index]; + } + + inline const T* begin() const { return ptr; } + inline const T* end() const { return ptr + size_; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(ptr + size_ - 1); } + inline T* begin() { return ptr; } + inline T* end() { return ptr + size_; } + inline T& front() { return *ptr; } + inline T& back() { return *(ptr + size_ - 1); } + + inline ArrayPtr slice(size_t start, size_t end) { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); + return ArrayPtr(ptr + start, end - start); + } + inline ArrayPtr slice(size_t start, size_t end) const { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); + return ArrayPtr(ptr + start, end - start); + } + + inline ArrayPtr asBytes() const { return asPtr().asBytes(); } + inline ArrayPtr> asBytes() { return asPtr().asBytes(); } + inline ArrayPtr asChars() const { return asPtr().asChars(); } + inline ArrayPtr> asChars() { return asPtr().asChars(); } + + inline Array> releaseAsBytes() { + // Like asBytes() but transfers ownership. + static_assert(sizeof(T) == sizeof(byte), + "releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars)."); + Array> result( + reinterpret_cast*>(ptr), size_, *disposer); + ptr = nullptr; + size_ = 0; + return result; + } + inline Array> releaseAsChars() { + // Like asChars() but transfers ownership. + static_assert(sizeof(T) == sizeof(PropagateConst), + "releaseAsChars() only possible on arrays with char-size elements (e.g. bytes)."); + Array> result( + reinterpret_cast*>(ptr), size_, *disposer); + ptr = nullptr; + size_ = 0; + return result; + } + + inline bool operator==(decltype(nullptr)) const { return size_ == 0; } + inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } + + inline Array& operator=(decltype(nullptr)) { + dispose(); + return *this; + } + + inline Array& operator=(Array&& other) { + dispose(); + ptr = other.ptr; + size_ = other.size_; + disposer = other.disposer; + other.ptr = nullptr; + other.size_ = 0; + return *this; + } + +private: + T* ptr; + size_t size_; + const ArrayDisposer* disposer; + + inline void dispose() { + // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly + // dispose again. + T* ptrCopy = ptr; + size_t sizeCopy = size_; + if (ptrCopy != nullptr) { + ptr = nullptr; + size_ = 0; + disposer->dispose(ptrCopy, sizeCopy, sizeCopy); + } + } + + template + friend class Array; +}; + +static_assert(!canMemcpy>(), "canMemcpy<>() is broken"); + +namespace _ { // private + +class HeapArrayDisposer final: public ArrayDisposer { +public: + template + static T* allocate(size_t count); + template + static T* allocateUninitialized(size_t count); + + static const HeapArrayDisposer instance; + +private: + static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity, + void (*constructElement)(void*), void (*destroyElement)(void*)); + // Allocates and constructs the array. Both function pointers are null if the constructor is + // trivial, otherwise destroyElement is null if the constructor doesn't throw. + + virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; + + template + struct Allocate_; +}; + +} // namespace _ (private) + +template +inline Array heapArray(size_t size) { + // Much like `heap()` from memory.h, allocates a new array on the heap. + + return Array(_::HeapArrayDisposer::allocate(size), size, + _::HeapArrayDisposer::instance); +} + +template Array heapArray(const T* content, size_t size); +template Array heapArray(ArrayPtr content); +template Array heapArray(ArrayPtr content); +template Array heapArray(Iterator begin, Iterator end); +template Array heapArray(std::initializer_list init); +// Allocate a heap array containing a copy of the given content. + +template +Array heapArrayFromIterable(Container&& a) { return heapArray(a.begin(), a.end()); } +template +Array heapArrayFromIterable(Array&& a) { return mv(a); } + +// ======================================================================================= +// ArrayBuilder + +template +class ArrayBuilder { + // Class which lets you build an Array specifying the exact constructor arguments for each + // element, rather than starting by default-constructing them. + +public: + ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} + ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} + explicit ArrayBuilder(RemoveConst* firstElement, size_t capacity, + const ArrayDisposer& disposer) + : ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity), + disposer(&disposer) {} + ArrayBuilder(ArrayBuilder&& other) + : ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) { + other.ptr = nullptr; + other.pos = nullptr; + other.endPtr = nullptr; + } + KJ_DISALLOW_COPY(ArrayBuilder); + inline ~ArrayBuilder() noexcept(false) { dispose(); } + + inline operator ArrayPtr() { + return arrayPtr(ptr, pos); + } + inline operator ArrayPtr() const { + return arrayPtr(ptr, pos); + } + inline ArrayPtr asPtr() { + return arrayPtr(ptr, pos); + } + inline ArrayPtr asPtr() const { + return arrayPtr(ptr, pos); + } + + inline size_t size() const { return pos - ptr; } + inline size_t capacity() const { return endPtr - ptr; } + inline T& operator[](size_t index) const { + KJ_IREQUIRE(index < implicitCast(pos - ptr), "Out-of-bounds Array access."); + return ptr[index]; + } + + inline const T* begin() const { return ptr; } + inline const T* end() const { return pos; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(pos - 1); } + inline T* begin() { return ptr; } + inline T* end() { return pos; } + inline T& front() { return *ptr; } + inline T& back() { return *(pos - 1); } + + ArrayBuilder& operator=(ArrayBuilder&& other) { + dispose(); + ptr = other.ptr; + pos = other.pos; + endPtr = other.endPtr; + disposer = other.disposer; + other.ptr = nullptr; + other.pos = nullptr; + other.endPtr = nullptr; + return *this; + } + ArrayBuilder& operator=(decltype(nullptr)) { + dispose(); + return *this; + } + + template + T& add(Params&&... params) { + KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder."); + ctor(*pos, kj::fwd(params)...); + return *pos++; + } + + template + void addAll(Container&& container) { + addAll()>( + container.begin(), container.end()); + } + + template + void addAll(Iterator start, Iterator end); + + void removeLast() { + KJ_IREQUIRE(pos > ptr, "No elements present to remove."); + kj::dtor(*--pos); + } + + void truncate(size_t size) { + KJ_IREQUIRE(size <= this->size(), "can't use truncate() to expand"); + + T* target = ptr + size; + if (__has_trivial_destructor(T)) { + pos = target; + } else { + while (pos > target) { + kj::dtor(*--pos); + } + } + } + + void resize(size_t size) { + KJ_IREQUIRE(size <= capacity(), "can't resize past capacity"); + + T* target = ptr + size; + if (target > pos) { + // expand + if (__has_trivial_constructor(T)) { + pos = target; + } else { + while (pos < target) { + kj::ctor(*pos++); + } + } + } else { + // truncate + if (__has_trivial_destructor(T)) { + pos = target; + } else { + while (pos > target) { + kj::dtor(*--pos); + } + } + } + } + + Array finish() { + // We could safely remove this check if we assume that the disposer implementation doesn't + // need to know the original capacity, as is thes case with HeapArrayDisposer since it uses + // operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity + // in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this + // check might catch bugs. Probably people should use Vector if they want to build arrays + // without knowing the final size in advance. + KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely."); + Array result(reinterpret_cast(ptr), pos - ptr, *disposer); + ptr = nullptr; + pos = nullptr; + endPtr = nullptr; + return result; + } + + inline bool isFull() const { + return pos == endPtr; + } + +private: + T* ptr; + RemoveConst* pos; + T* endPtr; + const ArrayDisposer* disposer; + + inline void dispose() { + // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly + // dispose again. + T* ptrCopy = ptr; + T* posCopy = pos; + T* endCopy = endPtr; + if (ptrCopy != nullptr) { + ptr = nullptr; + pos = nullptr; + endPtr = nullptr; + disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy); + } + } +}; + +template +inline ArrayBuilder heapArrayBuilder(size_t size) { + // Like `heapArray()` but does not default-construct the elements. You must construct them + // manually by calling `add()`. + + return ArrayBuilder(_::HeapArrayDisposer::allocateUninitialized>(size), + size, _::HeapArrayDisposer::instance); +} + +// ======================================================================================= +// Inline Arrays + +template +class FixedArray { + // A fixed-width array whose storage is allocated inline rather than on the heap. + +public: + inline size_t size() const { return fixedSize; } + inline T* begin() { return content; } + inline T* end() { return content + fixedSize; } + inline const T* begin() const { return content; } + inline const T* end() const { return content + fixedSize; } + + inline operator ArrayPtr() { + return arrayPtr(content, fixedSize); + } + inline operator ArrayPtr() const { + return arrayPtr(content, fixedSize); + } + + inline T& operator[](size_t index) { return content[index]; } + inline const T& operator[](size_t index) const { return content[index]; } + +private: + T content[fixedSize]; +}; + +template +class CappedArray { + // Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit + // specified by the template parameter. + // + // TODO(someday): Don't construct elements past currentSize? + +public: + inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {} + inline explicit constexpr CappedArray(size_t s): currentSize(s) {} + + inline size_t size() const { return currentSize; } + inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; } + inline T* begin() { return content; } + inline T* end() { return content + currentSize; } + inline const T* begin() const { return content; } + inline const T* end() const { return content + currentSize; } + + inline operator ArrayPtr() { + return arrayPtr(content, currentSize); + } + inline operator ArrayPtr() const { + return arrayPtr(content, currentSize); + } + + inline T& operator[](size_t index) { return content[index]; } + inline const T& operator[](size_t index) const { return content[index]; } + +private: + size_t currentSize; + T content[fixedSize]; +}; + +// ======================================================================================= +// KJ_MAP + +#define KJ_MAP(elementName, array) \ + ::kj::_::Mapper(array) * \ + [&](typename ::kj::_::Mapper::Element elementName) +// Applies some function to every element of an array, returning an Array of the results, with +// nice syntax. Example: +// +// StringPtr foo = "abcd"; +// Array bar = KJ_MAP(c, foo) -> char { return c + 1; }; +// KJ_ASSERT(str(bar) == "bcde"); + +namespace _ { // private + +template +struct Mapper { + T array; + Mapper(T&& array): array(kj::fwd(array)) {} + template + auto operator*(Func&& func) -> Array { + auto builder = heapArrayBuilder(array.size()); + for (auto iter = array.begin(); iter != array.end(); ++iter) { + builder.add(func(*iter)); + } + return builder.finish(); + } + typedef decltype(*kj::instance().begin()) Element; +}; + +template +struct Mapper { + T* array; + Mapper(T* array): array(array) {} + template + auto operator*(Func&& func) -> Array { + auto builder = heapArrayBuilder(s); + for (size_t i = 0; i < s; i++) { + builder.add(func(array[i])); + } + return builder.finish(); + } + typedef decltype(*array)& Element; +}; + +} // namespace _ (private) + +// ======================================================================================= +// Inline implementation details + +template +struct ArrayDisposer::Dispose_ { + static void dispose(T* firstElement, size_t elementCount, size_t capacity, + const ArrayDisposer& disposer) { + disposer.disposeImpl(const_cast*>(firstElement), + sizeof(T), elementCount, capacity, nullptr); + } +}; +template +struct ArrayDisposer::Dispose_ { + static void destruct(void* ptr) { + kj::dtor(*reinterpret_cast(ptr)); + } + + static void dispose(T* firstElement, size_t elementCount, size_t capacity, + const ArrayDisposer& disposer) { + disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct); + } +}; + +template +void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const { + Dispose_::dispose(firstElement, elementCount, capacity, *this); +} + +namespace _ { // private + +template +struct HeapArrayDisposer::Allocate_ { + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, nullptr, nullptr)); + } +}; +template +struct HeapArrayDisposer::Allocate_ { + static void construct(void* ptr) { + kj::ctor(*reinterpret_cast(ptr)); + } + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, &construct, nullptr)); + } +}; +template +struct HeapArrayDisposer::Allocate_ { + static void construct(void* ptr) { + kj::ctor(*reinterpret_cast(ptr)); + } + static void destruct(void* ptr) { + kj::dtor(*reinterpret_cast(ptr)); + } + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, &construct, &destruct)); + } +}; + +template +T* HeapArrayDisposer::allocate(size_t count) { + return Allocate_::allocate(count, count); +} + +template +T* HeapArrayDisposer::allocateUninitialized(size_t count) { + return Allocate_::allocate(0, count); +} + +template ()> +struct CopyConstructArray_; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, T* start, T* end) { + memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); + return pos + (end - start); + } +}; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, const T* start, const T* end) { + memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); + return pos + (end - start); + } +}; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Since both the copy constructor and assignment operator are trivial, we know that assignment + // is equivalent to copy-constructing. So we can make this case somewhat easier for the + // compiler to optimize. + while (start != end) { + *pos++ = *start++; + } + return pos; + } +}; + +template +struct CopyConstructArray_ { + struct ExceptionGuard { + T* start; + T* pos; + inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {} + ~ExceptionGuard() noexcept(false) { + while (pos > start) { + dtor(*--pos); + } + } + }; + + static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Verify that T can be *implicitly* constructed from the source values. + if (false) implicitCast(*start); + + if (noexcept(T(*start))) { + while (start != end) { + ctor(*pos++, *start++); + } + return pos; + } else { + // Crap. This is complicated. + ExceptionGuard guard(pos); + while (start != end) { + ctor(*guard.pos, *start++); + ++guard.pos; + } + guard.start = guard.pos; + return guard.pos; + } + } +}; + +template +struct CopyConstructArray_ { + // Actually move-construct. + + struct ExceptionGuard { + T* start; + T* pos; + inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {} + ~ExceptionGuard() noexcept(false) { + while (pos > start) { + dtor(*--pos); + } + } + }; + + static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Verify that T can be *implicitly* constructed from the source values. + if (false) implicitCast(kj::mv(*start)); + + if (noexcept(T(kj::mv(*start)))) { + while (start != end) { + ctor(*pos++, kj::mv(*start++)); + } + return pos; + } else { + // Crap. This is complicated. + ExceptionGuard guard(pos); + while (start != end) { + ctor(*guard.pos, kj::mv(*start++)); + ++guard.pos; + } + guard.start = guard.pos; + return guard.pos; + } + } +}; + +} // namespace _ (private) + +template +template +void ArrayBuilder::addAll(Iterator start, Iterator end) { + pos = _::CopyConstructArray_, Decay, move>::apply(pos, start, end); +} + +template +Array heapArray(const T* content, size_t size) { + ArrayBuilder builder = heapArrayBuilder(size); + builder.addAll(content, content + size); + return builder.finish(); +} + +template +Array heapArray(T* content, size_t size) { + ArrayBuilder builder = heapArrayBuilder(size); + builder.addAll(content, content + size); + return builder.finish(); +} + +template +Array heapArray(ArrayPtr content) { + ArrayBuilder builder = heapArrayBuilder(content.size()); + builder.addAll(content); + return builder.finish(); +} + +template +Array heapArray(ArrayPtr content) { + ArrayBuilder builder = heapArrayBuilder(content.size()); + builder.addAll(content); + return builder.finish(); +} + +template Array +heapArray(Iterator begin, Iterator end) { + ArrayBuilder builder = heapArrayBuilder(end - begin); + builder.addAll(begin, end); + return builder.finish(); +} + +template +inline Array heapArray(std::initializer_list init) { + return heapArray(init.begin(), init.end()); +} + +} // namespace kj + +#endif // KJ_ARRAY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async-inl.h --- a/osx/include/kj/async-inl.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/async-inl.h Mon May 22 10:01:37 2017 +0100 @@ -1,1085 +1,1112 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file contains extended inline implementation details that are required along with async.h. -// We move this all into a separate file to make async.h more readable. -// -// Non-inline declarations here are defined in async.c++. - -#ifndef KJ_ASYNC_H_ -#error "Do not include this directly; include kj/async.h." -#include "async.h" // help IDE parse this file -#endif - -#ifndef KJ_ASYNC_INL_H_ -#define KJ_ASYNC_INL_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -namespace kj { -namespace _ { // private - -template -class ExceptionOr; - -class ExceptionOrValue { -public: - ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {} - KJ_DISALLOW_COPY(ExceptionOrValue); - - void addException(Exception&& exception) { - if (this->exception == nullptr) { - this->exception = kj::mv(exception); - } - } - - template - ExceptionOr& as() { return *static_cast*>(this); } - template - const ExceptionOr& as() const { return *static_cast*>(this); } - - Maybe exception; - -protected: - // Allow subclasses to have move constructor / assignment. - ExceptionOrValue() = default; - ExceptionOrValue(ExceptionOrValue&& other) = default; - ExceptionOrValue& operator=(ExceptionOrValue&& other) = default; -}; - -template -class ExceptionOr: public ExceptionOrValue { -public: - ExceptionOr() = default; - ExceptionOr(T&& value): value(kj::mv(value)) {} - ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {} - ExceptionOr(ExceptionOr&&) = default; - ExceptionOr& operator=(ExceptionOr&&) = default; - - Maybe value; -}; - -class Event { - // An event waiting to be executed. Not for direct use by applications -- promises use this - // internally. - -public: - Event(); - ~Event() noexcept(false); - KJ_DISALLOW_COPY(Event); - - void armDepthFirst(); - // Enqueue this event so that `fire()` will be called from the event loop soon. - // - // Events scheduled in this way are executed in depth-first order: if an event callback arms - // more events, those events are placed at the front of the queue (in the order in which they - // were armed), so that they run immediately after the first event's callback returns. - // - // Depth-first event scheduling is appropriate for events that represent simple continuations - // of a previous event that should be globbed together for performance. Depth-first scheduling - // can lead to starvation, so any long-running task must occasionally yield with - // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses - // breadth-first.) - // - // To use breadth-first scheduling instead, use `armBreadthFirst()`. - - void armBreadthFirst(); - // Like `armDepthFirst()` except that the event is placed at the end of the queue. - - kj::String trace(); - // Dump debug info about this event. - - virtual _::PromiseNode* getInnerForTrace(); - // If this event wraps a PromiseNode, get that node. Used for debug tracing. - // Default implementation returns nullptr. - -protected: - virtual Maybe> fire() = 0; - // Fire the event. Possibly returns a pointer to itself, which will be discarded by the - // caller. This is the only way that an event can delete itself as a result of firing, as - // doing so from within fire() will throw an exception. - -private: - friend class kj::EventLoop; - EventLoop& loop; - Event* next; - Event** prev; - bool firing = false; -}; - -class PromiseNode { - // A Promise contains a chain of PromiseNodes tracking the pending transformations. - // - // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky - // use of pointers to ExceptionOrValue which actually point to ExceptionOr, but are only - // so down-cast in the few places that really need to be templated. Luckily this is all - // internal implementation details. - -public: - virtual void onReady(Event& event) noexcept = 0; - // Arms the given event when ready. - - virtual void setSelfPointer(Own* selfPtr) noexcept; - // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own - // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses - // this to shorten redundant chains. The default implementation does nothing; only - // ChainPromiseNode should implement this. - - virtual void get(ExceptionOrValue& output) noexcept = 0; - // Get the result. `output` points to an ExceptionOr into which the result will be written. - // Can only be called once, and only after the node is ready. Must be called directly from the - // event loop, with no application code on the stack. - - virtual PromiseNode* getInnerForTrace(); - // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing. - // Default implementation returns nullptr. - -protected: - class OnReadyEvent { - // Helper class for implementing onReady(). - - public: - void init(Event& newEvent); - // Returns true if arm() was already called. - - void arm(); - // Arms the event if init() has already been called and makes future calls to init() return - // true. - - private: - Event* event = nullptr; - }; -}; - -// ------------------------------------------------------------------- - -class ImmediatePromiseNodeBase: public PromiseNode { -public: - ImmediatePromiseNodeBase(); - ~ImmediatePromiseNodeBase() noexcept(false); - - void onReady(Event& event) noexcept override; -}; - -template -class ImmediatePromiseNode final: public ImmediatePromiseNodeBase { - // A promise that has already been resolved to an immediate value or exception. - -public: - ImmediatePromiseNode(ExceptionOr&& result): result(kj::mv(result)) {} - - void get(ExceptionOrValue& output) noexcept override { - output.as() = kj::mv(result); - } - -private: - ExceptionOr result; -}; - -class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase { -public: - ImmediateBrokenPromiseNode(Exception&& exception); - - void get(ExceptionOrValue& output) noexcept override; - -private: - Exception exception; -}; - -// ------------------------------------------------------------------- - -class AttachmentPromiseNodeBase: public PromiseNode { -public: - AttachmentPromiseNodeBase(Own&& dependency); - - void onReady(Event& event) noexcept override; - void get(ExceptionOrValue& output) noexcept override; - PromiseNode* getInnerForTrace() override; - -private: - Own dependency; - - void dropDependency(); - - template - friend class AttachmentPromiseNode; -}; - -template -class AttachmentPromiseNode final: public AttachmentPromiseNodeBase { - // A PromiseNode that holds on to some object (usually, an Own, but could be any movable - // object) until the promise resolves. - -public: - AttachmentPromiseNode(Own&& dependency, Attachment&& attachment) - : AttachmentPromiseNodeBase(kj::mv(dependency)), - attachment(kj::mv(attachment)) {} - - ~AttachmentPromiseNode() noexcept(false) { - // We need to make sure the dependency is deleted before we delete the attachment because the - // dependency may be using the attachment. - dropDependency(); - } - -private: - Attachment attachment; -}; - -// ------------------------------------------------------------------- - -class PtmfHelper { - // This class is a private helper for GetFunctorStartAddress. The class represents the internal - // representation of a pointer-to-member-function. - - template - friend struct GetFunctorStartAddress; - -#if __GNUG__ - void* ptr; - ptrdiff_t adj; - // Layout of a pointer-to-member-function used by GCC and compatible compilers. -#else -#error "TODO(port): PTMF instruction address extraction" -#endif - -#define BODY \ - PtmfHelper result; \ - static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \ - memcpy(&result, &p, sizeof(result)); \ - return result - - template - static PtmfHelper from(F p) { BODY; } - // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not - // overloaded nor a template. In this case the compiler is able to deduce the full function - // signature directly given the name since there is only one function with that name. - - template - static PtmfHelper from(R (C::*p)(NoInfer

...)) { BODY; } - template - static PtmfHelper from(R (C::*p)(NoInfer

...) const) { BODY; } - // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case - // the function must match exactly the containing type C, return type R, and parameter types P... - // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a - // guess at P. Luckily, if the function parameters are template parameters then it's not - // necessary to be precise about P. -#undef BODY - - void* apply(void* obj) { -#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) - if (adj & 1) { - ptrdiff_t voff = (ptrdiff_t)ptr; -#else - ptrdiff_t voff = (ptrdiff_t)ptr; - if (voff & 1) { - voff &= ~1; -#endif - return *(void**)(*(char**)obj + voff); - } else { - return ptr; - } - } -}; - -template -struct GetFunctorStartAddress { - // Given a functor (any object defining operator()), return the start address of the function, - // suitable for passing to addr2line to obtain a source file/line for debugging purposes. - // - // This turns out to be incredibly hard to implement in the presence of overloaded or templated - // functors. Therefore, we impose these specific restrictions, specific to our use case: - // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas - // anyway.) - // - The template parameters to GetFunctorStartAddress specify a hint as to the expected - // parameter types. If the functor is templated, its parameters must match exactly these types. - // (If it's not templated, ParamTypes are ignored.) - - template - static void* apply(Func&& func) { - typedef decltype(func(instance()...)) ReturnType; - return PtmfHelper::from, ParamTypes...>( - &Decay::operator()).apply(&func); - } -}; - -template <> -struct GetFunctorStartAddress: public GetFunctorStartAddress<> {}; -// Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function -// actually has no parameters. - -class TransformPromiseNodeBase: public PromiseNode { -public: - TransformPromiseNodeBase(Own&& dependency, void* continuationTracePtr); - - void onReady(Event& event) noexcept override; - void get(ExceptionOrValue& output) noexcept override; - PromiseNode* getInnerForTrace() override; - -private: - Own dependency; - void* continuationTracePtr; - - void dropDependency(); - void getDepResult(ExceptionOrValue& output); - - virtual void getImpl(ExceptionOrValue& output) = 0; - - template - friend class TransformPromiseNode; -}; - -template -class TransformPromiseNode final: public TransformPromiseNodeBase { - // A PromiseNode that transforms the result of another PromiseNode through an application-provided - // function (implements `then()`). - -public: - TransformPromiseNode(Own&& dependency, Func&& func, ErrorFunc&& errorHandler) - : TransformPromiseNodeBase(kj::mv(dependency), - GetFunctorStartAddress::apply(func)), - func(kj::fwd(func)), errorHandler(kj::fwd(errorHandler)) {} - - ~TransformPromiseNode() noexcept(false) { - // We need to make sure the dependency is deleted before we delete the continuations because it - // is a common pattern for the continuations to hold ownership of objects that might be in-use - // by the dependency. - dropDependency(); - } - -private: - Func func; - ErrorFunc errorHandler; - - void getImpl(ExceptionOrValue& output) override { - ExceptionOr depResult; - getDepResult(depResult); - KJ_IF_MAYBE(depException, depResult.exception) { - output.as() = handle( - MaybeVoidCaller>>::apply( - errorHandler, kj::mv(*depException))); - } else KJ_IF_MAYBE(depValue, depResult.value) { - output.as() = handle(MaybeVoidCaller::apply(func, kj::mv(*depValue))); - } - } - - ExceptionOr handle(T&& value) { - return kj::mv(value); - } - ExceptionOr handle(PropagateException::Bottom&& value) { - return ExceptionOr(false, value.asException()); - } -}; - -// ------------------------------------------------------------------- - -class ForkHubBase; - -class ForkBranchBase: public PromiseNode { -public: - ForkBranchBase(Own&& hub); - ~ForkBranchBase() noexcept(false); - - void hubReady() noexcept; - // Called by the hub to indicate that it is ready. - - // implements PromiseNode ------------------------------------------ - void onReady(Event& event) noexcept override; - PromiseNode* getInnerForTrace() override; - -protected: - inline ExceptionOrValue& getHubResultRef(); - - void releaseHub(ExceptionOrValue& output); - // Release the hub. If an exception is thrown, add it to `output`. - -private: - OnReadyEvent onReadyEvent; - - Own hub; - ForkBranchBase* next = nullptr; - ForkBranchBase** prevPtr = nullptr; - - friend class ForkHubBase; -}; - -template T copyOrAddRef(T& t) { return t; } -template Own copyOrAddRef(Own& t) { return t->addRef(); } - -template -class ForkBranch final: public ForkBranchBase { - // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives - // a const reference. - -public: - ForkBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} - - void get(ExceptionOrValue& output) noexcept override { - ExceptionOr& hubResult = getHubResultRef().template as(); - KJ_IF_MAYBE(value, hubResult.value) { - output.as().value = copyOrAddRef(*value); - } else { - output.as().value = nullptr; - } - output.exception = hubResult.exception; - releaseHub(output); - } -}; - -template -class SplitBranch final: public ForkBranchBase { - // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives - // a const reference. - -public: - SplitBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} - - typedef kj::Decay(kj::instance()))> Element; - - void get(ExceptionOrValue& output) noexcept override { - ExceptionOr& hubResult = getHubResultRef().template as(); - KJ_IF_MAYBE(value, hubResult.value) { - output.as().value = kj::mv(kj::get(*value)); - } else { - output.as().value = nullptr; - } - output.exception = hubResult.exception; - releaseHub(output); - } -}; - -// ------------------------------------------------------------------- - -class ForkHubBase: public Refcounted, protected Event { -public: - ForkHubBase(Own&& inner, ExceptionOrValue& resultRef); - - inline ExceptionOrValue& getResultRef() { return resultRef; } - -private: - Own inner; - ExceptionOrValue& resultRef; - - ForkBranchBase* headBranch = nullptr; - ForkBranchBase** tailBranch = &headBranch; - // Tail becomes null once the inner promise is ready and all branches have been notified. - - Maybe> fire() override; - _::PromiseNode* getInnerForTrace() override; - - friend class ForkBranchBase; -}; - -template -class ForkHub final: public ForkHubBase { - // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces - // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if - // possible). - -public: - ForkHub(Own&& inner): ForkHubBase(kj::mv(inner), result) {} - - Promise<_::UnfixVoid> addBranch() { - return Promise<_::UnfixVoid>(false, kj::heap>(addRef(*this))); - } - - _::SplitTuplePromise split() { - return splitImpl(MakeIndexes()>()); - } - -private: - ExceptionOr result; - - template - _::SplitTuplePromise splitImpl(Indexes) { - return kj::tuple(addSplit()...); - } - - template - Promise::Element>> addSplit() { - return Promise::Element>>( - false, maybeChain(kj::heap>(addRef(*this)), - implicitCast::Element*>(nullptr))); - } -}; - -inline ExceptionOrValue& ForkBranchBase::getHubResultRef() { - return hub->getResultRef(); -} - -// ------------------------------------------------------------------- - -class ChainPromiseNode final: public PromiseNode, public Event { - // Promise node which reduces Promise> to Promise. - // - // `Event` is only a public base class because otherwise we can't cast Own to - // Own. Ugh, templates and private... - -public: - explicit ChainPromiseNode(Own inner); - ~ChainPromiseNode() noexcept(false); - - void onReady(Event& event) noexcept override; - void setSelfPointer(Own* selfPtr) noexcept override; - void get(ExceptionOrValue& output) noexcept override; - PromiseNode* getInnerForTrace() override; - -private: - enum State { - STEP1, - STEP2 - }; - - State state; - - Own inner; - // In STEP1, a PromiseNode for a Promise. - // In STEP2, a PromiseNode for a T. - - Event* onReadyEvent = nullptr; - Own* selfPtr = nullptr; - - Maybe> fire() override; -}; - -template -Own maybeChain(Own&& node, Promise*) { - return heap(kj::mv(node)); -} - -template -Own&& maybeChain(Own&& node, T*) { - return kj::mv(node); -} - -// ------------------------------------------------------------------- - -class ExclusiveJoinPromiseNode final: public PromiseNode { -public: - ExclusiveJoinPromiseNode(Own left, Own right); - ~ExclusiveJoinPromiseNode() noexcept(false); - - void onReady(Event& event) noexcept override; - void get(ExceptionOrValue& output) noexcept override; - PromiseNode* getInnerForTrace() override; - -private: - class Branch: public Event { - public: - Branch(ExclusiveJoinPromiseNode& joinNode, Own dependency); - ~Branch() noexcept(false); - - bool get(ExceptionOrValue& output); - // Returns true if this is the side that finished. - - Maybe> fire() override; - _::PromiseNode* getInnerForTrace() override; - - private: - ExclusiveJoinPromiseNode& joinNode; - Own dependency; - }; - - Branch left; - Branch right; - OnReadyEvent onReadyEvent; -}; - -// ------------------------------------------------------------------- - -class ArrayJoinPromiseNodeBase: public PromiseNode { -public: - ArrayJoinPromiseNodeBase(Array> promises, - ExceptionOrValue* resultParts, size_t partSize); - ~ArrayJoinPromiseNodeBase() noexcept(false); - - void onReady(Event& event) noexcept override final; - void get(ExceptionOrValue& output) noexcept override final; - PromiseNode* getInnerForTrace() override final; - -protected: - virtual void getNoError(ExceptionOrValue& output) noexcept = 0; - // Called to compile the result only in the case where there were no errors. - -private: - uint countLeft; - OnReadyEvent onReadyEvent; - - class Branch final: public Event { - public: - Branch(ArrayJoinPromiseNodeBase& joinNode, Own dependency, - ExceptionOrValue& output); - ~Branch() noexcept(false); - - Maybe> fire() override; - _::PromiseNode* getInnerForTrace() override; - - Maybe getPart(); - // Calls dependency->get(output). If there was an exception, return it. - - private: - ArrayJoinPromiseNodeBase& joinNode; - Own dependency; - ExceptionOrValue& output; - }; - - Array branches; -}; - -template -class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { -public: - ArrayJoinPromiseNode(Array> promises, - Array> resultParts) - : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr)), - resultParts(kj::mv(resultParts)) {} - -protected: - void getNoError(ExceptionOrValue& output) noexcept override { - auto builder = heapArrayBuilder(resultParts.size()); - for (auto& part: resultParts) { - KJ_IASSERT(part.value != nullptr, - "Bug in KJ promise framework: Promise result had neither value no exception."); - builder.add(kj::mv(*_::readMaybe(part.value))); - } - output.as>() = builder.finish(); - } - -private: - Array> resultParts; -}; - -template <> -class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { -public: - ArrayJoinPromiseNode(Array> promises, - Array> resultParts); - ~ArrayJoinPromiseNode(); - -protected: - void getNoError(ExceptionOrValue& output) noexcept override; - -private: - Array> resultParts; -}; - -// ------------------------------------------------------------------- - -class EagerPromiseNodeBase: public PromiseNode, protected Event { - // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly - // evaluate it. - -public: - EagerPromiseNodeBase(Own&& dependency, ExceptionOrValue& resultRef); - - void onReady(Event& event) noexcept override; - PromiseNode* getInnerForTrace() override; - -private: - Own dependency; - OnReadyEvent onReadyEvent; - - ExceptionOrValue& resultRef; - - Maybe> fire() override; -}; - -template -class EagerPromiseNode final: public EagerPromiseNodeBase { -public: - EagerPromiseNode(Own&& dependency) - : EagerPromiseNodeBase(kj::mv(dependency), result) {} - - void get(ExceptionOrValue& output) noexcept override { - output.as() = kj::mv(result); - } - -private: - ExceptionOr result; -}; - -template -Own spark(Own&& node) { - // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting - // on it. - return heap>(kj::mv(node)); -} - -// ------------------------------------------------------------------- - -class AdapterPromiseNodeBase: public PromiseNode { -public: - void onReady(Event& event) noexcept override; - -protected: - inline void setReady() { - onReadyEvent.arm(); - } - -private: - OnReadyEvent onReadyEvent; -}; - -template -class AdapterPromiseNode final: public AdapterPromiseNodeBase, - private PromiseFulfiller> { - // A PromiseNode that wraps a PromiseAdapter. - -public: - template - AdapterPromiseNode(Params&&... params) - : adapter(static_cast>&>(*this), kj::fwd(params)...) {} - - void get(ExceptionOrValue& output) noexcept override { - KJ_IREQUIRE(!isWaiting()); - output.as() = kj::mv(result); - } - -private: - ExceptionOr result; - bool waiting = true; - Adapter adapter; - - void fulfill(T&& value) override { - if (waiting) { - waiting = false; - result = ExceptionOr(kj::mv(value)); - setReady(); - } - } - - void reject(Exception&& exception) override { - if (waiting) { - waiting = false; - result = ExceptionOr(false, kj::mv(exception)); - setReady(); - } - } - - bool isWaiting() override { - return waiting; - } -}; - -} // namespace _ (private) - -// ======================================================================================= - -template -Promise::Promise(_::FixVoid value) - : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid>>(kj::mv(value))) {} - -template -Promise::Promise(kj::Exception&& exception) - : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {} - -template -template -PromiseForResult Promise::then(Func&& func, ErrorFunc&& errorHandler) { - typedef _::FixVoid<_::ReturnType> ResultT; - - Own<_::PromiseNode> intermediate = - heap<_::TransformPromiseNode, Func, ErrorFunc>>( - kj::mv(node), kj::fwd(func), kj::fwd(errorHandler)); - return PromiseForResult(false, - _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); -} - -namespace _ { // private - -template -struct IdentityFunc { - inline T operator()(T&& value) const { - return kj::mv(value); - } -}; -template -struct IdentityFunc> { - inline Promise operator()(T&& value) const { - return kj::mv(value); - } -}; -template <> -struct IdentityFunc { - inline void operator()() const {} -}; -template <> -struct IdentityFunc> { - Promise operator()() const; - // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly, - // Cap'n Proto relies on being able to include this header without creating such a link-time - // dependency. -}; - -} // namespace _ (private) - -template -template -Promise Promise::catch_(ErrorFunc&& errorHandler) { - // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case, - // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise, - // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually - // return a promise. So we make our Func return match ErrorFunc. - return then(_::IdentityFunc()))>(), - kj::fwd(errorHandler)); -} - -template -T Promise::wait(WaitScope& waitScope) { - _::ExceptionOr<_::FixVoid> result; - - waitImpl(kj::mv(node), result, waitScope); - - KJ_IF_MAYBE(value, result.value) { - KJ_IF_MAYBE(exception, result.exception) { - throwRecoverableException(kj::mv(*exception)); - } - return _::returnMaybeVoid(kj::mv(*value)); - } else KJ_IF_MAYBE(exception, result.exception) { - throwFatalException(kj::mv(*exception)); - } else { - // Result contained neither a value nor an exception? - KJ_UNREACHABLE; - } -} - -template -ForkedPromise Promise::fork() { - return ForkedPromise(false, refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))); -} - -template -Promise ForkedPromise::addBranch() { - return hub->addBranch(); -} - -template -_::SplitTuplePromise Promise::split() { - return refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))->split(); -} - -template -Promise Promise::exclusiveJoin(Promise&& other) { - return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node))); -} - -template -template -Promise Promise::attach(Attachments&&... attachments) { - return Promise(false, kj::heap<_::AttachmentPromiseNode>>( - kj::mv(node), kj::tuple(kj::fwd(attachments)...))); -} - -template -template -Promise Promise::eagerlyEvaluate(ErrorFunc&& errorHandler) { - // See catch_() for commentary. - return Promise(false, _::spark<_::FixVoid>(then( - _::IdentityFunc()))>(), - kj::fwd(errorHandler)).node)); -} - -template -Promise Promise::eagerlyEvaluate(decltype(nullptr)) { - return Promise(false, _::spark<_::FixVoid>(kj::mv(node))); -} - -template -kj::String Promise::trace() { - return PromiseBase::trace(); -} - -template -inline PromiseForResult evalLater(Func&& func) { - return _::yield().then(kj::fwd(func), _::PropagateException()); -} - -template -inline PromiseForResult evalNow(Func&& func) { - PromiseForResult result = nullptr; - KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { - result = func(); - })) { - result = kj::mv(*e); - } - return result; -} - -template -template -void Promise::detach(ErrorFunc&& errorHandler) { - return _::detach(then([](T&&) {}, kj::fwd(errorHandler))); -} - -template <> -template -void Promise::detach(ErrorFunc&& errorHandler) { - return _::detach(then([]() {}, kj::fwd(errorHandler))); -} - -template -Promise> joinPromises(Array>&& promises) { - return Promise>(false, kj::heap<_::ArrayJoinPromiseNode>( - KJ_MAP(p, promises) { return kj::mv(p.node); }, - heapArray<_::ExceptionOr>(promises.size()))); -} - -// ======================================================================================= - -namespace _ { // private - -template -class WeakFulfiller final: public PromiseFulfiller, private kj::Disposer { - // A wrapper around PromiseFulfiller which can be detached. - // - // There are a couple non-trivialities here: - // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly - // rejected. - // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been - // detached from the underlying fulfiller, because otherwise the later detach() call will go - // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the - // refcount never goes over 2 and we manually implement the refcounting because we need to do - // other special things when each side detaches anyway. To this end, WeakFulfiller is its own - // Disposer -- dispose() is called when the application discards its owned pointer to the - // fulfiller and detach() is called when the promise is destroyed. - -public: - KJ_DISALLOW_COPY(WeakFulfiller); - - static kj::Own make() { - WeakFulfiller* ptr = new WeakFulfiller; - return Own(ptr, *ptr); - } - - void fulfill(FixVoid&& value) override { - if (inner != nullptr) { - inner->fulfill(kj::mv(value)); - } - } - - void reject(Exception&& exception) override { - if (inner != nullptr) { - inner->reject(kj::mv(exception)); - } - } - - bool isWaiting() override { - return inner != nullptr && inner->isWaiting(); - } - - void attach(PromiseFulfiller& newInner) { - inner = &newInner; - } - - void detach(PromiseFulfiller& from) { - if (inner == nullptr) { - // Already disposed. - delete this; - } else { - KJ_IREQUIRE(inner == &from); - inner = nullptr; - } - } - -private: - mutable PromiseFulfiller* inner; - - WeakFulfiller(): inner(nullptr) {} - - void disposeImpl(void* pointer) const override { - // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type? - - if (inner == nullptr) { - // Already detached. - delete this; - } else { - if (inner->isWaiting()) { - inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, - kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise."))); - } - inner = nullptr; - } - } -}; - -template -class PromiseAndFulfillerAdapter { -public: - PromiseAndFulfillerAdapter(PromiseFulfiller& fulfiller, - WeakFulfiller& wrapper) - : fulfiller(fulfiller), wrapper(wrapper) { - wrapper.attach(fulfiller); - } - - ~PromiseAndFulfillerAdapter() noexcept(false) { - wrapper.detach(fulfiller); - } - -private: - PromiseFulfiller& fulfiller; - WeakFulfiller& wrapper; -}; - -} // namespace _ (private) - -template -template -bool PromiseFulfiller::rejectIfThrows(Func&& func) { - KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { - reject(kj::mv(*exception)); - return false; - } else { - return true; - } -} - -template -bool PromiseFulfiller::rejectIfThrows(Func&& func) { - KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { - reject(kj::mv(*exception)); - return false; - } else { - return true; - } -} - -template -Promise newAdaptedPromise(Params&&... adapterConstructorParams) { - return Promise(false, heap<_::AdapterPromiseNode<_::FixVoid, Adapter>>( - kj::fwd(adapterConstructorParams)...)); -} - -template -PromiseFulfillerPair newPromiseAndFulfiller() { - auto wrapper = _::WeakFulfiller::make(); - - Own<_::PromiseNode> intermediate( - heap<_::AdapterPromiseNode<_::FixVoid, _::PromiseAndFulfillerAdapter>>(*wrapper)); - Promise<_::JoinPromises> promise(false, - _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); - - return PromiseFulfillerPair { kj::mv(promise), kj::mv(wrapper) }; -} - -} // namespace kj - -#endif // KJ_ASYNC_INL_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains extended inline implementation details that are required along with async.h. +// We move this all into a separate file to make async.h more readable. +// +// Non-inline declarations here are defined in async.c++. + +#ifndef KJ_ASYNC_H_ +#error "Do not include this directly; include kj/async.h." +#include "async.h" // help IDE parse this file +#endif + +#ifndef KJ_ASYNC_INL_H_ +#define KJ_ASYNC_INL_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +namespace kj { +namespace _ { // private + +template +class ExceptionOr; + +class ExceptionOrValue { +public: + ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {} + KJ_DISALLOW_COPY(ExceptionOrValue); + + void addException(Exception&& exception) { + if (this->exception == nullptr) { + this->exception = kj::mv(exception); + } + } + + template + ExceptionOr& as() { return *static_cast*>(this); } + template + const ExceptionOr& as() const { return *static_cast*>(this); } + + Maybe exception; + +protected: + // Allow subclasses to have move constructor / assignment. + ExceptionOrValue() = default; + ExceptionOrValue(ExceptionOrValue&& other) = default; + ExceptionOrValue& operator=(ExceptionOrValue&& other) = default; +}; + +template +class ExceptionOr: public ExceptionOrValue { +public: + ExceptionOr() = default; + ExceptionOr(T&& value): value(kj::mv(value)) {} + ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {} + ExceptionOr(ExceptionOr&&) = default; + ExceptionOr& operator=(ExceptionOr&&) = default; + + Maybe value; +}; + +class Event { + // An event waiting to be executed. Not for direct use by applications -- promises use this + // internally. + +public: + Event(); + ~Event() noexcept(false); + KJ_DISALLOW_COPY(Event); + + void armDepthFirst(); + // Enqueue this event so that `fire()` will be called from the event loop soon. + // + // Events scheduled in this way are executed in depth-first order: if an event callback arms + // more events, those events are placed at the front of the queue (in the order in which they + // were armed), so that they run immediately after the first event's callback returns. + // + // Depth-first event scheduling is appropriate for events that represent simple continuations + // of a previous event that should be globbed together for performance. Depth-first scheduling + // can lead to starvation, so any long-running task must occasionally yield with + // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses + // breadth-first.) + // + // To use breadth-first scheduling instead, use `armBreadthFirst()`. + + void armBreadthFirst(); + // Like `armDepthFirst()` except that the event is placed at the end of the queue. + + kj::String trace(); + // Dump debug info about this event. + + virtual _::PromiseNode* getInnerForTrace(); + // If this event wraps a PromiseNode, get that node. Used for debug tracing. + // Default implementation returns nullptr. + +protected: + virtual Maybe> fire() = 0; + // Fire the event. Possibly returns a pointer to itself, which will be discarded by the + // caller. This is the only way that an event can delete itself as a result of firing, as + // doing so from within fire() will throw an exception. + +private: + friend class kj::EventLoop; + EventLoop& loop; + Event* next; + Event** prev; + bool firing = false; +}; + +class PromiseNode { + // A Promise contains a chain of PromiseNodes tracking the pending transformations. + // + // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky + // use of pointers to ExceptionOrValue which actually point to ExceptionOr, but are only + // so down-cast in the few places that really need to be templated. Luckily this is all + // internal implementation details. + +public: + virtual void onReady(Event& event) noexcept = 0; + // Arms the given event when ready. + + virtual void setSelfPointer(Own* selfPtr) noexcept; + // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own + // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses + // this to shorten redundant chains. The default implementation does nothing; only + // ChainPromiseNode should implement this. + + virtual void get(ExceptionOrValue& output) noexcept = 0; + // Get the result. `output` points to an ExceptionOr into which the result will be written. + // Can only be called once, and only after the node is ready. Must be called directly from the + // event loop, with no application code on the stack. + + virtual PromiseNode* getInnerForTrace(); + // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing. + // Default implementation returns nullptr. + +protected: + class OnReadyEvent { + // Helper class for implementing onReady(). + + public: + void init(Event& newEvent); + // Returns true if arm() was already called. + + void arm(); + // Arms the event if init() has already been called and makes future calls to init() return + // true. + + private: + Event* event = nullptr; + }; +}; + +// ------------------------------------------------------------------- + +class ImmediatePromiseNodeBase: public PromiseNode { +public: + ImmediatePromiseNodeBase(); + ~ImmediatePromiseNodeBase() noexcept(false); + + void onReady(Event& event) noexcept override; +}; + +template +class ImmediatePromiseNode final: public ImmediatePromiseNodeBase { + // A promise that has already been resolved to an immediate value or exception. + +public: + ImmediatePromiseNode(ExceptionOr&& result): result(kj::mv(result)) {} + + void get(ExceptionOrValue& output) noexcept override { + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; +}; + +class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase { +public: + ImmediateBrokenPromiseNode(Exception&& exception); + + void get(ExceptionOrValue& output) noexcept override; + +private: + Exception exception; +}; + +// ------------------------------------------------------------------- + +class AttachmentPromiseNodeBase: public PromiseNode { +public: + AttachmentPromiseNodeBase(Own&& dependency); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + + void dropDependency(); + + template + friend class AttachmentPromiseNode; +}; + +template +class AttachmentPromiseNode final: public AttachmentPromiseNodeBase { + // A PromiseNode that holds on to some object (usually, an Own, but could be any movable + // object) until the promise resolves. + +public: + AttachmentPromiseNode(Own&& dependency, Attachment&& attachment) + : AttachmentPromiseNodeBase(kj::mv(dependency)), + attachment(kj::mv(attachment)) {} + + ~AttachmentPromiseNode() noexcept(false) { + // We need to make sure the dependency is deleted before we delete the attachment because the + // dependency may be using the attachment. + dropDependency(); + } + +private: + Attachment attachment; +}; + +// ------------------------------------------------------------------- + +class PtmfHelper { + // This class is a private helper for GetFunctorStartAddress. The class represents the internal + // representation of a pointer-to-member-function. + + template + friend struct GetFunctorStartAddress; + +#if __GNUG__ + + void* ptr; + ptrdiff_t adj; + // Layout of a pointer-to-member-function used by GCC and compatible compilers. + + void* apply(void* obj) { +#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) + if (adj & 1) { + ptrdiff_t voff = (ptrdiff_t)ptr; +#else + ptrdiff_t voff = (ptrdiff_t)ptr; + if (voff & 1) { + voff &= ~1; +#endif + return *(void**)(*(char**)obj + voff); + } else { + return ptr; + } + } + +#define BODY \ + PtmfHelper result; \ + static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \ + memcpy(&result, &p, sizeof(result)); \ + return result + +#else // __GNUG__ + + void* apply(void* obj) { return nullptr; } + // TODO(port): PTMF instruction address extraction + +#define BODY return PtmfHelper{} + +#endif // __GNUG__, else + + template + static PtmfHelper from(F p) { BODY; } + // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not + // overloaded nor a template. In this case the compiler is able to deduce the full function + // signature directly given the name since there is only one function with that name. + + template + static PtmfHelper from(R (C::*p)(NoInfer

...)) { BODY; } + template + static PtmfHelper from(R (C::*p)(NoInfer

...) const) { BODY; } + // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case + // the function must match exactly the containing type C, return type R, and parameter types P... + // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a + // guess at P. Luckily, if the function parameters are template parameters then it's not + // necessary to be precise about P. +#undef BODY +}; + +template +struct GetFunctorStartAddress { + // Given a functor (any object defining operator()), return the start address of the function, + // suitable for passing to addr2line to obtain a source file/line for debugging purposes. + // + // This turns out to be incredibly hard to implement in the presence of overloaded or templated + // functors. Therefore, we impose these specific restrictions, specific to our use case: + // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas + // anyway.) + // - The template parameters to GetFunctorStartAddress specify a hint as to the expected + // parameter types. If the functor is templated, its parameters must match exactly these types. + // (If it's not templated, ParamTypes are ignored.) + + template + static void* apply(Func&& func) { + typedef decltype(func(instance()...)) ReturnType; + return PtmfHelper::from, ParamTypes...>( + &Decay::operator()).apply(&func); + } +}; + +template <> +struct GetFunctorStartAddress: public GetFunctorStartAddress<> {}; +// Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function +// actually has no parameters. + +class TransformPromiseNodeBase: public PromiseNode { +public: + TransformPromiseNodeBase(Own&& dependency, void* continuationTracePtr); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + void* continuationTracePtr; + + void dropDependency(); + void getDepResult(ExceptionOrValue& output); + + virtual void getImpl(ExceptionOrValue& output) = 0; + + template + friend class TransformPromiseNode; +}; + +template +class TransformPromiseNode final: public TransformPromiseNodeBase { + // A PromiseNode that transforms the result of another PromiseNode through an application-provided + // function (implements `then()`). + +public: + TransformPromiseNode(Own&& dependency, Func&& func, ErrorFunc&& errorHandler) + : TransformPromiseNodeBase(kj::mv(dependency), + GetFunctorStartAddress::apply(func)), + func(kj::fwd(func)), errorHandler(kj::fwd(errorHandler)) {} + + ~TransformPromiseNode() noexcept(false) { + // We need to make sure the dependency is deleted before we delete the continuations because it + // is a common pattern for the continuations to hold ownership of objects that might be in-use + // by the dependency. + dropDependency(); + } + +private: + Func func; + ErrorFunc errorHandler; + + void getImpl(ExceptionOrValue& output) override { + ExceptionOr depResult; + getDepResult(depResult); + KJ_IF_MAYBE(depException, depResult.exception) { + output.as() = handle( + MaybeVoidCaller>>::apply( + errorHandler, kj::mv(*depException))); + } else KJ_IF_MAYBE(depValue, depResult.value) { + output.as() = handle(MaybeVoidCaller::apply(func, kj::mv(*depValue))); + } + } + + ExceptionOr handle(T&& value) { + return kj::mv(value); + } + ExceptionOr handle(PropagateException::Bottom&& value) { + return ExceptionOr(false, value.asException()); + } +}; + +// ------------------------------------------------------------------- + +class ForkHubBase; + +class ForkBranchBase: public PromiseNode { +public: + ForkBranchBase(Own&& hub); + ~ForkBranchBase() noexcept(false); + + void hubReady() noexcept; + // Called by the hub to indicate that it is ready. + + // implements PromiseNode ------------------------------------------ + void onReady(Event& event) noexcept override; + PromiseNode* getInnerForTrace() override; + +protected: + inline ExceptionOrValue& getHubResultRef(); + + void releaseHub(ExceptionOrValue& output); + // Release the hub. If an exception is thrown, add it to `output`. + +private: + OnReadyEvent onReadyEvent; + + Own hub; + ForkBranchBase* next = nullptr; + ForkBranchBase** prevPtr = nullptr; + + friend class ForkHubBase; +}; + +template T copyOrAddRef(T& t) { return t; } +template Own copyOrAddRef(Own& t) { return t->addRef(); } + +template +class ForkBranch final: public ForkBranchBase { + // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives + // a const reference. + +public: + ForkBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} + + void get(ExceptionOrValue& output) noexcept override { + ExceptionOr& hubResult = getHubResultRef().template as(); + KJ_IF_MAYBE(value, hubResult.value) { + output.as().value = copyOrAddRef(*value); + } else { + output.as().value = nullptr; + } + output.exception = hubResult.exception; + releaseHub(output); + } +}; + +template +class SplitBranch final: public ForkBranchBase { + // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives + // a const reference. + +public: + SplitBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} + + typedef kj::Decay(kj::instance()))> Element; + + void get(ExceptionOrValue& output) noexcept override { + ExceptionOr& hubResult = getHubResultRef().template as(); + KJ_IF_MAYBE(value, hubResult.value) { + output.as().value = kj::mv(kj::get(*value)); + } else { + output.as().value = nullptr; + } + output.exception = hubResult.exception; + releaseHub(output); + } +}; + +// ------------------------------------------------------------------- + +class ForkHubBase: public Refcounted, protected Event { +public: + ForkHubBase(Own&& inner, ExceptionOrValue& resultRef); + + inline ExceptionOrValue& getResultRef() { return resultRef; } + +private: + Own inner; + ExceptionOrValue& resultRef; + + ForkBranchBase* headBranch = nullptr; + ForkBranchBase** tailBranch = &headBranch; + // Tail becomes null once the inner promise is ready and all branches have been notified. + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + friend class ForkBranchBase; +}; + +template +class ForkHub final: public ForkHubBase { + // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces + // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if + // possible). + +public: + ForkHub(Own&& inner): ForkHubBase(kj::mv(inner), result) {} + + Promise<_::UnfixVoid> addBranch() { + return Promise<_::UnfixVoid>(false, kj::heap>(addRef(*this))); + } + + _::SplitTuplePromise split() { + return splitImpl(MakeIndexes()>()); + } + +private: + ExceptionOr result; + + template + _::SplitTuplePromise splitImpl(Indexes) { + return kj::tuple(addSplit()...); + } + + template + Promise::Element>> addSplit() { + return Promise::Element>>( + false, maybeChain(kj::heap>(addRef(*this)), + implicitCast::Element*>(nullptr))); + } +}; + +inline ExceptionOrValue& ForkBranchBase::getHubResultRef() { + return hub->getResultRef(); +} + +// ------------------------------------------------------------------- + +class ChainPromiseNode final: public PromiseNode, public Event { + // Promise node which reduces Promise> to Promise. + // + // `Event` is only a public base class because otherwise we can't cast Own to + // Own. Ugh, templates and private... + +public: + explicit ChainPromiseNode(Own inner); + ~ChainPromiseNode() noexcept(false); + + void onReady(Event& event) noexcept override; + void setSelfPointer(Own* selfPtr) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + enum State { + STEP1, + STEP2 + }; + + State state; + + Own inner; + // In STEP1, a PromiseNode for a Promise. + // In STEP2, a PromiseNode for a T. + + Event* onReadyEvent = nullptr; + Own* selfPtr = nullptr; + + Maybe> fire() override; +}; + +template +Own maybeChain(Own&& node, Promise*) { + return heap(kj::mv(node)); +} + +template +Own&& maybeChain(Own&& node, T*) { + return kj::mv(node); +} + +// ------------------------------------------------------------------- + +class ExclusiveJoinPromiseNode final: public PromiseNode { +public: + ExclusiveJoinPromiseNode(Own left, Own right); + ~ExclusiveJoinPromiseNode() noexcept(false); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + class Branch: public Event { + public: + Branch(ExclusiveJoinPromiseNode& joinNode, Own dependency); + ~Branch() noexcept(false); + + bool get(ExceptionOrValue& output); + // Returns true if this is the side that finished. + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + private: + ExclusiveJoinPromiseNode& joinNode; + Own dependency; + }; + + Branch left; + Branch right; + OnReadyEvent onReadyEvent; +}; + +// ------------------------------------------------------------------- + +class ArrayJoinPromiseNodeBase: public PromiseNode { +public: + ArrayJoinPromiseNodeBase(Array> promises, + ExceptionOrValue* resultParts, size_t partSize); + ~ArrayJoinPromiseNodeBase() noexcept(false); + + void onReady(Event& event) noexcept override final; + void get(ExceptionOrValue& output) noexcept override final; + PromiseNode* getInnerForTrace() override final; + +protected: + virtual void getNoError(ExceptionOrValue& output) noexcept = 0; + // Called to compile the result only in the case where there were no errors. + +private: + uint countLeft; + OnReadyEvent onReadyEvent; + + class Branch final: public Event { + public: + Branch(ArrayJoinPromiseNodeBase& joinNode, Own dependency, + ExceptionOrValue& output); + ~Branch() noexcept(false); + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + Maybe getPart(); + // Calls dependency->get(output). If there was an exception, return it. + + private: + ArrayJoinPromiseNodeBase& joinNode; + Own dependency; + ExceptionOrValue& output; + }; + + Array branches; +}; + +template +class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { +public: + ArrayJoinPromiseNode(Array> promises, + Array> resultParts) + : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr)), + resultParts(kj::mv(resultParts)) {} + +protected: + void getNoError(ExceptionOrValue& output) noexcept override { + auto builder = heapArrayBuilder(resultParts.size()); + for (auto& part: resultParts) { + KJ_IASSERT(part.value != nullptr, + "Bug in KJ promise framework: Promise result had neither value no exception."); + builder.add(kj::mv(*_::readMaybe(part.value))); + } + output.as>() = builder.finish(); + } + +private: + Array> resultParts; +}; + +template <> +class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { +public: + ArrayJoinPromiseNode(Array> promises, + Array> resultParts); + ~ArrayJoinPromiseNode(); + +protected: + void getNoError(ExceptionOrValue& output) noexcept override; + +private: + Array> resultParts; +}; + +// ------------------------------------------------------------------- + +class EagerPromiseNodeBase: public PromiseNode, protected Event { + // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly + // evaluate it. + +public: + EagerPromiseNodeBase(Own&& dependency, ExceptionOrValue& resultRef); + + void onReady(Event& event) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + OnReadyEvent onReadyEvent; + + ExceptionOrValue& resultRef; + + Maybe> fire() override; +}; + +template +class EagerPromiseNode final: public EagerPromiseNodeBase { +public: + EagerPromiseNode(Own&& dependency) + : EagerPromiseNodeBase(kj::mv(dependency), result) {} + + void get(ExceptionOrValue& output) noexcept override { + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; +}; + +template +Own spark(Own&& node) { + // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting + // on it. + return heap>(kj::mv(node)); +} + +// ------------------------------------------------------------------- + +class AdapterPromiseNodeBase: public PromiseNode { +public: + void onReady(Event& event) noexcept override; + +protected: + inline void setReady() { + onReadyEvent.arm(); + } + +private: + OnReadyEvent onReadyEvent; +}; + +template +class AdapterPromiseNode final: public AdapterPromiseNodeBase, + private PromiseFulfiller> { + // A PromiseNode that wraps a PromiseAdapter. + +public: + template + AdapterPromiseNode(Params&&... params) + : adapter(static_cast>&>(*this), kj::fwd(params)...) {} + + void get(ExceptionOrValue& output) noexcept override { + KJ_IREQUIRE(!isWaiting()); + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; + bool waiting = true; + Adapter adapter; + + void fulfill(T&& value) override { + if (waiting) { + waiting = false; + result = ExceptionOr(kj::mv(value)); + setReady(); + } + } + + void reject(Exception&& exception) override { + if (waiting) { + waiting = false; + result = ExceptionOr(false, kj::mv(exception)); + setReady(); + } + } + + bool isWaiting() override { + return waiting; + } +}; + +} // namespace _ (private) + +// ======================================================================================= + +template +Promise::Promise(_::FixVoid value) + : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid>>(kj::mv(value))) {} + +template +Promise::Promise(kj::Exception&& exception) + : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {} + +template +template +PromiseForResult Promise::then(Func&& func, ErrorFunc&& errorHandler) { + typedef _::FixVoid<_::ReturnType> ResultT; + + Own<_::PromiseNode> intermediate = + heap<_::TransformPromiseNode, Func, ErrorFunc>>( + kj::mv(node), kj::fwd(func), kj::fwd(errorHandler)); + return PromiseForResult(false, + _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); +} + +namespace _ { // private + +template +struct IdentityFunc { + inline T operator()(T&& value) const { + return kj::mv(value); + } +}; +template +struct IdentityFunc> { + inline Promise operator()(T&& value) const { + return kj::mv(value); + } +}; +template <> +struct IdentityFunc { + inline void operator()() const {} +}; +template <> +struct IdentityFunc> { + Promise operator()() const; + // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly, + // Cap'n Proto relies on being able to include this header without creating such a link-time + // dependency. +}; + +} // namespace _ (private) + +template +template +Promise Promise::catch_(ErrorFunc&& errorHandler) { + // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case, + // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise, + // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually + // return a promise. So we make our Func return match ErrorFunc. + return then(_::IdentityFunc()))>(), + kj::fwd(errorHandler)); +} + +template +T Promise::wait(WaitScope& waitScope) { + _::ExceptionOr<_::FixVoid> result; + + waitImpl(kj::mv(node), result, waitScope); + + KJ_IF_MAYBE(value, result.value) { + KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } + return _::returnMaybeVoid(kj::mv(*value)); + } else KJ_IF_MAYBE(exception, result.exception) { + throwFatalException(kj::mv(*exception)); + } else { + // Result contained neither a value nor an exception? + KJ_UNREACHABLE; + } +} + +template <> +inline void Promise::wait(WaitScope& waitScope) { + // Override case to use throwRecoverableException(). + + _::ExceptionOr<_::Void> result; + + waitImpl(kj::mv(node), result, waitScope); + + if (result.value != nullptr) { + KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } + } else KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } else { + // Result contained neither a value nor an exception? + KJ_UNREACHABLE; + } +} + +template +ForkedPromise Promise::fork() { + return ForkedPromise(false, refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))); +} + +template +Promise ForkedPromise::addBranch() { + return hub->addBranch(); +} + +template +_::SplitTuplePromise Promise::split() { + return refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))->split(); +} + +template +Promise Promise::exclusiveJoin(Promise&& other) { + return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node))); +} + +template +template +Promise Promise::attach(Attachments&&... attachments) { + return Promise(false, kj::heap<_::AttachmentPromiseNode>>( + kj::mv(node), kj::tuple(kj::fwd(attachments)...))); +} + +template +template +Promise Promise::eagerlyEvaluate(ErrorFunc&& errorHandler) { + // See catch_() for commentary. + return Promise(false, _::spark<_::FixVoid>(then( + _::IdentityFunc()))>(), + kj::fwd(errorHandler)).node)); +} + +template +Promise Promise::eagerlyEvaluate(decltype(nullptr)) { + return Promise(false, _::spark<_::FixVoid>(kj::mv(node))); +} + +template +kj::String Promise::trace() { + return PromiseBase::trace(); +} + +template +inline PromiseForResult evalLater(Func&& func) { + return _::yield().then(kj::fwd(func), _::PropagateException()); +} + +template +inline PromiseForResult evalNow(Func&& func) { + PromiseForResult result = nullptr; + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + result = func(); + })) { + result = kj::mv(*e); + } + return result; +} + +template +template +void Promise::detach(ErrorFunc&& errorHandler) { + return _::detach(then([](T&&) {}, kj::fwd(errorHandler))); +} + +template <> +template +void Promise::detach(ErrorFunc&& errorHandler) { + return _::detach(then([]() {}, kj::fwd(errorHandler))); +} + +template +Promise> joinPromises(Array>&& promises) { + return Promise>(false, kj::heap<_::ArrayJoinPromiseNode>( + KJ_MAP(p, promises) { return kj::mv(p.node); }, + heapArray<_::ExceptionOr>(promises.size()))); +} + +// ======================================================================================= + +namespace _ { // private + +template +class WeakFulfiller final: public PromiseFulfiller, private kj::Disposer { + // A wrapper around PromiseFulfiller which can be detached. + // + // There are a couple non-trivialities here: + // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly + // rejected. + // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been + // detached from the underlying fulfiller, because otherwise the later detach() call will go + // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the + // refcount never goes over 2 and we manually implement the refcounting because we need to do + // other special things when each side detaches anyway. To this end, WeakFulfiller is its own + // Disposer -- dispose() is called when the application discards its owned pointer to the + // fulfiller and detach() is called when the promise is destroyed. + +public: + KJ_DISALLOW_COPY(WeakFulfiller); + + static kj::Own make() { + WeakFulfiller* ptr = new WeakFulfiller; + return Own(ptr, *ptr); + } + + void fulfill(FixVoid&& value) override { + if (inner != nullptr) { + inner->fulfill(kj::mv(value)); + } + } + + void reject(Exception&& exception) override { + if (inner != nullptr) { + inner->reject(kj::mv(exception)); + } + } + + bool isWaiting() override { + return inner != nullptr && inner->isWaiting(); + } + + void attach(PromiseFulfiller& newInner) { + inner = &newInner; + } + + void detach(PromiseFulfiller& from) { + if (inner == nullptr) { + // Already disposed. + delete this; + } else { + KJ_IREQUIRE(inner == &from); + inner = nullptr; + } + } + +private: + mutable PromiseFulfiller* inner; + + WeakFulfiller(): inner(nullptr) {} + + void disposeImpl(void* pointer) const override { + // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type? + + if (inner == nullptr) { + // Already detached. + delete this; + } else { + if (inner->isWaiting()) { + inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, + kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise."))); + } + inner = nullptr; + } + } +}; + +template +class PromiseAndFulfillerAdapter { +public: + PromiseAndFulfillerAdapter(PromiseFulfiller& fulfiller, + WeakFulfiller& wrapper) + : fulfiller(fulfiller), wrapper(wrapper) { + wrapper.attach(fulfiller); + } + + ~PromiseAndFulfillerAdapter() noexcept(false) { + wrapper.detach(fulfiller); + } + +private: + PromiseFulfiller& fulfiller; + WeakFulfiller& wrapper; +}; + +} // namespace _ (private) + +template +template +bool PromiseFulfiller::rejectIfThrows(Func&& func) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { + reject(kj::mv(*exception)); + return false; + } else { + return true; + } +} + +template +bool PromiseFulfiller::rejectIfThrows(Func&& func) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { + reject(kj::mv(*exception)); + return false; + } else { + return true; + } +} + +template +Promise newAdaptedPromise(Params&&... adapterConstructorParams) { + return Promise(false, heap<_::AdapterPromiseNode<_::FixVoid, Adapter>>( + kj::fwd(adapterConstructorParams)...)); +} + +template +PromiseFulfillerPair newPromiseAndFulfiller() { + auto wrapper = _::WeakFulfiller::make(); + + Own<_::PromiseNode> intermediate( + heap<_::AdapterPromiseNode<_::FixVoid, _::PromiseAndFulfillerAdapter>>(*wrapper)); + Promise<_::JoinPromises> promise(false, + _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); + + return PromiseFulfillerPair { kj::mv(promise), kj::mv(wrapper) }; +} + +} // namespace kj + +#endif // KJ_ASYNC_INL_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async-io.h --- a/osx/include/kj/async-io.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/async-io.h Mon May 22 10:01:37 2017 +0100 @@ -1,502 +1,560 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ASYNC_IO_H_ -#define KJ_ASYNC_IO_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "async.h" -#include "function.h" -#include "thread.h" -#include "time.h" - -struct sockaddr; - -namespace kj { - -class UnixEventPort; -class NetworkAddress; - -// ======================================================================================= -// Streaming I/O - -class AsyncInputStream { - // Asynchronous equivalent of InputStream (from io.h). - -public: - virtual Promise read(void* buffer, size_t minBytes, size_t maxBytes) = 0; - virtual Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; - - Promise read(void* buffer, size_t bytes); -}; - -class AsyncOutputStream { - // Asynchronous equivalent of OutputStream (from io.h). - -public: - virtual Promise write(const void* buffer, size_t size) = 0; - virtual Promise write(ArrayPtr> pieces) = 0; -}; - -class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream { - // A combination input and output stream. - -public: - virtual void shutdownWrite() = 0; - // Cleanly shut down just the write end of the stream, while keeping the read end open. - - virtual void abortRead() {} - // Similar to shutdownWrite, but this will shut down the read end of the stream, and should only - // be called when an error has occurred. - - virtual void getsockopt(int level, int option, void* value, uint* length); - virtual void setsockopt(int level, int option, const void* value, uint length); - // Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception - // if the stream is not a socket or the option is not appropriate for the socket type. The - // default implementations always throw "unimplemented". - - virtual void getsockname(struct sockaddr* addr, uint* length); - virtual void getpeername(struct sockaddr* addr, uint* length); - // Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented" - // exception if the stream is not a socket. The default implementations always throw - // "unimplemented". - // - // Note that we don't provide methods that return NetworkAddress because it usually wouldn't - // be useful. You can't connect() to or listen() on these addresses, obviously, because they are - // ephemeral addresses for a single connection. -}; - -struct OneWayPipe { - // A data pipe with an input end and an output end. (Typically backed by pipe() system call.) - - Own in; - Own out; -}; - -struct TwoWayPipe { - // A data pipe that supports sending in both directions. Each end's output sends data to the - // other end's input. (Typically backed by socketpair() system call.) - - Own ends[2]; -}; - -class ConnectionReceiver { - // Represents a server socket listening on a port. - -public: - virtual Promise> accept() = 0; - // Accept the next incoming connection. - - virtual uint getPort() = 0; - // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't - // specify a port when constructing the NetworkAddress -- one will have been assigned - // automatically. - - virtual void getsockopt(int level, int option, void* value, uint* length); - virtual void setsockopt(int level, int option, const void* value, uint length); - // Same as the methods of AsyncIoStream. -}; - -// ======================================================================================= -// Datagram I/O - -class AncillaryMessage { - // Represents an ancillary message (aka control message) received using the recvmsg() system - // call (or equivalent). Most apps will not use this. - -public: - inline AncillaryMessage(int level, int type, ArrayPtr data); - AncillaryMessage() = default; - - inline int getLevel() const; - // Originating protocol / socket level. - - inline int getType() const; - // Protocol-specific message type. - - template - inline Maybe as(); - // Interpret the ancillary message as the given struct type. Most ancillary messages are some - // sort of struct, so this is a convenient way to access it. Returns nullptr if the message - // is smaller than the struct -- this can happen if the message was truncated due to - // insufficient ancillary buffer space. - - template - inline ArrayPtr asArray(); - // Interpret the ancillary message as an array of items. If the message size does not evenly - // divide into elements of type T, the remainder is discarded -- this can happen if the message - // was truncated due to insufficient ancillary buffer space. - -private: - int level; - int type; - ArrayPtr data; - // Message data. In most cases you should use `as()` or `asArray()`. -}; - -class DatagramReceiver { - // Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's - // capacity in advance; if a received packet is larger than the capacity, it will be truncated. - -public: - virtual Promise receive() = 0; - // Receive a new message, overwriting this object's content. - // - // receive() may reuse the same buffers for content and ancillary data with each call. - - template - struct MaybeTruncated { - T value; - - bool isTruncated; - // True if the Receiver's capacity was insufficient to receive the value and therefore the - // value is truncated. - }; - - virtual MaybeTruncated> getContent() = 0; - // Get the content of the datagram. - - virtual MaybeTruncated> getAncillary() = 0; - // Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr - // struct. Most apps don't need this. - // - // If the returned value is truncated, then the last message in the array may itself be - // truncated, meaning its as() method will return nullptr or its asArray() method will - // return fewer elements than expected. Truncation can also mean that additional messages were - // available but discarded. - - virtual NetworkAddress& getSource() = 0; - // Get the datagram sender's address. - - struct Capacity { - size_t content = 8192; - // How much space to allocate for the datagram content. If a datagram is received that is - // larger than this, it will be truncated, with no way to recover the tail. - - size_t ancillary = 0; - // How much space to allocate for ancillary messages. As with content, if the ancillary data - // is larger than this, it will be truncated. - }; -}; - -class DatagramPort { -public: - virtual Promise send(const void* buffer, size_t size, NetworkAddress& destination) = 0; - virtual Promise send(ArrayPtr> pieces, - NetworkAddress& destination) = 0; - - virtual Own makeReceiver( - DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0; - // Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much - // space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`. - - virtual uint getPort() = 0; - // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't - // specify a port when constructing the NetworkAddress -- one will have been assigned - // automatically. - - virtual void getsockopt(int level, int option, void* value, uint* length); - virtual void setsockopt(int level, int option, const void* value, uint length); - // Same as the methods of AsyncIoStream. -}; - -// ======================================================================================= -// Networks - -class NetworkAddress { - // Represents a remote address to which the application can connect. - -public: - virtual Promise> connect() = 0; - // Make a new connection to this address. - // - // The address must not be a wildcard ("*"). If it is an IP address, it must have a port number. - - virtual Own listen() = 0; - // Listen for incoming connections on this address. - // - // The address must be local. - - virtual Own bindDatagramPort(); - // Open this address as a datagram (e.g. UDP) port. - // - // The address must be local. - - virtual Own clone() = 0; - // Returns an equivalent copy of this NetworkAddress. - - virtual String toString() = 0; - // Produce a human-readable string which hopefully can be passed to Network::parseAddress() - // to reproduce this address, although whether or not that works of course depends on the Network - // implementation. This should be called only to display the address to human users, who will - // hopefully know what they are able to do with it. -}; - -class Network { - // Factory for NetworkAddress instances, representing the network services offered by the - // operating system. - // - // This interface typically represents broad authority, and well-designed code should limit its - // use to high-level startup code and user interaction. Low-level APIs should accept - // NetworkAddress instances directly and work from there, if at all possible. - -public: - virtual Promise> parseAddress(StringPtr addr, uint portHint = 0) = 0; - // Construct a network address from a user-provided string. The format of the address - // strings is not specified at the API level, and application code should make no assumptions - // about them. These strings should always be provided by humans, and said humans will know - // what format to use in their particular context. - // - // `portHint`, if provided, specifies the "standard" IP port number for the application-level - // service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a - // port number, this port will be used. If `addr` lacks a port number *and* `portHint` is - // omitted, then the returned address will only support listen() and bindDatagramPort() - // (not connect()), and an unused port will be chosen each time one of those methods is called. - - virtual Own getSockaddr(const void* sockaddr, uint len) = 0; - // Construct a network address from a legacy struct sockaddr. -}; - -// ======================================================================================= -// I/O Provider - -class AsyncIoProvider { - // Class which constructs asynchronous wrappers around the operating system's I/O facilities. - // - // Generally, the implementation of this interface must integrate closely with a particular - // `EventLoop` implementation. Typically, the EventLoop implementation itself will provide - // an AsyncIoProvider. - -public: - virtual OneWayPipe newOneWayPipe() = 0; - // Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with - // the pipe(2) system call). - - virtual TwoWayPipe newTwoWayPipe() = 0; - // Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with - // socketpair(2) system call). Data written to one end can be read from the other. - - virtual Network& getNetwork() = 0; - // Creates a new `Network` instance representing the networks exposed by the operating system. - // - // DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If - // you call this from low-level code, then you are preventing higher-level code from injecting an - // alternative implementation. Instead, if your code needs to use network functionality, it - // should ask for a `Network` as a constructor or method parameter, so that higher-level code can - // chose what implementation to use. The system network is essentially a singleton. See: - // http://www.object-oriented-security.org/lets-argue/singletons - // - // Code that uses the system network should not make any assumptions about what kinds of - // addresses it will parse, as this could differ across platforms. String addresses should come - // strictly from the user, who will know how to write them correctly for their system. - // - // With that said, KJ currently supports the following string address formats: - // - IPv4: "1.2.3.4", "1.2.3.4:80" - // - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80" - // - Local IP wildcard (covers both v4 and v6): "*", "*:80" - // - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http" - // - Unix domain: "unix:/path/to/socket" - - struct PipeThread { - // A combination of a thread and a two-way pipe that communicates with that thread. - // - // The fields are intentionally ordered so that the pipe will be destroyed (and therefore - // disconnected) before the thread is destroyed (and therefore joined). Thus if the thread - // arranges to exit when it detects disconnect, destruction should be clean. - - Own thread; - Own pipe; - }; - - virtual PipeThread newPipeThread( - Function startFunc) = 0; - // Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate - // with it. One end of the pipe is passed to the thread's start function and the other end of - // the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will - // already have an active `EventLoop` when `startFunc` is called. - // - // TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too - // much at once but I'm not sure how to cleanly break it down. - - virtual Timer& getTimer() = 0; - // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- - // it only updates when the event loop polls for system events. This means that calling `now()` - // on this timer does not require a system call. - // - // This timer is not affected by changes to the system date. It is unspecified whether the timer - // continues to count while the system is suspended. -}; - -class LowLevelAsyncIoProvider { - // Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on - // different operating systems. You should prefer to use `AsyncIoProvider` over this interface - // whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection. - // - // On Unix, this interface can be used to import native file descriptors into the async framework. - // Different implementations of this interface might work on top of different event handling - // primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library. - // - // On Windows, this interface can be used to import native HANDLEs into the async framework. - // Different implementations of this interface might work on top of different event handling - // primitives, such as I/O completion ports vs. completion routines. - // - // TODO(port): Actually implement Windows support. - -public: - // --------------------------------------------------------------------------- - // Unix-specific stuff - - enum Flags { - // Flags controlling how to wrap a file descriptor. - - TAKE_OWNERSHIP = 1 << 0, - // The returned object should own the file descriptor, automatically closing it when destroyed. - // The close-on-exec flag will be set on the descriptor if it is not already. - // - // If this flag is not used, then the file descriptor is not automatically closed and the - // close-on-exec flag is not modified. - - ALREADY_CLOEXEC = 1 << 1, - // Indicates that the close-on-exec flag is known already to be set, so need not be set again. - // Only relevant when combined with TAKE_OWNERSHIP. - // - // On Linux, all system calls which yield new file descriptors have flags or variants which - // set the close-on-exec flag immediately. Unfortunately, other OS's do not. - - ALREADY_NONBLOCK = 1 << 2 - // Indicates that the file descriptor is known already to be in non-blocking mode, so the flag - // need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode - // automatically. - // - // On Linux, all system calls which yield new file descriptors have flags or variants which - // enable non-blocking mode immediately. Unfortunately, other OS's do not. - }; - - virtual Own wrapInputFd(int fd, uint flags = 0) = 0; - // Create an AsyncInputStream wrapping a file descriptor. - // - // `flags` is a bitwise-OR of the values of the `Flags` enum. - - virtual Own wrapOutputFd(int fd, uint flags = 0) = 0; - // Create an AsyncOutputStream wrapping a file descriptor. - // - // `flags` is a bitwise-OR of the values of the `Flags` enum. - - virtual Own wrapSocketFd(int fd, uint flags = 0) = 0; - // Create an AsyncIoStream wrapping a socket file descriptor. - // - // `flags` is a bitwise-OR of the values of the `Flags` enum. - - virtual Promise> wrapConnectingSocketFd(int fd, uint flags = 0) = 0; - // Create an AsyncIoStream wrapping a socket that is in the process of connecting. The returned - // promise should not resolve until connection has completed -- traditionally indicated by the - // descriptor becoming writable. - // - // `flags` is a bitwise-OR of the values of the `Flags` enum. - - virtual Own wrapListenSocketFd(int fd, uint flags = 0) = 0; - // Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already - // have had `bind()` and `listen()` called on it, so it's ready for `accept()`. - // - // `flags` is a bitwise-OR of the values of the `Flags` enum. - - virtual Own wrapDatagramSocketFd(int fd, uint flags = 0); - - virtual Timer& getTimer() = 0; - // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- - // it only updates when the event loop polls for system events. This means that calling `now()` - // on this timer does not require a system call. - // - // This timer is not affected by changes to the system date. It is unspecified whether the timer - // continues to count while the system is suspended. -}; - -Own newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel); -// Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`. - -struct AsyncIoContext { - Own lowLevelProvider; - Own provider; - WaitScope& waitScope; - - UnixEventPort& unixEventPort; - // TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This - // field will go away at some point when we have a chance to improve these interfaces. -}; - -AsyncIoContext setupAsyncIo(); -// Convenience method which sets up the current thread with everything it needs to do async I/O. -// The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for -// doing I/O on the host system, so everything is ready for the thread to start making async calls -// and waiting on promises. -// -// You would typically call this in your main() loop or in the start function of a thread. -// Example: -// -// int main() { -// auto ioContext = kj::setupAsyncIo(); -// -// // Now we can call an async function. -// Promise textPromise = getHttp(*ioContext.provider, "http://example.com"); -// -// // And we can wait for the promise to complete. Note that you can only use `wait()` -// // from the top level, not from inside a promise callback. -// String text = textPromise.wait(ioContext.waitScope); -// print(text); -// return 0; -// } -// -// WARNING: An AsyncIoContext can only be used in the thread and process that created it. In -// particular, note that after a fork(), an AsyncIoContext created in the parent process will -// not work correctly in the child, even if the parent ceases to use its copy. In particular -// note that this means that server processes which daemonize themselves at startup must wait -// until after daemonization to create an AsyncIoContext. - -// ======================================================================================= -// inline implementation details - -inline AncillaryMessage::AncillaryMessage( - int level, int type, ArrayPtr data) - : level(level), type(type), data(data) {} - -inline int AncillaryMessage::getLevel() const { return level; } -inline int AncillaryMessage::getType() const { return type; } - -template -inline Maybe AncillaryMessage::as() { - if (data.size() >= sizeof(T)) { - return *reinterpret_cast(data.begin()); - } else { - return nullptr; - } -} - -template -inline ArrayPtr AncillaryMessage::asArray() { - return arrayPtr(reinterpret_cast(data.begin()), data.size() / sizeof(T)); -} - -} // namespace kj - -#endif // KJ_ASYNC_IO_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_IO_H_ +#define KJ_ASYNC_IO_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async.h" +#include "function.h" +#include "thread.h" +#include "time.h" + +struct sockaddr; + +namespace kj { + +#if _WIN32 +class Win32EventPort; +#else +class UnixEventPort; +#endif + +class NetworkAddress; +class AsyncOutputStream; + +// ======================================================================================= +// Streaming I/O + +class AsyncInputStream { + // Asynchronous equivalent of InputStream (from io.h). + +public: + virtual Promise read(void* buffer, size_t minBytes, size_t maxBytes); + virtual Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; + + Promise read(void* buffer, size_t bytes); + + virtual Maybe tryGetLength(); + // Get the remaining number of bytes that will be produced by this stream, if known. + // + // This is used e.g. to fill in the Content-Length header of an HTTP message. If unknown, the + // HTTP implementation may need to fall back to Transfer-Encoding: chunked. + // + // The default implementation always returns null. + + virtual Promise pumpTo( + AsyncOutputStream& output, uint64_t amount = kj::maxValue); + // Read `amount` bytes from this stream (or to EOF) and write them to `output`, returning the + // total bytes actually pumped (which is only less than `amount` if EOF was reached). + // + // Override this if your stream type knows how to pump itself to certain kinds of output + // streams more efficiently than via the naive approach. You can use + // kj::dynamicDowncastIfAvailable() to test for stream types you recognize, and if none match, + // delegate to the default implementation. + // + // The default implementation first tries calling output.tryPumpFrom(), but if that fails, it + // performs a naive pump by allocating a buffer and reading to it / writing from it in a loop. + + Promise> readAllBytes(); + Promise readAllText(); + // Read until EOF and return as one big byte array or string. +}; + +class AsyncOutputStream { + // Asynchronous equivalent of OutputStream (from io.h). + +public: + virtual Promise write(const void* buffer, size_t size) = 0; + virtual Promise write(ArrayPtr> pieces) = 0; + + virtual Maybe> tryPumpFrom( + AsyncInputStream& input, uint64_t amount = kj::maxValue); + // Implements double-dispatch for AsyncInputStream::pumpTo(). + // + // This method should only be called from within an implementation of pumpTo(). + // + // This method examines the type of `input` to find optimized ways to pump data from it to this + // output stream. If it finds one, it performs the pump. Otherwise, it returns null. + // + // The default implementation always returns null. +}; + +class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream { + // A combination input and output stream. + +public: + virtual void shutdownWrite() = 0; + // Cleanly shut down just the write end of the stream, while keeping the read end open. + + virtual void abortRead() {} + // Similar to shutdownWrite, but this will shut down the read end of the stream, and should only + // be called when an error has occurred. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception + // if the stream is not a socket or the option is not appropriate for the socket type. The + // default implementations always throw "unimplemented". + + virtual void getsockname(struct sockaddr* addr, uint* length); + virtual void getpeername(struct sockaddr* addr, uint* length); + // Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented" + // exception if the stream is not a socket. The default implementations always throw + // "unimplemented". + // + // Note that we don't provide methods that return NetworkAddress because it usually wouldn't + // be useful. You can't connect() to or listen() on these addresses, obviously, because they are + // ephemeral addresses for a single connection. +}; + +struct OneWayPipe { + // A data pipe with an input end and an output end. (Typically backed by pipe() system call.) + + Own in; + Own out; +}; + +struct TwoWayPipe { + // A data pipe that supports sending in both directions. Each end's output sends data to the + // other end's input. (Typically backed by socketpair() system call.) + + Own ends[2]; +}; + +class ConnectionReceiver { + // Represents a server socket listening on a port. + +public: + virtual Promise> accept() = 0; + // Accept the next incoming connection. + + virtual uint getPort() = 0; + // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't + // specify a port when constructing the NetworkAddress -- one will have been assigned + // automatically. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Same as the methods of AsyncIoStream. +}; + +// ======================================================================================= +// Datagram I/O + +class AncillaryMessage { + // Represents an ancillary message (aka control message) received using the recvmsg() system + // call (or equivalent). Most apps will not use this. + +public: + inline AncillaryMessage(int level, int type, ArrayPtr data); + AncillaryMessage() = default; + + inline int getLevel() const; + // Originating protocol / socket level. + + inline int getType() const; + // Protocol-specific message type. + + template + inline Maybe as(); + // Interpret the ancillary message as the given struct type. Most ancillary messages are some + // sort of struct, so this is a convenient way to access it. Returns nullptr if the message + // is smaller than the struct -- this can happen if the message was truncated due to + // insufficient ancillary buffer space. + + template + inline ArrayPtr asArray(); + // Interpret the ancillary message as an array of items. If the message size does not evenly + // divide into elements of type T, the remainder is discarded -- this can happen if the message + // was truncated due to insufficient ancillary buffer space. + +private: + int level; + int type; + ArrayPtr data; + // Message data. In most cases you should use `as()` or `asArray()`. +}; + +class DatagramReceiver { + // Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's + // capacity in advance; if a received packet is larger than the capacity, it will be truncated. + +public: + virtual Promise receive() = 0; + // Receive a new message, overwriting this object's content. + // + // receive() may reuse the same buffers for content and ancillary data with each call. + + template + struct MaybeTruncated { + T value; + + bool isTruncated; + // True if the Receiver's capacity was insufficient to receive the value and therefore the + // value is truncated. + }; + + virtual MaybeTruncated> getContent() = 0; + // Get the content of the datagram. + + virtual MaybeTruncated> getAncillary() = 0; + // Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr + // struct. Most apps don't need this. + // + // If the returned value is truncated, then the last message in the array may itself be + // truncated, meaning its as() method will return nullptr or its asArray() method will + // return fewer elements than expected. Truncation can also mean that additional messages were + // available but discarded. + + virtual NetworkAddress& getSource() = 0; + // Get the datagram sender's address. + + struct Capacity { + size_t content = 8192; + // How much space to allocate for the datagram content. If a datagram is received that is + // larger than this, it will be truncated, with no way to recover the tail. + + size_t ancillary = 0; + // How much space to allocate for ancillary messages. As with content, if the ancillary data + // is larger than this, it will be truncated. + }; +}; + +class DatagramPort { +public: + virtual Promise send(const void* buffer, size_t size, NetworkAddress& destination) = 0; + virtual Promise send(ArrayPtr> pieces, + NetworkAddress& destination) = 0; + + virtual Own makeReceiver( + DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0; + // Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much + // space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`. + + virtual uint getPort() = 0; + // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't + // specify a port when constructing the NetworkAddress -- one will have been assigned + // automatically. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Same as the methods of AsyncIoStream. +}; + +// ======================================================================================= +// Networks + +class NetworkAddress { + // Represents a remote address to which the application can connect. + +public: + virtual Promise> connect() = 0; + // Make a new connection to this address. + // + // The address must not be a wildcard ("*"). If it is an IP address, it must have a port number. + + virtual Own listen() = 0; + // Listen for incoming connections on this address. + // + // The address must be local. + + virtual Own bindDatagramPort(); + // Open this address as a datagram (e.g. UDP) port. + // + // The address must be local. + + virtual Own clone() = 0; + // Returns an equivalent copy of this NetworkAddress. + + virtual String toString() = 0; + // Produce a human-readable string which hopefully can be passed to Network::parseAddress() + // to reproduce this address, although whether or not that works of course depends on the Network + // implementation. This should be called only to display the address to human users, who will + // hopefully know what they are able to do with it. +}; + +class Network { + // Factory for NetworkAddress instances, representing the network services offered by the + // operating system. + // + // This interface typically represents broad authority, and well-designed code should limit its + // use to high-level startup code and user interaction. Low-level APIs should accept + // NetworkAddress instances directly and work from there, if at all possible. + +public: + virtual Promise> parseAddress(StringPtr addr, uint portHint = 0) = 0; + // Construct a network address from a user-provided string. The format of the address + // strings is not specified at the API level, and application code should make no assumptions + // about them. These strings should always be provided by humans, and said humans will know + // what format to use in their particular context. + // + // `portHint`, if provided, specifies the "standard" IP port number for the application-level + // service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a + // port number, this port will be used. If `addr` lacks a port number *and* `portHint` is + // omitted, then the returned address will only support listen() and bindDatagramPort() + // (not connect()), and an unused port will be chosen each time one of those methods is called. + + virtual Own getSockaddr(const void* sockaddr, uint len) = 0; + // Construct a network address from a legacy struct sockaddr. +}; + +// ======================================================================================= +// I/O Provider + +class AsyncIoProvider { + // Class which constructs asynchronous wrappers around the operating system's I/O facilities. + // + // Generally, the implementation of this interface must integrate closely with a particular + // `EventLoop` implementation. Typically, the EventLoop implementation itself will provide + // an AsyncIoProvider. + +public: + virtual OneWayPipe newOneWayPipe() = 0; + // Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with + // the pipe(2) system call). + + virtual TwoWayPipe newTwoWayPipe() = 0; + // Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with + // socketpair(2) system call). Data written to one end can be read from the other. + + virtual Network& getNetwork() = 0; + // Creates a new `Network` instance representing the networks exposed by the operating system. + // + // DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If + // you call this from low-level code, then you are preventing higher-level code from injecting an + // alternative implementation. Instead, if your code needs to use network functionality, it + // should ask for a `Network` as a constructor or method parameter, so that higher-level code can + // chose what implementation to use. The system network is essentially a singleton. See: + // http://www.object-oriented-security.org/lets-argue/singletons + // + // Code that uses the system network should not make any assumptions about what kinds of + // addresses it will parse, as this could differ across platforms. String addresses should come + // strictly from the user, who will know how to write them correctly for their system. + // + // With that said, KJ currently supports the following string address formats: + // - IPv4: "1.2.3.4", "1.2.3.4:80" + // - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80" + // - Local IP wildcard (covers both v4 and v6): "*", "*:80" + // - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http" + // - Unix domain: "unix:/path/to/socket" + + struct PipeThread { + // A combination of a thread and a two-way pipe that communicates with that thread. + // + // The fields are intentionally ordered so that the pipe will be destroyed (and therefore + // disconnected) before the thread is destroyed (and therefore joined). Thus if the thread + // arranges to exit when it detects disconnect, destruction should be clean. + + Own thread; + Own pipe; + }; + + virtual PipeThread newPipeThread( + Function startFunc) = 0; + // Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate + // with it. One end of the pipe is passed to the thread's start function and the other end of + // the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will + // already have an active `EventLoop` when `startFunc` is called. + // + // TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too + // much at once but I'm not sure how to cleanly break it down. + + virtual Timer& getTimer() = 0; + // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- + // it only updates when the event loop polls for system events. This means that calling `now()` + // on this timer does not require a system call. + // + // This timer is not affected by changes to the system date. It is unspecified whether the timer + // continues to count while the system is suspended. +}; + +class LowLevelAsyncIoProvider { + // Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on + // different operating systems. You should prefer to use `AsyncIoProvider` over this interface + // whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection. + // + // On Unix, this interface can be used to import native file descriptors into the async framework. + // Different implementations of this interface might work on top of different event handling + // primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library. + // + // On Windows, this interface can be used to import native HANDLEs into the async framework. + // Different implementations of this interface might work on top of different event handling + // primitives, such as I/O completion ports vs. completion routines. + // + // TODO(port): Actually implement Windows support. + +public: + // --------------------------------------------------------------------------- + // Unix-specific stuff + + enum Flags { + // Flags controlling how to wrap a file descriptor. + + TAKE_OWNERSHIP = 1 << 0, + // The returned object should own the file descriptor, automatically closing it when destroyed. + // The close-on-exec flag will be set on the descriptor if it is not already. + // + // If this flag is not used, then the file descriptor is not automatically closed and the + // close-on-exec flag is not modified. + +#if !_WIN32 + ALREADY_CLOEXEC = 1 << 1, + // Indicates that the close-on-exec flag is known already to be set, so need not be set again. + // Only relevant when combined with TAKE_OWNERSHIP. + // + // On Linux, all system calls which yield new file descriptors have flags or variants which + // set the close-on-exec flag immediately. Unfortunately, other OS's do not. + + ALREADY_NONBLOCK = 1 << 2 + // Indicates that the file descriptor is known already to be in non-blocking mode, so the flag + // need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode + // automatically. + // + // On Linux, all system calls which yield new file descriptors have flags or variants which + // enable non-blocking mode immediately. Unfortunately, other OS's do not. +#endif + }; + +#if _WIN32 + typedef uintptr_t Fd; + // On Windows, the `fd` parameter to each of these methods must be a SOCKET, and must have the + // flag WSA_FLAG_OVERLAPPED (which socket() uses by default, but WSASocket() wants you to specify + // explicitly). +#else + typedef int Fd; + // On Unix, any arbitrary file descriptor is supported. +#endif + + virtual Own wrapInputFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncInputStream wrapping a file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapOutputFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncOutputStream wrapping a file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapSocketFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a socket file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Promise> wrapConnectingSocketFd( + Fd fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a socket and initiate a connection to the given address. + // The returned promise does not resolve until connection has completed. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapListenSocketFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already + // have had `bind()` and `listen()` called on it, so it's ready for `accept()`. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapDatagramSocketFd(Fd fd, uint flags = 0); + + virtual Timer& getTimer() = 0; + // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- + // it only updates when the event loop polls for system events. This means that calling `now()` + // on this timer does not require a system call. + // + // This timer is not affected by changes to the system date. It is unspecified whether the timer + // continues to count while the system is suspended. +}; + +Own newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel); +// Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`. + +struct AsyncIoContext { + Own lowLevelProvider; + Own provider; + WaitScope& waitScope; + +#if _WIN32 + Win32EventPort& win32EventPort; +#else + UnixEventPort& unixEventPort; + // TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This + // field will go away at some point when we have a chance to improve these interfaces. +#endif +}; + +AsyncIoContext setupAsyncIo(); +// Convenience method which sets up the current thread with everything it needs to do async I/O. +// The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for +// doing I/O on the host system, so everything is ready for the thread to start making async calls +// and waiting on promises. +// +// You would typically call this in your main() loop or in the start function of a thread. +// Example: +// +// int main() { +// auto ioContext = kj::setupAsyncIo(); +// +// // Now we can call an async function. +// Promise textPromise = getHttp(*ioContext.provider, "http://example.com"); +// +// // And we can wait for the promise to complete. Note that you can only use `wait()` +// // from the top level, not from inside a promise callback. +// String text = textPromise.wait(ioContext.waitScope); +// print(text); +// return 0; +// } +// +// WARNING: An AsyncIoContext can only be used in the thread and process that created it. In +// particular, note that after a fork(), an AsyncIoContext created in the parent process will +// not work correctly in the child, even if the parent ceases to use its copy. In particular +// note that this means that server processes which daemonize themselves at startup must wait +// until after daemonization to create an AsyncIoContext. + +// ======================================================================================= +// inline implementation details + +inline AncillaryMessage::AncillaryMessage( + int level, int type, ArrayPtr data) + : level(level), type(type), data(data) {} + +inline int AncillaryMessage::getLevel() const { return level; } +inline int AncillaryMessage::getType() const { return type; } + +template +inline Maybe AncillaryMessage::as() { + if (data.size() >= sizeof(T)) { + return *reinterpret_cast(data.begin()); + } else { + return nullptr; + } +} + +template +inline ArrayPtr AncillaryMessage::asArray() { + return arrayPtr(reinterpret_cast(data.begin()), data.size() / sizeof(T)); +} + +} // namespace kj + +#endif // KJ_ASYNC_IO_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async-prelude.h --- a/osx/include/kj/async-prelude.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/async-prelude.h Mon May 22 10:01:37 2017 +0100 @@ -1,218 +1,218 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file contains a bunch of internal declarations that must appear before async.h can start. -// We don't define these directly in async.h because it makes the file hard to read. - -#ifndef KJ_ASYNC_PRELUDE_H_ -#define KJ_ASYNC_PRELUDE_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "exception.h" -#include "tuple.h" - -namespace kj { - -class EventLoop; -template -class Promise; -class WaitScope; - -template -Promise> joinPromises(Array>&& promises); -Promise joinPromises(Array>&& promises); - -namespace _ { // private - -template struct JoinPromises_ { typedef T Type; }; -template struct JoinPromises_> { typedef T Type; }; - -template -using JoinPromises = typename JoinPromises_::Type; -// If T is Promise, resolves to U, otherwise resolves to T. -// -// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely -// unrelated. - -class PropagateException { - // A functor which accepts a kj::Exception as a parameter and returns a broken promise of - // arbitrary type which simply propagates the exception. -public: - class Bottom { - public: - Bottom(Exception&& exception): exception(kj::mv(exception)) {} - - Exception asException() { return kj::mv(exception); } - - private: - Exception exception; - }; - - Bottom operator()(Exception&& e) { - return Bottom(kj::mv(e)); - } - Bottom operator()(const Exception& e) { - return Bottom(kj::cp(e)); - } -}; - -template -struct ReturnType_ { typedef decltype(instance()(instance())) Type; }; -template -struct ReturnType_ { typedef decltype(instance()()) Type; }; - -template -using ReturnType = typename ReturnType_::Type; -// The return type of functor Func given a parameter of type T, with the special exception that if -// T is void, this is the return type of Func called with no arguments. - -template struct SplitTuplePromise_ { typedef Promise Type; }; -template -struct SplitTuplePromise_> { - typedef kj::Tuple>...> Type; -}; - -template -using SplitTuplePromise = typename SplitTuplePromise_::Type; -// T -> Promise -// Tuple -> Tuple> - -struct Void {}; -// Application code should NOT refer to this! See `kj::READY_NOW` instead. - -template struct FixVoid_ { typedef T Type; }; -template <> struct FixVoid_ { typedef Void Type; }; -template using FixVoid = typename FixVoid_::Type; -// FixVoid is just T unless T is void in which case it is _::Void (an empty struct). - -template struct UnfixVoid_ { typedef T Type; }; -template <> struct UnfixVoid_ { typedef void Type; }; -template using UnfixVoid = typename UnfixVoid_::Type; -// UnfixVoid is the opposite of FixVoid. - -template -struct MaybeVoidCaller { - // Calls the function converting a Void input to an empty parameter list and a void return - // value to a Void output. - - template - static inline Out apply(Func& func, In&& in) { - return func(kj::mv(in)); - } -}; -template -struct MaybeVoidCaller { - template - static inline Out apply(Func& func, In& in) { - return func(in); - } -}; -template -struct MaybeVoidCaller { - template - static inline Out apply(Func& func, Void&& in) { - return func(); - } -}; -template -struct MaybeVoidCaller { - template - static inline Void apply(Func& func, In&& in) { - func(kj::mv(in)); - return Void(); - } -}; -template -struct MaybeVoidCaller { - template - static inline Void apply(Func& func, In& in) { - func(in); - return Void(); - } -}; -template <> -struct MaybeVoidCaller { - template - static inline Void apply(Func& func, Void&& in) { - func(); - return Void(); - } -}; - -template -inline T&& returnMaybeVoid(T&& t) { - return kj::fwd(t); -} -inline void returnMaybeVoid(Void&& v) {} - -class ExceptionOrValue; -class PromiseNode; -class ChainPromiseNode; -template -class ForkHub; - -class TaskSetImpl; - -class Event; - -class PromiseBase { -public: - kj::String trace(); - // Dump debug info about this promise. - -private: - Own node; - - PromiseBase() = default; - PromiseBase(Own&& node): node(kj::mv(node)) {} - - friend class kj::EventLoop; - friend class ChainPromiseNode; - template - friend class kj::Promise; - friend class TaskSetImpl; - template - friend Promise> kj::joinPromises(Array>&& promises); - friend Promise kj::joinPromises(Array>&& promises); -}; - -void detach(kj::Promise&& promise); -void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope); -Promise yield(); -Own neverDone(); - -class NeverDone { -public: - template - operator Promise() const { - return Promise(false, neverDone()); - } - - KJ_NORETURN(void wait(WaitScope& waitScope) const); -}; - -} // namespace _ (private) -} // namespace kj - -#endif // KJ_ASYNC_PRELUDE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains a bunch of internal declarations that must appear before async.h can start. +// We don't define these directly in async.h because it makes the file hard to read. + +#ifndef KJ_ASYNC_PRELUDE_H_ +#define KJ_ASYNC_PRELUDE_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "exception.h" +#include "tuple.h" + +namespace kj { + +class EventLoop; +template +class Promise; +class WaitScope; + +template +Promise> joinPromises(Array>&& promises); +Promise joinPromises(Array>&& promises); + +namespace _ { // private + +template struct JoinPromises_ { typedef T Type; }; +template struct JoinPromises_> { typedef T Type; }; + +template +using JoinPromises = typename JoinPromises_::Type; +// If T is Promise, resolves to U, otherwise resolves to T. +// +// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely +// unrelated. + +class PropagateException { + // A functor which accepts a kj::Exception as a parameter and returns a broken promise of + // arbitrary type which simply propagates the exception. +public: + class Bottom { + public: + Bottom(Exception&& exception): exception(kj::mv(exception)) {} + + Exception asException() { return kj::mv(exception); } + + private: + Exception exception; + }; + + Bottom operator()(Exception&& e) { + return Bottom(kj::mv(e)); + } + Bottom operator()(const Exception& e) { + return Bottom(kj::cp(e)); + } +}; + +template +struct ReturnType_ { typedef decltype(instance()(instance())) Type; }; +template +struct ReturnType_ { typedef decltype(instance()()) Type; }; + +template +using ReturnType = typename ReturnType_::Type; +// The return type of functor Func given a parameter of type T, with the special exception that if +// T is void, this is the return type of Func called with no arguments. + +template struct SplitTuplePromise_ { typedef Promise Type; }; +template +struct SplitTuplePromise_> { + typedef kj::Tuple>...> Type; +}; + +template +using SplitTuplePromise = typename SplitTuplePromise_::Type; +// T -> Promise +// Tuple -> Tuple> + +struct Void {}; +// Application code should NOT refer to this! See `kj::READY_NOW` instead. + +template struct FixVoid_ { typedef T Type; }; +template <> struct FixVoid_ { typedef Void Type; }; +template using FixVoid = typename FixVoid_::Type; +// FixVoid is just T unless T is void in which case it is _::Void (an empty struct). + +template struct UnfixVoid_ { typedef T Type; }; +template <> struct UnfixVoid_ { typedef void Type; }; +template using UnfixVoid = typename UnfixVoid_::Type; +// UnfixVoid is the opposite of FixVoid. + +template +struct MaybeVoidCaller { + // Calls the function converting a Void input to an empty parameter list and a void return + // value to a Void output. + + template + static inline Out apply(Func& func, In&& in) { + return func(kj::mv(in)); + } +}; +template +struct MaybeVoidCaller { + template + static inline Out apply(Func& func, In& in) { + return func(in); + } +}; +template +struct MaybeVoidCaller { + template + static inline Out apply(Func& func, Void&& in) { + return func(); + } +}; +template +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, In&& in) { + func(kj::mv(in)); + return Void(); + } +}; +template +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, In& in) { + func(in); + return Void(); + } +}; +template <> +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, Void&& in) { + func(); + return Void(); + } +}; + +template +inline T&& returnMaybeVoid(T&& t) { + return kj::fwd(t); +} +inline void returnMaybeVoid(Void&& v) {} + +class ExceptionOrValue; +class PromiseNode; +class ChainPromiseNode; +template +class ForkHub; + +class TaskSetImpl; + +class Event; + +class PromiseBase { +public: + kj::String trace(); + // Dump debug info about this promise. + +private: + Own node; + + PromiseBase() = default; + PromiseBase(Own&& node): node(kj::mv(node)) {} + + friend class kj::EventLoop; + friend class ChainPromiseNode; + template + friend class kj::Promise; + friend class TaskSetImpl; + template + friend Promise> kj::joinPromises(Array>&& promises); + friend Promise kj::joinPromises(Array>&& promises); +}; + +void detach(kj::Promise&& promise); +void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope); +Promise yield(); +Own neverDone(); + +class NeverDone { +public: + template + operator Promise() const { + return Promise(false, neverDone()); + } + + KJ_NORETURN(void wait(WaitScope& waitScope) const); +}; + +} // namespace _ (private) +} // namespace kj + +#endif // KJ_ASYNC_PRELUDE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async-unix.h --- a/osx/include/kj/async-unix.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/async-unix.h Mon May 22 10:01:37 2017 +0100 @@ -1,273 +1,274 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ASYNC_UNIX_H_ -#define KJ_ASYNC_UNIX_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "async.h" -#include "time.h" -#include "vector.h" -#include "io.h" -#include - -#if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL) -// Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h. -#define KJ_USE_EPOLL 1 -#endif - -namespace kj { - -class UnixEventPort: public EventPort { - // An EventPort implementation which can wait for events on file descriptors as well as signals. - // This API only makes sense on Unix. - // - // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue). - // To also wait on signals without race conditions, the implementation may block signals until - // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before - // the signal was unblocked, or it may use a nicer platform-specific API like signalfd. - // - // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you - // need to use SIGUSR1 for something else, you must offer a different signal by calling - // setReservedSignal() at startup. - // - // WARNING: A UnixEventPort can only be used in the thread and process that created it. In - // particular, note that after a fork(), a UnixEventPort created in the parent process will - // not work correctly in the child, even if the parent ceases to use its copy. In particular - // note that this means that server processes which daemonize themselves at startup must wait - // until after daemonization to create a UnixEventPort. - -public: - UnixEventPort(); - ~UnixEventPort() noexcept(false); - - class FdObserver; - // Class that watches an fd for readability or writability. See definition below. - - Promise onSignal(int signum); - // When the given signal is delivered to this thread, return the corresponding siginfo_t. - // The signal must have been captured using `captureSignal()`. - // - // If `onSignal()` has not been called, the signal will remain blocked in this thread. - // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the - // next call to 'onSignal()' will receive it. Also, you can control which thread receives a - // process-wide signal by only calling `onSignal()` on that thread's event loop. - // - // The result of waiting on the same signal twice at once is undefined. - - static void captureSignal(int signum); - // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may - // then pass it to `onSignal()`. This method is static because it registers a signal handler - // which applies process-wide. If any other threads exist in the process when `captureSignal()` - // is called, you *must* set the signal mask in those threads to block this signal, otherwise - // terrible things will happen if the signal happens to be delivered to those threads. If at - // all possible, call `captureSignal()` *before* creating threads, so that threads you create in - // the future will inherit the proper signal mask. - // - // To un-capture a signal, simply install a different signal handler and then un-block it from - // the signal mask. - - static void setReservedSignal(int signum); - // Sets the signal number which `UnixEventPort` reserves for internal use. If your application - // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before - // constructing an `UnixEventPort`) to offer a different signal. - - TimePoint steadyTime() { return frozenSteadyTime; } - Promise atSteadyTime(TimePoint time); - - // implements EventPort ------------------------------------------------------ - bool wait() override; - bool poll() override; - void wake() const override; - -private: - struct TimerSet; // Defined in source file to avoid STL include. - class TimerPromiseAdapter; - class SignalPromiseAdapter; - - Own timers; - TimePoint frozenSteadyTime; - - SignalPromiseAdapter* signalHead = nullptr; - SignalPromiseAdapter** signalTail = &signalHead; - - TimePoint currentSteadyTime(); - void processTimers(); - void gotSignal(const siginfo_t& siginfo); - - friend class TimerPromiseAdapter; - -#if KJ_USE_EPOLL - AutoCloseFd epollFd; - AutoCloseFd signalFd; - AutoCloseFd eventFd; // Used for cross-thread wakeups. - - sigset_t signalFdSigset; - // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it - // needs updating. - - bool doEpollWait(int timeout); - -#else - class PollContext; - - FdObserver* observersHead = nullptr; - FdObserver** observersTail = &observersHead; - - unsigned long long threadId; // actually pthread_t -#endif -}; - -class UnixEventPort::FdObserver { - // Object which watches a file descriptor to determine when it is readable or writable. - // - // For listen sockets, "readable" means that there is a connection to accept(). For everything - // else, it means that read() (or recv()) will return data. - // - // The presence of out-of-band data should NOT fire this event. However, the event may - // occasionally fire spuriously (when there is actually no data to read), and one thing that can - // cause such spurious events is the arrival of OOB data on certain platforms whose event - // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX). - // - // WARNING: The exact behavior of this class differs across systems, since event interfaces - // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified - // behavior. If at all possible, use the higher-level AsyncInputStream interface instead. - -public: - enum Flags { - OBSERVE_READ = 1, - OBSERVE_WRITE = 2, - OBSERVE_URGENT = 4, - OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE - }; - - FdObserver(UnixEventPort& eventPort, int fd, uint flags); - // Begin watching the given file descriptor for readability. Only one ReadObserver may exist - // for a given file descriptor at a time. - - ~FdObserver() noexcept(false); - - KJ_DISALLOW_COPY(FdObserver); - - Promise whenBecomesReadable(); - // Resolves the next time the file descriptor transitions from having no data to read to having - // some data to read. - // - // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error - // to call this method when there is already data in the read buffer which has been there since - // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is - // unspecified whether the promise will ever resolve -- it depends on the underlying event - // mechanism being used. - // - // In order to avoid this problem, make sure that you only call `whenBecomesReadable()` - // only at times when you know the buffer is empty. You know this for sure when one of the - // following happens: - // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode - // enabled on the fd!) - // * The file descriptor is a regular byte-oriented object (like a socket or pipe), - // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()` - // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note, - // though, that for record-oriented file descriptors like Linux's inotify interface, this - // rule does not hold, because it could simply be that the next record did not fit into the - // space available.) - // - // It is an error to call `whenBecomesReadable()` again when the promise returned previously - // has not yet resolved. If you do this, the previous promise may throw an exception. - - inline Maybe atEndHint() { return atEnd; } - // Returns true if the event system has indicated that EOF has been received. There may still - // be data in the read buffer, but once that is gone, there's nothing left. - // - // Returns false if the event system has indicated that EOF had NOT been received as of the - // last turn of the event loop. - // - // Returns nullptr if the event system does not know whether EOF has been reached. In this - // case, the only way to know for sure is to call read() or recv() and check if it returns - // zero. - // - // This hint may be useful as an optimization to avoid an unnecessary system call. - - Promise whenBecomesWritable(); - // Resolves the next time the file descriptor transitions from having no space available in the - // write buffer to having some space available. - // - // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error - // to call this method when there is already space in the write buffer which has been there - // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case, - // it is unspecified whether the promise will ever resolve -- it depends on the underlying - // event mechanism being used. - // - // In order to avoid this problem, make sure that you only call `whenBecomesWritable()` - // only at times when you know the buffer is full. You know this for sure when one of the - // following happens: - // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode - // enabled on the fd!) - // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can - // only happen if the buffer is full. - // - // It is an error to call `whenBecomesWritable()` again when the promise returned previously - // has not yet resolved. If you do this, the previous promise may throw an exception. - - Promise whenUrgentDataAvailable(); - // Resolves the next time the file descriptor's read buffer contains "urgent" data. - // - // The conditions for availability of urgent data are specific to the file descriptor's - // underlying implementation. - // - // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously - // has not yet resolved. If you do this, the previous promise may throw an exception. - // - // WARNING: This has some known weird behavior on macOS. See - // https://github.com/sandstorm-io/capnproto/issues/374. - -private: - UnixEventPort& eventPort; - int fd; - uint flags; - - kj::Maybe>> readFulfiller; - kj::Maybe>> writeFulfiller; - kj::Maybe>> urgentFulfiller; - // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to - // null every time an event is fired. - - Maybe atEnd; - - void fire(short events); - -#if !KJ_USE_EPOLL - FdObserver* next; - FdObserver** prev; - // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller. - // If `prev` is null then the observer is not currently in the list. - - short getEventMask(); -#endif - - friend class UnixEventPort; -}; - -} // namespace kj - -#endif // KJ_ASYNC_UNIX_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_UNIX_H_ +#define KJ_ASYNC_UNIX_H_ + +#if _WIN32 +#error "This file is Unix-specific. On Windows, include async-win32.h instead." +#endif + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async.h" +#include "time.h" +#include "vector.h" +#include "io.h" +#include + +#if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL) +// Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h. +#define KJ_USE_EPOLL 1 +#endif + +namespace kj { + +class UnixEventPort: public EventPort { + // An EventPort implementation which can wait for events on file descriptors as well as signals. + // This API only makes sense on Unix. + // + // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue). + // To also wait on signals without race conditions, the implementation may block signals until + // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before + // the signal was unblocked, or it may use a nicer platform-specific API like signalfd. + // + // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you + // need to use SIGUSR1 for something else, you must offer a different signal by calling + // setReservedSignal() at startup. + // + // WARNING: A UnixEventPort can only be used in the thread and process that created it. In + // particular, note that after a fork(), a UnixEventPort created in the parent process will + // not work correctly in the child, even if the parent ceases to use its copy. In particular + // note that this means that server processes which daemonize themselves at startup must wait + // until after daemonization to create a UnixEventPort. + +public: + UnixEventPort(); + ~UnixEventPort() noexcept(false); + + class FdObserver; + // Class that watches an fd for readability or writability. See definition below. + + Promise onSignal(int signum); + // When the given signal is delivered to this thread, return the corresponding siginfo_t. + // The signal must have been captured using `captureSignal()`. + // + // If `onSignal()` has not been called, the signal will remain blocked in this thread. + // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the + // next call to 'onSignal()' will receive it. Also, you can control which thread receives a + // process-wide signal by only calling `onSignal()` on that thread's event loop. + // + // The result of waiting on the same signal twice at once is undefined. + + static void captureSignal(int signum); + // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may + // then pass it to `onSignal()`. This method is static because it registers a signal handler + // which applies process-wide. If any other threads exist in the process when `captureSignal()` + // is called, you *must* set the signal mask in those threads to block this signal, otherwise + // terrible things will happen if the signal happens to be delivered to those threads. If at + // all possible, call `captureSignal()` *before* creating threads, so that threads you create in + // the future will inherit the proper signal mask. + // + // To un-capture a signal, simply install a different signal handler and then un-block it from + // the signal mask. + + static void setReservedSignal(int signum); + // Sets the signal number which `UnixEventPort` reserves for internal use. If your application + // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before + // constructing an `UnixEventPort`) to offer a different signal. + + Timer& getTimer() { return timerImpl; } + + // implements EventPort ------------------------------------------------------ + bool wait() override; + bool poll() override; + void wake() const override; + +private: + struct TimerSet; // Defined in source file to avoid STL include. + class TimerPromiseAdapter; + class SignalPromiseAdapter; + + TimerImpl timerImpl; + + SignalPromiseAdapter* signalHead = nullptr; + SignalPromiseAdapter** signalTail = &signalHead; + + TimePoint readClock(); + void gotSignal(const siginfo_t& siginfo); + + friend class TimerPromiseAdapter; + +#if KJ_USE_EPOLL + AutoCloseFd epollFd; + AutoCloseFd signalFd; + AutoCloseFd eventFd; // Used for cross-thread wakeups. + + sigset_t signalFdSigset; + // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it + // needs updating. + + bool doEpollWait(int timeout); + +#else + class PollContext; + + FdObserver* observersHead = nullptr; + FdObserver** observersTail = &observersHead; + + unsigned long long threadId; // actually pthread_t +#endif +}; + +class UnixEventPort::FdObserver { + // Object which watches a file descriptor to determine when it is readable or writable. + // + // For listen sockets, "readable" means that there is a connection to accept(). For everything + // else, it means that read() (or recv()) will return data. + // + // The presence of out-of-band data should NOT fire this event. However, the event may + // occasionally fire spuriously (when there is actually no data to read), and one thing that can + // cause such spurious events is the arrival of OOB data on certain platforms whose event + // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX). + // + // WARNING: The exact behavior of this class differs across systems, since event interfaces + // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified + // behavior. If at all possible, use the higher-level AsyncInputStream interface instead. + +public: + enum Flags { + OBSERVE_READ = 1, + OBSERVE_WRITE = 2, + OBSERVE_URGENT = 4, + OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE + }; + + FdObserver(UnixEventPort& eventPort, int fd, uint flags); + // Begin watching the given file descriptor for readability. Only one ReadObserver may exist + // for a given file descriptor at a time. + + ~FdObserver() noexcept(false); + + KJ_DISALLOW_COPY(FdObserver); + + Promise whenBecomesReadable(); + // Resolves the next time the file descriptor transitions from having no data to read to having + // some data to read. + // + // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error + // to call this method when there is already data in the read buffer which has been there since + // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is + // unspecified whether the promise will ever resolve -- it depends on the underlying event + // mechanism being used. + // + // In order to avoid this problem, make sure that you only call `whenBecomesReadable()` + // only at times when you know the buffer is empty. You know this for sure when one of the + // following happens: + // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode + // enabled on the fd!) + // * The file descriptor is a regular byte-oriented object (like a socket or pipe), + // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()` + // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note, + // though, that for record-oriented file descriptors like Linux's inotify interface, this + // rule does not hold, because it could simply be that the next record did not fit into the + // space available.) + // + // It is an error to call `whenBecomesReadable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + + inline Maybe atEndHint() { return atEnd; } + // Returns true if the event system has indicated that EOF has been received. There may still + // be data in the read buffer, but once that is gone, there's nothing left. + // + // Returns false if the event system has indicated that EOF had NOT been received as of the + // last turn of the event loop. + // + // Returns nullptr if the event system does not know whether EOF has been reached. In this + // case, the only way to know for sure is to call read() or recv() and check if it returns + // zero. + // + // This hint may be useful as an optimization to avoid an unnecessary system call. + + Promise whenBecomesWritable(); + // Resolves the next time the file descriptor transitions from having no space available in the + // write buffer to having some space available. + // + // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error + // to call this method when there is already space in the write buffer which has been there + // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case, + // it is unspecified whether the promise will ever resolve -- it depends on the underlying + // event mechanism being used. + // + // In order to avoid this problem, make sure that you only call `whenBecomesWritable()` + // only at times when you know the buffer is full. You know this for sure when one of the + // following happens: + // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode + // enabled on the fd!) + // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can + // only happen if the buffer is full. + // + // It is an error to call `whenBecomesWritable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + + Promise whenUrgentDataAvailable(); + // Resolves the next time the file descriptor's read buffer contains "urgent" data. + // + // The conditions for availability of urgent data are specific to the file descriptor's + // underlying implementation. + // + // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + // + // WARNING: This has some known weird behavior on macOS. See + // https://github.com/sandstorm-io/capnproto/issues/374. + +private: + UnixEventPort& eventPort; + int fd; + uint flags; + + kj::Maybe>> readFulfiller; + kj::Maybe>> writeFulfiller; + kj::Maybe>> urgentFulfiller; + // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to + // null every time an event is fired. + + Maybe atEnd; + + void fire(short events); + +#if !KJ_USE_EPOLL + FdObserver* next; + FdObserver** prev; + // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller. + // If `prev` is null then the observer is not currently in the list. + + short getEventMask(); +#endif + + friend class UnixEventPort; +}; + +} // namespace kj + +#endif // KJ_ASYNC_UNIX_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async-win32.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/async-win32.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,234 @@ +// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_WIN32_H_ +#define KJ_ASYNC_WIN32_H_ + +#if !_WIN32 +#error "This file is Windows-specific. On Unix, include async-unix.h instead." +#endif + +#include "async.h" +#include "time.h" +#include "io.h" +#include +#include + +// Include windows.h as lean as possible. (If you need more of the Windows API for your app, +// #include windows.h yourself before including this header.) +#define WIN32_LEAN_AND_MEAN 1 +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#include +#include "windows-sanity.h" + +namespace kj { + +class Win32EventPort: public EventPort { + // Abstract base interface for EventPorts that can listen on Win32 event types. Due to the + // absurd complexity of the Win32 API, it's not possible to standardize on a single + // implementation of EventPort. In particular, there is no way for a single thread to use I/O + // completion ports (the most efficient way of handling I/O) while at the same time waiting for + // signalable handles or UI messages. + // + // Note that UI messages are not supported at all by this interface because the message queue + // is implemented by user32.dll and we want libkj to depend only on kernel32.dll. A separate + // compat library could provide a Win32EventPort implementation that works with the UI message + // queue. + +public: + // --------------------------------------------------------------------------- + // overlapped I/O + + struct IoResult { + DWORD errorCode; + DWORD bytesTransferred; + }; + + class IoOperation { + public: + virtual LPOVERLAPPED getOverlapped() = 0; + // Gets the OVERLAPPED structure to pass to the Win32 I/O call. Do NOT modify it; just pass it + // on. + + virtual Promise onComplete() = 0; + // After making the Win32 call, if the return value indicates that the operation was + // successfully queued (i.e. the completion event will definitely occur), call this to wait + // for completion. + // + // You MUST call this if the operation was successfully queued, and you MUST NOT call this + // otherwise. If the Win32 call failed (without queuing any operation or event) then you should + // simply drop the IoOperation object. + // + // Dropping the returned Promise cancels the operation via Win32's CancelIoEx(). The destructor + // will wait for the cancellation to complete, such that after dropping the proimse it is safe + // to free the buffer that the operation was reading from / writing to. + // + // You may safely drop the `IoOperation` while still waiting for this promise. You may not, + // however, drop the `IoObserver`. + }; + + class IoObserver { + public: + virtual Own newOperation(uint64_t offset) = 0; + // Begin an I/O operation. For file operations, `offset` is the offset within the file at + // which the operation will start. For stream operations, `offset` is ignored. + }; + + virtual Own observeIo(HANDLE handle) = 0; + // Given a handle which supports overlapped I/O, arrange to receive I/O completion events via + // this EventPort. + // + // Different Win32EventPort implementations may handle this in different ways, such as by using + // completion routines (APCs) or by using I/O completion ports. The caller should not assume + // any particular technique. + // + // WARNING: It is only safe to call observeIo() on a particular handle once during its lifetime. + // You cannot observe the same handle from multiple Win32EventPorts, even if not at the same + // time. This is because the Win32 API provides no way to disassociate a handle from an I/O + // completion port once it is associated. + + // --------------------------------------------------------------------------- + // signalable handles + // + // Warning: Due to limitations in the Win32 API, implementations of EventPort may be forced to + // spawn additional threads to wait for signaled objects. This is necessary if the EventPort + // implementation is based on I/O completion ports, or if you need to wait on more than 64 + // handles at once. + + class SignalObserver { + public: + virtual Promise onSignaled() = 0; + // Returns a promise that completes the next time the handle enters the signaled state. + // + // Depending on the type of handle, the handle may automatically be reset to a non-signaled + // state before the promise resolves. The underlying implementaiton uses WaitForSingleObject() + // or an equivalent wait call, so check the documentation for that to understand the semantics. + // + // If the handle is a mutex and it is abandoned without being unlocked, the promise breaks with + // an exception. + + virtual Promise onSignaledOrAbandoned() = 0; + // Like onSingaled(), but instead of throwing when a mutex is abandoned, resolves to `true`. + // Resolves to `false` for non-abandoned signals. + }; + + virtual Own observeSignalState(HANDLE handle) = 0; + // Given a handle that supports waiting for it to become "signaled" via WaitForSingleObject(), + // return an object that can wait for this state using the EventPort. + + // --------------------------------------------------------------------------- + // APCs + + virtual void allowApc() = 0; + // If this is ever called, the Win32EventPort will switch modes so that APCs can be scheduled + // on the thread, e.g. through the Win32 QueueUserAPC() call. In the future, this may be enabled + // by default. However, as of this writing, Wine does not support the necessary + // GetQueuedCompletionStatusEx() call, thus allowApc() breaks Wine support. (Tested on Wine + // 1.8.7.) + // + // If the event port implementation can't support APCs for some reason, this throws. + + // --------------------------------------------------------------------------- + // time + + virtual Timer& getTimer() = 0; +}; + +class Win32WaitObjectThreadPool { + // Helper class that implements Win32EventPort::observeSignalState() by spawning additional + // threads as needed to perform the actual waiting. + // + // This class is intended to be used to assist in building Win32EventPort implementations. + +public: + Win32WaitObjectThreadPool(uint mainThreadCount = 0); + // `mainThreadCount` indicates the number of objects the main thread is able to listen on + // directly. Typically this would be zero (e.g. if the main thread watches an I/O completion + // port) or MAXIMUM_WAIT_OBJECTS (e.g. if the main thread is a UI thread but can use + // MsgWaitForMultipleObjectsEx() to wait on some handles at the same time as messages). + + Own observeSignalState(HANDLE handle); + // Implemetns Win32EventPort::observeSignalState(). + + uint prepareMainThreadWait(HANDLE* handles[]); + // Call immediately before invoking WaitForMultipleObjects() or similar in the main thread. + // Fills in `handles` with the handle pointers to wait on, and returns the number of handles + // in this array. (The array should be allocated to be at least the size passed to the + // constructor). + // + // There's no need to call this if `mainThreadCount` as passed to the constructor was zero. + + bool finishedMainThreadWait(DWORD returnCode); + // Call immediately after invoking WaitForMultipleObjects() or similar in the main thread, + // passing the value returend by that call. Returns true if the event indicated by `returnCode` + // has been handled (i.e. it was WAIT_OBJECT_n or WAIT_ABANDONED_n where n is in-range for the + // last call to prepareMainThreadWait()). +}; + +class Win32IocpEventPort final: public Win32EventPort { + // An EventPort implementation which uses Windows I/O completion ports to listen for events. + // + // With this implementation, observeSignalState() requires spawning a separate thread. + +public: + Win32IocpEventPort(); + ~Win32IocpEventPort() noexcept(false); + + // implements EventPort ------------------------------------------------------ + bool wait() override; + bool poll() override; + void wake() const override; + + // implements Win32IocpEventPort --------------------------------------------- + Own observeIo(HANDLE handle) override; + Own observeSignalState(HANDLE handle) override; + Timer& getTimer() override { return timerImpl; } + void allowApc() override { isAllowApc = true; } + +private: + class IoPromiseAdapter; + class IoOperationImpl; + class IoObserverImpl; + + AutoCloseHandle iocp; + AutoCloseHandle thread; + Win32WaitObjectThreadPool waitThreads; + TimerImpl timerImpl; + mutable std::atomic sentWake {false}; + bool isAllowApc = false; + + static TimePoint readClock(); + + void waitIocp(DWORD timeoutMs); + // Wait on the I/O completion port for up to timeoutMs and pump events. Does not advance the + // timer; caller must do that. + + bool receivedWake(); + + static AutoCloseHandle newIocpHandle(); + static AutoCloseHandle openCurrentThread(); +}; + +} // namespace kj + +#endif // KJ_ASYNC_WIN32_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/async.h --- a/osx/include/kj/async.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/async.h Mon May 22 10:01:37 2017 +0100 @@ -1,682 +1,682 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ASYNC_H_ -#define KJ_ASYNC_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "async-prelude.h" -#include "exception.h" -#include "refcount.h" - -namespace kj { - -class EventLoop; -class WaitScope; - -template -class Promise; -template -class ForkedPromise; -template -class PromiseFulfiller; -template -struct PromiseFulfillerPair; - -template -using PromiseForResult = Promise<_::JoinPromises<_::ReturnType>>; -// Evaluates to the type of Promise for the result of calling functor type Func with parameter type -// T. If T is void, then the promise is for the result of calling Func with no arguments. If -// Func itself returns a promise, the promises are joined, so you never get Promise>. - -// ======================================================================================= -// Promises - -template -class Promise: protected _::PromiseBase { - // The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed - // specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A. - // - // A Promise represents a promise to produce a value of type T some time in the future. Once - // that value has been produced, the promise is "fulfilled". Alternatively, a promise can be - // "broken", with an Exception describing what went wrong. You may implicitly convert a value of - // type T to an already-fulfilled Promise. You may implicitly convert the constant - // `kj::READY_NOW` to an already-fulfilled Promise. You may also implicitly convert a - // `kj::Exception` to an already-broken promise of any type. - // - // Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed - // or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations - // meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless - // otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they - // should be rvalue-qualified, but at the time this interface was created compilers didn't widely - // support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If - // you want to use one Promise in two different places, you must fork it with `fork()`. - // - // To use the result of a Promise, you must call `then()` and supply a callback function to - // call with the result. `then()` returns another promise, for the result of the callback. - // Any time that this would result in Promise>, the promises are collapsed into a - // simple Promise that first waits for the outer promise, then the inner. Example: - // - // // Open a remote file, read the content, and then count the - // // number of lines of text. - // // Note that none of the calls here block. `file`, `content` - // // and `lineCount` are all initialized immediately before any - // // asynchronous operations occur. The lambda callbacks are - // // called later. - // Promise> file = openFtp("ftp://host/foo/bar"); - // Promise content = file.then( - // [](Own file) -> Promise { - // return file.readAll(); - // }); - // Promise lineCount = content.then( - // [](String text) -> int { - // uint count = 0; - // for (char c: text) count += (c == '\n'); - // return count; - // }); - // - // For `then()` to work, the current thread must have an active `EventLoop`. Each callback - // is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current - // thread's event loop, you do not need to worry about two callbacks running at the same time. - // You will need to set up at least one `EventLoop` at the top level of your program before you - // can use promises. - // - // To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`. - // - // Systems using promises should consider supporting the concept of "pipelining". Pipelining - // means allowing a caller to start issuing method calls against a promised object before the - // promise has actually been fulfilled. This is particularly useful if the promise is for a - // remote object living across a network, as this can avoid round trips when chaining a series - // of calls. It is suggested that any class T which supports pipelining implement a subclass of - // Promise which adds "eventual send" methods -- methods which, when called, say "please - // invoke the corresponding method on the promised value once it is available". These methods - // should in turn return promises for the eventual results of said invocations. Cap'n Proto, - // for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see - // `capnp/capability.h`. - // - // KJ Promises are based on E promises: - // http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises - // - // KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript - // promises, which are themselves influenced by E promises: - // http://promisesaplus.com/ - // https://github.com/domenic/promises-unwrapping - -public: - Promise(_::FixVoid value); - // Construct an already-fulfilled Promise from a value of type T. For non-void promises, the - // parameter type is simply T. So, e.g., in a function that returns `Promise`, you can - // say `return 123;` to return a promise that is already fulfilled to 123. - // - // For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`. - - Promise(kj::Exception&& e); - // Construct an already-broken Promise. - - inline Promise(decltype(nullptr)) {} - - template - PromiseForResult then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException()) - KJ_WARN_UNUSED_RESULT; - // Register a continuation function to be executed when the promise completes. The continuation - // (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation - // may return a new value; `then()` itself returns a promise for the continuation's eventual - // result. If the continuation itself returns a `Promise`, then `then()` shall also return - // a `Promise` which first waits for the original promise, then executes the continuation, - // then waits for the inner promise (i.e. it automatically "unwraps" the promise). - // - // In all cases, `then()` returns immediately. The continuation is executed later. The - // continuation is always executed on the same EventLoop (and, therefore, the same thread) which - // called `then()`, therefore no synchronization is necessary on state shared by the continuation - // and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws - // an exception. - // - // You may also specify an error handler continuation as the second parameter. `errorHandler` - // must be a functor taking a parameter of type `kj::Exception&&`. It must return the same - // type as `func` returns (except when `func` returns `Promise`, in which case `errorHandler` - // may return either `Promise` or just `U`). The default error handler simply propagates the - // exception to the returned promise. - // - // Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise - // is broken. When compiled with -fno-exceptions, the framework will still detect when a - // recoverable exception was thrown inside of a continuation and will consider the promise - // broken even though a (presumably garbage) result was returned. - // - // If the returned promise is destroyed before the callback runs, the callback will be canceled - // (it will never run). - // - // Note that `then()` -- like all other Promise methods -- consumes the promise on which it is - // called, in the sense of move semantics. After returning, the original promise is no longer - // valid, but `then()` returns a new promise. - // - // *Advanced implementation tips:* Most users will never need to worry about the below, but - // it is good to be aware of. - // - // As an optimization, if the callback function `func` does _not_ return another promise, then - // execution of `func` itself may be delayed until its result is known to be needed. The - // expectation here is that `func` is just doing some transformation on the results, not - // scheduling any other actions, therefore the system doesn't need to be proactive about - // evaluating it. This way, a chain of trivial then() transformations can be executed all at - // once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()` - // method to suppress this behavior. - // - // On the other hand, if `func` _does_ return another promise, then the system evaluates `func` - // as soon as possible, because the promise it returns might be for a newly-scheduled - // long-running asynchronous task. - // - // As another optimization, when a callback function registered with `then()` is actually - // scheduled, it is scheduled to occur immediately, preempting other work in the event queue. - // This allows a long chain of `then`s to execute all at once, improving cache locality by - // clustering operations on the same data. However, this implies that starvation can occur - // if a chain of `then()`s takes a very long time to execute without ever stopping to wait for - // actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events - // in the queue will get a chance to run before your callback is executed. - - Promise ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); } - // Convenience method to convert the promise to a void promise by ignoring the return value. - // - // You must still wait on the returned promise if you want the task to execute. - - template - Promise catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; - // Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that - // just returns its input. - - T wait(WaitScope& waitScope); - // Run the event loop until the promise is fulfilled, then return its result. If the promise - // is rejected, throw an exception. - // - // wait() is primarily useful at the top level of a program -- typically, within the function - // that allocated the EventLoop. For example, a program that performs one or two RPCs and then - // exits would likely use wait() in its main() function to wait on each RPC. On the other hand, - // server-side code generally cannot use wait(), because it has to be able to accept multiple - // requests at once. - // - // If the promise is rejected, `wait()` throws an exception. If the program was compiled without - // exceptions (-fno-exceptions), this will usually abort. In this case you really should first - // use `then()` to set an appropriate handler for the exception case, so that the promise you - // actually wait on never throws. - // - // `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By - // convention, any function which might call wait(), or which might call another function which - // might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two - // reasons: - // * `wait()` is not allowed during an event callback, because event callbacks are themselves - // called during some other `wait()`, and such recursive `wait()`s would only be able to - // complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer - // than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during - // an event callback. - // * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()` - // returns. This means that anyone calling `wait()` must be reentrant -- state may change - // around them in arbitrary ways. Therefore, callers really need to know if a function they - // are calling might wait(), and the `WaitScope&` parameter makes this clear. - // - // TODO(someday): Implement fibers, and let them call wait() even when they are handling an - // event. - - ForkedPromise fork() KJ_WARN_UNUSED_RESULT; - // Forks the promise, so that multiple different clients can independently wait on the result. - // `T` must be copy-constructable for this to work. Or, in the special case where `T` is - // `Own`, `U` must have a method `Own addRef()` which returns a new reference to the same - // (or an equivalent) object (probably implemented via reference counting). - - _::SplitTuplePromise split(); - // Split a promise for a tuple into a tuple of promises. - // - // E.g. if you have `Promise>`, `split()` returns - // `kj::Tuple, Promise>`. - - Promise exclusiveJoin(Promise&& other) KJ_WARN_UNUSED_RESULT; - // Return a new promise that resolves when either the original promise resolves or `other` - // resolves (whichever comes first). The promise that didn't resolve first is canceled. - - // TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions - // and produces a tuple? - - template - Promise attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; - // "Attaches" one or more movable objects (often, Owns) to the promise, such that they will - // be destroyed when the promise resolves. This is useful when a promise's callback contains - // pointers into some object and you want to make sure the object still exists when the callback - // runs -- after calling then(), use attach() to add necessary objects to the result. - - template - Promise eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; - Promise eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT; - // Force eager evaluation of this promise. Use this if you are going to hold on to the promise - // for awhile without consuming the result, but you want to make sure that the system actually - // processes it. - // - // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to - // `then()`, except that it must return void. We make you specify this because otherwise it's - // easy to forget to handle errors in a promise that you never use. You may specify nullptr for - // the error handler if you are sure that ignoring errors is fine, or if you know that you'll - // eventually wait on the promise somewhere. - - template - void detach(ErrorFunc&& errorHandler); - // Allows the promise to continue running in the background until it completes or the - // `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this - // promise, you need to make sure that the promise owns all the objects it touches or make sure - // those objects outlive the EventLoop. - // - // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to - // `then()`, except that it must return void. - // - // This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be - // canceled unless the callee explicitly permits it. - - kj::String trace(); - // Returns a dump of debug info about this promise. Not for production use. Requires RTTI. - // This method does NOT consume the promise as other methods do. - -private: - Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {} - // Second parameter prevent ambiguity with immediate-value constructor. - - template - friend class Promise; - friend class EventLoop; - template - friend Promise newAdaptedPromise(Params&&... adapterConstructorParams); - template - friend PromiseFulfillerPair newPromiseAndFulfiller(); - template - friend class _::ForkHub; - friend class _::TaskSetImpl; - friend Promise _::yield(); - friend class _::NeverDone; - template - friend Promise> joinPromises(Array>&& promises); - friend Promise joinPromises(Array>&& promises); -}; - -template -class ForkedPromise { - // The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created. - // Like `Promise`, this is a pass-by-move type. - -public: - inline ForkedPromise(decltype(nullptr)) {} - - Promise addBranch(); - // Add a new branch to the fork. The branch is equivalent to the original promise. - -private: - Own<_::ForkHub<_::FixVoid>> hub; - - inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid>>&& hub): hub(kj::mv(hub)) {} - - friend class Promise; - friend class EventLoop; -}; - -constexpr _::Void READY_NOW = _::Void(); -// Use this when you need a Promise that is already fulfilled -- this value can be implicitly -// cast to `Promise`. - -constexpr _::NeverDone NEVER_DONE = _::NeverDone(); -// The opposite of `READY_NOW`, return this when the promise should never resolve. This can be -// implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait -// forever (useful for servers). - -template -PromiseForResult evalLater(Func&& func) KJ_WARN_UNUSED_RESULT; -// Schedule for the given zero-parameter function to be executed in the event loop at some -// point in the near future. Returns a Promise for its result -- or, if `func()` itself returns -// a promise, `evalLater()` returns a Promise for the result of resolving that promise. -// -// Example usage: -// Promise x = evalLater([]() { return 123; }); -// -// The above is exactly equivalent to: -// Promise x = Promise(READY_NOW).then([]() { return 123; }); -// -// If the returned promise is destroyed before the callback runs, the callback will be canceled -// (never called). -// -// If you schedule several evaluations with `evalLater` during the same callback, they are -// guaranteed to be executed in order. - -template -PromiseForResult evalNow(Func&& func) KJ_WARN_UNUSED_RESULT; -// Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns. -// If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the -// main reason why `evalNow()` is useful. - -template -Promise> joinPromises(Array>&& promises); -// Join an array of promises into a promise for an array. - -// ======================================================================================= -// Hack for creating a lambda that holds an owned pointer. - -template -class CaptureByMove { -public: - inline CaptureByMove(Func&& func, MovedParam&& param) - : func(kj::mv(func)), param(kj::mv(param)) {} - - template - inline auto operator()(Params&&... params) - -> decltype(kj::instance()(kj::instance(), kj::fwd(params)...)) { - return func(kj::mv(param), kj::fwd(params)...); - } - -private: - Func func; - MovedParam param; -}; - -template -inline CaptureByMove> mvCapture(MovedParam&& param, Func&& func) { - // Hack to create a "lambda" which captures a variable by moving it rather than copying or - // referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this - // is commonly needed for Promise continuations that own their state. Example usage: - // - // Own ptr = makeFoo(); - // Promise promise = callRpc(); - // promise.then(mvCapture(ptr, [](Own&& ptr, int result) { - // return ptr->finish(result); - // })); - - return CaptureByMove>(kj::fwd(func), kj::mv(param)); -} - -// ======================================================================================= -// Advanced promise construction - -template -class PromiseFulfiller { - // A callback which can be used to fulfill a promise. Only the first call to fulfill() or - // reject() matters; subsequent calls are ignored. - -public: - virtual void fulfill(T&& value) = 0; - // Fulfill the promise with the given value. - - virtual void reject(Exception&& exception) = 0; - // Reject the promise with an error. - - virtual bool isWaiting() = 0; - // Returns true if the promise is still unfulfilled and someone is potentially waiting for it. - // Returns false if fulfill()/reject() has already been called *or* if the promise to be - // fulfilled has been discarded and therefore the result will never be used anyway. - - template - bool rejectIfThrows(Func&& func); - // Call the function (with no arguments) and return true. If an exception is thrown, call - // `fulfiller.reject()` and then return false. When compiled with exceptions disabled, - // non-fatal exceptions are still detected and handled correctly. -}; - -template <> -class PromiseFulfiller { - // Specialization of PromiseFulfiller for void promises. See PromiseFulfiller. - -public: - virtual void fulfill(_::Void&& value = _::Void()) = 0; - // Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't - // have to specialize for . - - virtual void reject(Exception&& exception) = 0; - virtual bool isWaiting() = 0; - - template - bool rejectIfThrows(Func&& func); -}; - -template -Promise newAdaptedPromise(Params&&... adapterConstructorParams); -// Creates a new promise which owns an instance of `Adapter` which encapsulates the operation -// that will eventually fulfill the promise. This is primarily useful for adapting non-KJ -// asynchronous APIs to use promises. -// -// An instance of `Adapter` will be allocated and owned by the returned `Promise`. A -// `PromiseFulfiller&` will be passed as the first parameter to the adapter's constructor, -// and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter -// is expected to perform some asynchronous operation and call the `PromiseFulfiller` once -// it is finished. -// -// The adapter is destroyed when its owning Promise is destroyed. This may occur before the -// Promise has been fulfilled. In this case, the adapter's destructor should cancel the -// asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be -// called. -// -// An adapter implementation should be carefully written to ensure that it cannot accidentally -// be left unfulfilled permanently because of an exception. Consider making liberal use of -// `PromiseFulfiller::rejectIfThrows()`. - -template -struct PromiseFulfillerPair { - Promise<_::JoinPromises> promise; - Own> fulfiller; -}; - -template -PromiseFulfillerPair newPromiseAndFulfiller(); -// Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise. -// If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is -// implicitly rejected. -// -// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback -// that there is no way to handle cancellation (i.e. detect when the Promise is discarded). -// -// You can arrange to fulfill a promise with another promise by using a promise type for T. E.g. -// `newPromiseAndFulfiller>()` will produce a promise of type `Promise` but the -// fulfiller will be of type `PromiseFulfiller>`. Thus you pass a `Promise` to the -// `fulfill()` callback, and the promises are chained. - -// ======================================================================================= -// TaskSet - -class TaskSet { - // Holds a collection of Promises and ensures that each executes to completion. Memory - // associated with each promise is automatically freed when the promise completes. Destroying - // the TaskSet itself automatically cancels all unfinished promises. - // - // This is useful for "daemon" objects that perform background tasks which aren't intended to - // fulfill any particular external promise, but which may need to be canceled (and thus can't - // use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is - // working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well, - // and everything the daemon is doing is canceled. - -public: - class ErrorHandler { - public: - virtual void taskFailed(kj::Exception&& exception) = 0; - }; - - TaskSet(ErrorHandler& errorHandler); - // `loop` will be used to wait on promises. `errorHandler` will be executed any time a task - // throws an exception, and will execute within the given EventLoop. - - ~TaskSet() noexcept(false); - - void add(Promise&& promise); - - kj::String trace(); - // Return debug info about all promises currently in the TaskSet. - -private: - Own<_::TaskSetImpl> impl; -}; - -// ======================================================================================= -// The EventLoop class - -class EventPort { - // Interfaces between an `EventLoop` and events originating from outside of the loop's thread. - // All such events come in through the `EventPort` implementation. - // - // An `EventPort` implementation may interface with low-level operating system APIs and/or other - // threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop - // framework, allowing the two to coexist in a single thread. - -public: - virtual bool wait() = 0; - // Wait for an external event to arrive, sleeping if necessary. Once at least one event has - // arrived, queue it to the event loop (e.g. by fulfilling a promise) and return. - // - // This is called during `Promise::wait()` whenever the event queue becomes empty, in order to - // wait for new events to populate the queue. - // - // It is safe to return even if nothing has actually been queued, so long as calling `wait()` in - // a loop will eventually sleep. (That is to say, false positives are fine.) - // - // Returns true if wake() has been called from another thread. (Precisely, returns true if - // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last - // called.) - - virtual bool poll() = 0; - // Check if any external events have arrived, but do not sleep. If any events have arrived, - // add them to the event queue (e.g. by fulfilling promises) before returning. - // - // This may be called during `Promise::wait()` when the EventLoop has been executing for a while - // without a break but is still non-empty. - // - // Returns true if wake() has been called from another thread. (Precisely, returns true if - // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last - // called.) - - virtual void setRunnable(bool runnable); - // Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it - // transitions from empty -> runnable or runnable -> empty. This is typically useful when - // integrating with an external event loop; if the loop is currently runnable then you should - // arrange to call run() on it soon. The default implementation does nothing. - - virtual void wake() const; - // Wake up the EventPort's thread from another thread. - // - // Unlike all other methods on this interface, `wake()` may be called from another thread, hence - // it is `const`. - // - // Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep - // again until `wait()` or `poll()` has returned true at least once. - // - // The default implementation throws an UNIMPLEMENTED exception. -}; - -class EventLoop { - // Represents a queue of events being executed in a loop. Most code won't interact with - // EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the - // documentation for `Promise`. - // - // Each thread can have at most one current EventLoop. To make an `EventLoop` current for - // the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop, - // or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly - // be passed a reference to the `WaitScope` to make the caller aware that they might block. - // - // Generally, you will want to construct an `EventLoop` at the top level of your program, e.g. - // in the main() function, or in the start function of a thread. You can then use it to - // construct some promises and wait on the result. Example: - // - // int main() { - // // `loop` becomes the official EventLoop for the thread. - // MyEventPort eventPort; - // EventLoop loop(eventPort); - // - // // Now we can call an async function. - // Promise textPromise = getHttp("http://example.com"); - // - // // And we can wait for the promise to complete. Note that you can only use `wait()` - // // from the top level, not from inside a promise callback. - // String text = textPromise.wait(); - // print(text); - // return 0; - // } - // - // Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather - // than allocate an `EventLoop` directly. - -public: - EventLoop(); - // Construct an `EventLoop` which does not receive external events at all. - - explicit EventLoop(EventPort& port); - // Construct an `EventLoop` which receives external events through the given `EventPort`. - - ~EventLoop() noexcept(false); - - void run(uint maxTurnCount = maxValue); - // Run the event loop for `maxTurnCount` turns or until there is nothing left to be done, - // whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will - // call the `EventPort`'s `setRunnable(false)` if the queue becomes empty. - - bool isRunnable(); - // Returns true if run() would currently do anything, or false if the queue is empty. - -private: - EventPort& port; - - bool running = false; - // True while looping -- wait() is then not allowed. - - bool lastRunnableState = false; - // What did we last pass to port.setRunnable()? - - _::Event* head = nullptr; - _::Event** tail = &head; - _::Event** depthFirstInsertPoint = &head; - - Own<_::TaskSetImpl> daemons; - - bool turn(); - void setRunnable(bool runnable); - void enterScope(); - void leaveScope(); - - friend void _::detach(kj::Promise&& promise); - friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, - WaitScope& waitScope); - friend class _::Event; - friend class WaitScope; -}; - -class WaitScope { - // Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually - // be allocated on the stack and serves two purposes: - // * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the - // thread. Most operations dealing with `Promise` (including all of its methods) do not work - // unless the thread has a current `EventLoop`. - // * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular - // promise to complete. See `Promise::wait()` for an extended discussion. - -public: - inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); } - inline ~WaitScope() { loop.leaveScope(); } - KJ_DISALLOW_COPY(WaitScope); - -private: - EventLoop& loop; - friend class EventLoop; - friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, - WaitScope& waitScope); -}; - -} // namespace kj - -#include "async-inl.h" - -#endif // KJ_ASYNC_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_H_ +#define KJ_ASYNC_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async-prelude.h" +#include "exception.h" +#include "refcount.h" + +namespace kj { + +class EventLoop; +class WaitScope; + +template +class Promise; +template +class ForkedPromise; +template +class PromiseFulfiller; +template +struct PromiseFulfillerPair; + +template +using PromiseForResult = Promise<_::JoinPromises<_::ReturnType>>; +// Evaluates to the type of Promise for the result of calling functor type Func with parameter type +// T. If T is void, then the promise is for the result of calling Func with no arguments. If +// Func itself returns a promise, the promises are joined, so you never get Promise>. + +// ======================================================================================= +// Promises + +template +class Promise: protected _::PromiseBase { + // The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed + // specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A. + // + // A Promise represents a promise to produce a value of type T some time in the future. Once + // that value has been produced, the promise is "fulfilled". Alternatively, a promise can be + // "broken", with an Exception describing what went wrong. You may implicitly convert a value of + // type T to an already-fulfilled Promise. You may implicitly convert the constant + // `kj::READY_NOW` to an already-fulfilled Promise. You may also implicitly convert a + // `kj::Exception` to an already-broken promise of any type. + // + // Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed + // or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations + // meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless + // otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they + // should be rvalue-qualified, but at the time this interface was created compilers didn't widely + // support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If + // you want to use one Promise in two different places, you must fork it with `fork()`. + // + // To use the result of a Promise, you must call `then()` and supply a callback function to + // call with the result. `then()` returns another promise, for the result of the callback. + // Any time that this would result in Promise>, the promises are collapsed into a + // simple Promise that first waits for the outer promise, then the inner. Example: + // + // // Open a remote file, read the content, and then count the + // // number of lines of text. + // // Note that none of the calls here block. `file`, `content` + // // and `lineCount` are all initialized immediately before any + // // asynchronous operations occur. The lambda callbacks are + // // called later. + // Promise> file = openFtp("ftp://host/foo/bar"); + // Promise content = file.then( + // [](Own file) -> Promise { + // return file.readAll(); + // }); + // Promise lineCount = content.then( + // [](String text) -> int { + // uint count = 0; + // for (char c: text) count += (c == '\n'); + // return count; + // }); + // + // For `then()` to work, the current thread must have an active `EventLoop`. Each callback + // is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current + // thread's event loop, you do not need to worry about two callbacks running at the same time. + // You will need to set up at least one `EventLoop` at the top level of your program before you + // can use promises. + // + // To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`. + // + // Systems using promises should consider supporting the concept of "pipelining". Pipelining + // means allowing a caller to start issuing method calls against a promised object before the + // promise has actually been fulfilled. This is particularly useful if the promise is for a + // remote object living across a network, as this can avoid round trips when chaining a series + // of calls. It is suggested that any class T which supports pipelining implement a subclass of + // Promise which adds "eventual send" methods -- methods which, when called, say "please + // invoke the corresponding method on the promised value once it is available". These methods + // should in turn return promises for the eventual results of said invocations. Cap'n Proto, + // for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see + // `capnp/capability.h`. + // + // KJ Promises are based on E promises: + // http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises + // + // KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript + // promises, which are themselves influenced by E promises: + // http://promisesaplus.com/ + // https://github.com/domenic/promises-unwrapping + +public: + Promise(_::FixVoid value); + // Construct an already-fulfilled Promise from a value of type T. For non-void promises, the + // parameter type is simply T. So, e.g., in a function that returns `Promise`, you can + // say `return 123;` to return a promise that is already fulfilled to 123. + // + // For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`. + + Promise(kj::Exception&& e); + // Construct an already-broken Promise. + + inline Promise(decltype(nullptr)) {} + + template + PromiseForResult then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException()) + KJ_WARN_UNUSED_RESULT; + // Register a continuation function to be executed when the promise completes. The continuation + // (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation + // may return a new value; `then()` itself returns a promise for the continuation's eventual + // result. If the continuation itself returns a `Promise`, then `then()` shall also return + // a `Promise` which first waits for the original promise, then executes the continuation, + // then waits for the inner promise (i.e. it automatically "unwraps" the promise). + // + // In all cases, `then()` returns immediately. The continuation is executed later. The + // continuation is always executed on the same EventLoop (and, therefore, the same thread) which + // called `then()`, therefore no synchronization is necessary on state shared by the continuation + // and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws + // an exception. + // + // You may also specify an error handler continuation as the second parameter. `errorHandler` + // must be a functor taking a parameter of type `kj::Exception&&`. It must return the same + // type as `func` returns (except when `func` returns `Promise`, in which case `errorHandler` + // may return either `Promise` or just `U`). The default error handler simply propagates the + // exception to the returned promise. + // + // Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise + // is broken. When compiled with -fno-exceptions, the framework will still detect when a + // recoverable exception was thrown inside of a continuation and will consider the promise + // broken even though a (presumably garbage) result was returned. + // + // If the returned promise is destroyed before the callback runs, the callback will be canceled + // (it will never run). + // + // Note that `then()` -- like all other Promise methods -- consumes the promise on which it is + // called, in the sense of move semantics. After returning, the original promise is no longer + // valid, but `then()` returns a new promise. + // + // *Advanced implementation tips:* Most users will never need to worry about the below, but + // it is good to be aware of. + // + // As an optimization, if the callback function `func` does _not_ return another promise, then + // execution of `func` itself may be delayed until its result is known to be needed. The + // expectation here is that `func` is just doing some transformation on the results, not + // scheduling any other actions, therefore the system doesn't need to be proactive about + // evaluating it. This way, a chain of trivial then() transformations can be executed all at + // once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()` + // method to suppress this behavior. + // + // On the other hand, if `func` _does_ return another promise, then the system evaluates `func` + // as soon as possible, because the promise it returns might be for a newly-scheduled + // long-running asynchronous task. + // + // As another optimization, when a callback function registered with `then()` is actually + // scheduled, it is scheduled to occur immediately, preempting other work in the event queue. + // This allows a long chain of `then`s to execute all at once, improving cache locality by + // clustering operations on the same data. However, this implies that starvation can occur + // if a chain of `then()`s takes a very long time to execute without ever stopping to wait for + // actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events + // in the queue will get a chance to run before your callback is executed. + + Promise ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); } + // Convenience method to convert the promise to a void promise by ignoring the return value. + // + // You must still wait on the returned promise if you want the task to execute. + + template + Promise catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; + // Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that + // just returns its input. + + T wait(WaitScope& waitScope); + // Run the event loop until the promise is fulfilled, then return its result. If the promise + // is rejected, throw an exception. + // + // wait() is primarily useful at the top level of a program -- typically, within the function + // that allocated the EventLoop. For example, a program that performs one or two RPCs and then + // exits would likely use wait() in its main() function to wait on each RPC. On the other hand, + // server-side code generally cannot use wait(), because it has to be able to accept multiple + // requests at once. + // + // If the promise is rejected, `wait()` throws an exception. If the program was compiled without + // exceptions (-fno-exceptions), this will usually abort. In this case you really should first + // use `then()` to set an appropriate handler for the exception case, so that the promise you + // actually wait on never throws. + // + // `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By + // convention, any function which might call wait(), or which might call another function which + // might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two + // reasons: + // * `wait()` is not allowed during an event callback, because event callbacks are themselves + // called during some other `wait()`, and such recursive `wait()`s would only be able to + // complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer + // than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during + // an event callback. + // * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()` + // returns. This means that anyone calling `wait()` must be reentrant -- state may change + // around them in arbitrary ways. Therefore, callers really need to know if a function they + // are calling might wait(), and the `WaitScope&` parameter makes this clear. + // + // TODO(someday): Implement fibers, and let them call wait() even when they are handling an + // event. + + ForkedPromise fork() KJ_WARN_UNUSED_RESULT; + // Forks the promise, so that multiple different clients can independently wait on the result. + // `T` must be copy-constructable for this to work. Or, in the special case where `T` is + // `Own`, `U` must have a method `Own addRef()` which returns a new reference to the same + // (or an equivalent) object (probably implemented via reference counting). + + _::SplitTuplePromise split(); + // Split a promise for a tuple into a tuple of promises. + // + // E.g. if you have `Promise>`, `split()` returns + // `kj::Tuple, Promise>`. + + Promise exclusiveJoin(Promise&& other) KJ_WARN_UNUSED_RESULT; + // Return a new promise that resolves when either the original promise resolves or `other` + // resolves (whichever comes first). The promise that didn't resolve first is canceled. + + // TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions + // and produces a tuple? + + template + Promise attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; + // "Attaches" one or more movable objects (often, Owns) to the promise, such that they will + // be destroyed when the promise resolves. This is useful when a promise's callback contains + // pointers into some object and you want to make sure the object still exists when the callback + // runs -- after calling then(), use attach() to add necessary objects to the result. + + template + Promise eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; + Promise eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT; + // Force eager evaluation of this promise. Use this if you are going to hold on to the promise + // for awhile without consuming the result, but you want to make sure that the system actually + // processes it. + // + // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to + // `then()`, except that it must return void. We make you specify this because otherwise it's + // easy to forget to handle errors in a promise that you never use. You may specify nullptr for + // the error handler if you are sure that ignoring errors is fine, or if you know that you'll + // eventually wait on the promise somewhere. + + template + void detach(ErrorFunc&& errorHandler); + // Allows the promise to continue running in the background until it completes or the + // `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this + // promise, you need to make sure that the promise owns all the objects it touches or make sure + // those objects outlive the EventLoop. + // + // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to + // `then()`, except that it must return void. + // + // This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be + // canceled unless the callee explicitly permits it. + + kj::String trace(); + // Returns a dump of debug info about this promise. Not for production use. Requires RTTI. + // This method does NOT consume the promise as other methods do. + +private: + Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {} + // Second parameter prevent ambiguity with immediate-value constructor. + + template + friend class Promise; + friend class EventLoop; + template + friend Promise newAdaptedPromise(Params&&... adapterConstructorParams); + template + friend PromiseFulfillerPair newPromiseAndFulfiller(); + template + friend class _::ForkHub; + friend class _::TaskSetImpl; + friend Promise _::yield(); + friend class _::NeverDone; + template + friend Promise> joinPromises(Array>&& promises); + friend Promise joinPromises(Array>&& promises); +}; + +template +class ForkedPromise { + // The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created. + // Like `Promise`, this is a pass-by-move type. + +public: + inline ForkedPromise(decltype(nullptr)) {} + + Promise addBranch(); + // Add a new branch to the fork. The branch is equivalent to the original promise. + +private: + Own<_::ForkHub<_::FixVoid>> hub; + + inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid>>&& hub): hub(kj::mv(hub)) {} + + friend class Promise; + friend class EventLoop; +}; + +constexpr _::Void READY_NOW = _::Void(); +// Use this when you need a Promise that is already fulfilled -- this value can be implicitly +// cast to `Promise`. + +constexpr _::NeverDone NEVER_DONE = _::NeverDone(); +// The opposite of `READY_NOW`, return this when the promise should never resolve. This can be +// implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait +// forever (useful for servers). + +template +PromiseForResult evalLater(Func&& func) KJ_WARN_UNUSED_RESULT; +// Schedule for the given zero-parameter function to be executed in the event loop at some +// point in the near future. Returns a Promise for its result -- or, if `func()` itself returns +// a promise, `evalLater()` returns a Promise for the result of resolving that promise. +// +// Example usage: +// Promise x = evalLater([]() { return 123; }); +// +// The above is exactly equivalent to: +// Promise x = Promise(READY_NOW).then([]() { return 123; }); +// +// If the returned promise is destroyed before the callback runs, the callback will be canceled +// (never called). +// +// If you schedule several evaluations with `evalLater` during the same callback, they are +// guaranteed to be executed in order. + +template +PromiseForResult evalNow(Func&& func) KJ_WARN_UNUSED_RESULT; +// Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns. +// If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the +// main reason why `evalNow()` is useful. + +template +Promise> joinPromises(Array>&& promises); +// Join an array of promises into a promise for an array. + +// ======================================================================================= +// Hack for creating a lambda that holds an owned pointer. + +template +class CaptureByMove { +public: + inline CaptureByMove(Func&& func, MovedParam&& param) + : func(kj::mv(func)), param(kj::mv(param)) {} + + template + inline auto operator()(Params&&... params) + -> decltype(kj::instance()(kj::instance(), kj::fwd(params)...)) { + return func(kj::mv(param), kj::fwd(params)...); + } + +private: + Func func; + MovedParam param; +}; + +template +inline CaptureByMove> mvCapture(MovedParam&& param, Func&& func) { + // Hack to create a "lambda" which captures a variable by moving it rather than copying or + // referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this + // is commonly needed for Promise continuations that own their state. Example usage: + // + // Own ptr = makeFoo(); + // Promise promise = callRpc(); + // promise.then(mvCapture(ptr, [](Own&& ptr, int result) { + // return ptr->finish(result); + // })); + + return CaptureByMove>(kj::fwd(func), kj::mv(param)); +} + +// ======================================================================================= +// Advanced promise construction + +template +class PromiseFulfiller { + // A callback which can be used to fulfill a promise. Only the first call to fulfill() or + // reject() matters; subsequent calls are ignored. + +public: + virtual void fulfill(T&& value) = 0; + // Fulfill the promise with the given value. + + virtual void reject(Exception&& exception) = 0; + // Reject the promise with an error. + + virtual bool isWaiting() = 0; + // Returns true if the promise is still unfulfilled and someone is potentially waiting for it. + // Returns false if fulfill()/reject() has already been called *or* if the promise to be + // fulfilled has been discarded and therefore the result will never be used anyway. + + template + bool rejectIfThrows(Func&& func); + // Call the function (with no arguments) and return true. If an exception is thrown, call + // `fulfiller.reject()` and then return false. When compiled with exceptions disabled, + // non-fatal exceptions are still detected and handled correctly. +}; + +template <> +class PromiseFulfiller { + // Specialization of PromiseFulfiller for void promises. See PromiseFulfiller. + +public: + virtual void fulfill(_::Void&& value = _::Void()) = 0; + // Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't + // have to specialize for . + + virtual void reject(Exception&& exception) = 0; + virtual bool isWaiting() = 0; + + template + bool rejectIfThrows(Func&& func); +}; + +template +Promise newAdaptedPromise(Params&&... adapterConstructorParams); +// Creates a new promise which owns an instance of `Adapter` which encapsulates the operation +// that will eventually fulfill the promise. This is primarily useful for adapting non-KJ +// asynchronous APIs to use promises. +// +// An instance of `Adapter` will be allocated and owned by the returned `Promise`. A +// `PromiseFulfiller&` will be passed as the first parameter to the adapter's constructor, +// and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter +// is expected to perform some asynchronous operation and call the `PromiseFulfiller` once +// it is finished. +// +// The adapter is destroyed when its owning Promise is destroyed. This may occur before the +// Promise has been fulfilled. In this case, the adapter's destructor should cancel the +// asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be +// called. +// +// An adapter implementation should be carefully written to ensure that it cannot accidentally +// be left unfulfilled permanently because of an exception. Consider making liberal use of +// `PromiseFulfiller::rejectIfThrows()`. + +template +struct PromiseFulfillerPair { + Promise<_::JoinPromises> promise; + Own> fulfiller; +}; + +template +PromiseFulfillerPair newPromiseAndFulfiller(); +// Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise. +// If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is +// implicitly rejected. +// +// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback +// that there is no way to handle cancellation (i.e. detect when the Promise is discarded). +// +// You can arrange to fulfill a promise with another promise by using a promise type for T. E.g. +// `newPromiseAndFulfiller>()` will produce a promise of type `Promise` but the +// fulfiller will be of type `PromiseFulfiller>`. Thus you pass a `Promise` to the +// `fulfill()` callback, and the promises are chained. + +// ======================================================================================= +// TaskSet + +class TaskSet { + // Holds a collection of Promises and ensures that each executes to completion. Memory + // associated with each promise is automatically freed when the promise completes. Destroying + // the TaskSet itself automatically cancels all unfinished promises. + // + // This is useful for "daemon" objects that perform background tasks which aren't intended to + // fulfill any particular external promise, but which may need to be canceled (and thus can't + // use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is + // working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well, + // and everything the daemon is doing is canceled. + +public: + class ErrorHandler { + public: + virtual void taskFailed(kj::Exception&& exception) = 0; + }; + + TaskSet(ErrorHandler& errorHandler); + // `loop` will be used to wait on promises. `errorHandler` will be executed any time a task + // throws an exception, and will execute within the given EventLoop. + + ~TaskSet() noexcept(false); + + void add(Promise&& promise); + + kj::String trace(); + // Return debug info about all promises currently in the TaskSet. + +private: + Own<_::TaskSetImpl> impl; +}; + +// ======================================================================================= +// The EventLoop class + +class EventPort { + // Interfaces between an `EventLoop` and events originating from outside of the loop's thread. + // All such events come in through the `EventPort` implementation. + // + // An `EventPort` implementation may interface with low-level operating system APIs and/or other + // threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop + // framework, allowing the two to coexist in a single thread. + +public: + virtual bool wait() = 0; + // Wait for an external event to arrive, sleeping if necessary. Once at least one event has + // arrived, queue it to the event loop (e.g. by fulfilling a promise) and return. + // + // This is called during `Promise::wait()` whenever the event queue becomes empty, in order to + // wait for new events to populate the queue. + // + // It is safe to return even if nothing has actually been queued, so long as calling `wait()` in + // a loop will eventually sleep. (That is to say, false positives are fine.) + // + // Returns true if wake() has been called from another thread. (Precisely, returns true if + // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last + // called.) + + virtual bool poll() = 0; + // Check if any external events have arrived, but do not sleep. If any events have arrived, + // add them to the event queue (e.g. by fulfilling promises) before returning. + // + // This may be called during `Promise::wait()` when the EventLoop has been executing for a while + // without a break but is still non-empty. + // + // Returns true if wake() has been called from another thread. (Precisely, returns true if + // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last + // called.) + + virtual void setRunnable(bool runnable); + // Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it + // transitions from empty -> runnable or runnable -> empty. This is typically useful when + // integrating with an external event loop; if the loop is currently runnable then you should + // arrange to call run() on it soon. The default implementation does nothing. + + virtual void wake() const; + // Wake up the EventPort's thread from another thread. + // + // Unlike all other methods on this interface, `wake()` may be called from another thread, hence + // it is `const`. + // + // Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep + // again until `wait()` or `poll()` has returned true at least once. + // + // The default implementation throws an UNIMPLEMENTED exception. +}; + +class EventLoop { + // Represents a queue of events being executed in a loop. Most code won't interact with + // EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the + // documentation for `Promise`. + // + // Each thread can have at most one current EventLoop. To make an `EventLoop` current for + // the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop, + // or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly + // be passed a reference to the `WaitScope` to make the caller aware that they might block. + // + // Generally, you will want to construct an `EventLoop` at the top level of your program, e.g. + // in the main() function, or in the start function of a thread. You can then use it to + // construct some promises and wait on the result. Example: + // + // int main() { + // // `loop` becomes the official EventLoop for the thread. + // MyEventPort eventPort; + // EventLoop loop(eventPort); + // + // // Now we can call an async function. + // Promise textPromise = getHttp("http://example.com"); + // + // // And we can wait for the promise to complete. Note that you can only use `wait()` + // // from the top level, not from inside a promise callback. + // String text = textPromise.wait(); + // print(text); + // return 0; + // } + // + // Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather + // than allocate an `EventLoop` directly. + +public: + EventLoop(); + // Construct an `EventLoop` which does not receive external events at all. + + explicit EventLoop(EventPort& port); + // Construct an `EventLoop` which receives external events through the given `EventPort`. + + ~EventLoop() noexcept(false); + + void run(uint maxTurnCount = maxValue); + // Run the event loop for `maxTurnCount` turns or until there is nothing left to be done, + // whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will + // call the `EventPort`'s `setRunnable(false)` if the queue becomes empty. + + bool isRunnable(); + // Returns true if run() would currently do anything, or false if the queue is empty. + +private: + EventPort& port; + + bool running = false; + // True while looping -- wait() is then not allowed. + + bool lastRunnableState = false; + // What did we last pass to port.setRunnable()? + + _::Event* head = nullptr; + _::Event** tail = &head; + _::Event** depthFirstInsertPoint = &head; + + Own<_::TaskSetImpl> daemons; + + bool turn(); + void setRunnable(bool runnable); + void enterScope(); + void leaveScope(); + + friend void _::detach(kj::Promise&& promise); + friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, + WaitScope& waitScope); + friend class _::Event; + friend class WaitScope; +}; + +class WaitScope { + // Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually + // be allocated on the stack and serves two purposes: + // * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the + // thread. Most operations dealing with `Promise` (including all of its methods) do not work + // unless the thread has a current `EventLoop`. + // * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular + // promise to complete. See `Promise::wait()` for an extended discussion. + +public: + inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); } + inline ~WaitScope() { loop.leaveScope(); } + KJ_DISALLOW_COPY(WaitScope); + +private: + EventLoop& loop; + friend class EventLoop; + friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, + WaitScope& waitScope); +}; + +} // namespace kj + +#include "async-inl.h" + +#endif // KJ_ASYNC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/common.h --- a/osx/include/kj/common.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/common.h Mon May 22 10:01:37 2017 +0100 @@ -1,1342 +1,1400 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Header that should be #included by everyone. -// -// This defines very simple utilities that are widely applicable. - -#ifndef KJ_COMMON_H_ -#define KJ_COMMON_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#ifndef KJ_NO_COMPILER_CHECK -#if __cplusplus < 201103L && !__CDT_PARSER__ && !_MSC_VER - #error "This code requires C++11. Either your compiler does not support it or it is not enabled." - #ifdef __GNUC__ - // Compiler claims compatibility with GCC, so presumably supports -std. - #error "Pass -std=c++11 on the compiler command line to enable C++11." - #endif -#endif - -#ifdef __GNUC__ - #if __clang__ - #if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2) - #warning "This library requires at least Clang 3.2." - #elif defined(__apple_build_version__) && __apple_build_version__ <= 4250028 - #warning "This library requires at least Clang 3.2. XCode 4.6's Clang, which claims to be "\ - "version 4.2 (wat?), is actually built from some random SVN revision between 3.1 "\ - "and 3.2. Unfortunately, it is insufficient for compiling this library. You can "\ - "download the real Clang 3.2 (or newer) from the Clang web site. Step-by-step "\ - "instructions can be found in Cap'n Proto's documentation: "\ - "http://kentonv.github.io/capnproto/install.html#clang_32_on_mac_osx" - #elif __cplusplus >= 201103L && !__has_include() - #warning "Your compiler supports C++11 but your C++ standard library does not. If your "\ - "system has libc++ installed (as should be the case on e.g. Mac OSX), try adding "\ - "-stdlib=libc++ to your CXXFLAGS." - #endif - #else - #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) - #warning "This library requires at least GCC 4.7." - #endif - #endif -#elif defined(_MSC_VER) - #if _MSC_VER < 1900 - #error "You need Visual Studio 2015 or better to compile this code." - #elif !CAPNP_LITE - // TODO(cleanup): This is KJ, but we're talking about Cap'n Proto. - #error "As of this writing, Cap'n Proto only supports Visual C++ in 'lite mode'; please #define CAPNP_LITE" - #endif -#else - #warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\ - "known compilers with enough C++11 support for this library. "\ - "#define KJ_NO_COMPILER_CHECK to make this warning go away." -#endif -#endif - -#include -#include - -#if __linux__ && __cplusplus > 201200L -// Hack around stdlib bug with C++14 that exists on some Linux systems. -// Apparently in this mode the C library decides not to define gets() but the C++ library still -// tries to import it into the std namespace. This bug has been fixed at the source but is still -// widely present in the wild e.g. on Ubuntu 14.04. -#undef _GLIBCXX_HAVE_GETS -#endif - -#if defined(_MSC_VER) -#include // __popcnt -#endif - -// ======================================================================================= - -namespace kj { - -typedef unsigned int uint; -typedef unsigned char byte; - -// ======================================================================================= -// Common macros, especially for common yet compiler-specific features. - -// Detect whether RTTI and exceptions are enabled, assuming they are unless we have specific -// evidence to the contrary. Clients can always define KJ_NO_RTTI or KJ_NO_EXCEPTIONS explicitly -// to override these checks. -#ifdef __GNUC__ - #if !defined(KJ_NO_RTTI) && !__GXX_RTTI - #define KJ_NO_RTTI 1 - #endif - #if !defined(KJ_NO_EXCEPTIONS) && !__EXCEPTIONS - #define KJ_NO_EXCEPTIONS 1 - #endif -#elif defined(_MSC_VER) - #if !defined(KJ_NO_RTTI) && !defined(_CPPRTTI) - #define KJ_NO_RTTI 1 - #endif - #if !defined(KJ_NO_EXCEPTIONS) && !defined(_CPPUNWIND) - #define KJ_NO_EXCEPTIONS 1 - #endif -#endif - -#if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG) -// Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that. -// Otherwise, fall back to checking whether optimization is enabled. -#if defined(DEBUG) || defined(_DEBUG) -#define KJ_DEBUG -#elif defined(NDEBUG) -#define KJ_NDEBUG -#elif __OPTIMIZE__ -#define KJ_NDEBUG -#else -#define KJ_DEBUG -#endif -#endif - -#define KJ_DISALLOW_COPY(classname) \ - classname(const classname&) = delete; \ - classname& operator=(const classname&) = delete -// Deletes the implicit copy constructor and assignment operator. - -#ifdef __GNUC__ -#define KJ_LIKELY(condition) __builtin_expect(condition, true) -#define KJ_UNLIKELY(condition) __builtin_expect(condition, false) -// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we -// expect the condition to be true/false enough of the time that it's worth hard-coding branch -// prediction. -#else -#define KJ_LIKELY(condition) (condition) -#define KJ_UNLIKELY(condition) (condition) -#endif - -#if defined(KJ_DEBUG) || __NO_INLINE__ -#define KJ_ALWAYS_INLINE(prototype) inline prototype -// Don't force inline in debug mode. -#else -#if defined(_MSC_VER) -#define KJ_ALWAYS_INLINE(prototype) __forceinline prototype -#else -#define KJ_ALWAYS_INLINE(prototype) inline prototype __attribute__((always_inline)) -#endif -// Force a function to always be inlined. Apply only to the prototype, not to the definition. -#endif - -#if defined(_MSC_VER) -#define KJ_NOINLINE __declspec(noinline) -#else -#define KJ_NOINLINE __attribute__((noinline)) -#endif - -#if defined(_MSC_VER) -#define KJ_NORETURN(prototype) __declspec(noreturn) prototype -#define KJ_UNUSED -#define KJ_WARN_UNUSED_RESULT -// TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so -// wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx -// Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix. -#else -#define KJ_NORETURN(prototype) prototype __attribute__((noreturn)) -#define KJ_UNUSED __attribute__((unused)) -#define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#endif - -#if __clang__ -#define KJ_UNUSED_MEMBER __attribute__((unused)) -// Inhibits "unused" warning for member variables. Only Clang produces such a warning, while GCC -// complains if the attribute is set on members. -#else -#define KJ_UNUSED_MEMBER -#endif - -#if __clang__ -#define KJ_DEPRECATED(reason) \ - __attribute__((deprecated(reason))) -#define KJ_UNAVAILABLE(reason) \ - __attribute__((unavailable(reason))) -#elif __GNUC__ -#define KJ_DEPRECATED(reason) \ - __attribute__((deprecated)) -#define KJ_UNAVAILABLE(reason) -#else -#define KJ_DEPRECATED(reason) -#define KJ_UNAVAILABLE(reason) -// TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated). -#endif - -namespace _ { // private - -KJ_NORETURN(void inlineRequireFailure( - const char* file, int line, const char* expectation, const char* macroArgs, - const char* message = nullptr)); - -KJ_NORETURN(void unreachable()); - -} // namespace _ (private) - -#ifdef KJ_DEBUG -#if _MSC_VER -#define KJ_IREQUIRE(condition, ...) \ - if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ - __FILE__, __LINE__, #condition, "" #__VA_ARGS__, __VA_ARGS__) -// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to -// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that -// it will be enabled depending on whether the application is compiled in debug mode rather than -// whether libkj is. -#else -#define KJ_IREQUIRE(condition, ...) \ - if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ - __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) -// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to -// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that -// it will be enabled depending on whether the application is compiled in debug mode rather than -// whether libkj is. -#endif -#else -#define KJ_IREQUIRE(condition, ...) -#endif - -#define KJ_IASSERT KJ_IREQUIRE - -#define KJ_UNREACHABLE ::kj::_::unreachable(); -// Put this on code paths that cannot be reached to suppress compiler warnings about missing -// returns. - -#if __clang__ -#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT -#else -#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT KJ_UNREACHABLE -#endif - -// #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) -// -// Allocate an array, preferably on the stack, unless it is too big. On GCC this will use -// variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack` -// is the stack array size to use if variable-width arrays are not supported. `maxStack` is the -// maximum stack array size if variable-width arrays *are* supported. -#if __GNUC__ && !__clang__ -#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ - size_t name##_size = (size); \ - bool name##_isOnStack = name##_size <= (maxStack); \ - type name##_stack[name##_isOnStack ? size : 0]; \ - ::kj::Array name##_heap = name##_isOnStack ? \ - nullptr : kj::heapArray(name##_size); \ - ::kj::ArrayPtr name = name##_isOnStack ? \ - kj::arrayPtr(name##_stack, name##_size) : name##_heap -#else -#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ - size_t name##_size = (size); \ - bool name##_isOnStack = name##_size <= (minStack); \ - type name##_stack[minStack]; \ - ::kj::Array name##_heap = name##_isOnStack ? \ - nullptr : kj::heapArray(name##_size); \ - ::kj::ArrayPtr name = name##_isOnStack ? \ - kj::arrayPtr(name##_stack, name##_size) : name##_heap -#endif - -#define KJ_CONCAT_(x, y) x##y -#define KJ_CONCAT(x, y) KJ_CONCAT_(x, y) -#define KJ_UNIQUE_NAME(prefix) KJ_CONCAT(prefix, __LINE__) -// Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that -// the name can be used multiple times in the same macro. - -#if _MSC_VER - -#define KJ_CONSTEXPR(...) __VA_ARGS__ -// Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be -// provided, or just leave blank to remove the keyword entirely. -// -// TODO(msvc): Remove this hack once MSVC fully supports constexpr. - -#ifndef __restrict__ -#define __restrict__ __restrict -// TODO(msvc): Would it be better to define a KJ_RESTRICT macro? -#endif - -#pragma warning(disable: 4521 4522) -// This warning complains when there are two copy constructors, one for a const reference and -// one for a non-const reference. It is often quite necessary to do this in wrapper templates, -// therefore this warning is dumb and we disable it. - -#pragma warning(disable: 4458) -// Warns when a parameter name shadows a class member. Unfortunately my code does this a lot, -// since I don't use a special name format for members. - -#else // _MSC_VER -#define KJ_CONSTEXPR(...) constexpr -#endif - -// ======================================================================================= -// Template metaprogramming helpers. - -template struct NoInfer_ { typedef T Type; }; -template using NoInfer = typename NoInfer_::Type; -// Use NoInfer::Type in place of T for a template function parameter to prevent inference of -// the type based on the parameter value. - -template struct RemoveConst_ { typedef T Type; }; -template struct RemoveConst_ { typedef T Type; }; -template using RemoveConst = typename RemoveConst_::Type; - -template struct IsLvalueReference_ { static constexpr bool value = false; }; -template struct IsLvalueReference_ { static constexpr bool value = true; }; -template -inline constexpr bool isLvalueReference() { return IsLvalueReference_::value; } - -template struct Decay_ { typedef T Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template struct Decay_ { typedef typename Decay_::Type Type; }; -template using Decay = typename Decay_::Type; - -template struct EnableIf_; -template <> struct EnableIf_ { typedef void Type; }; -template using EnableIf = typename EnableIf_::Type; -// Use like: -// -// template ()> -// void func(T&& t); - -template struct VoidSfinae_ { using Type = void; }; -template using VoidSfinae = typename VoidSfinae_::Type; -// Note: VoidSfinae is std::void_t from C++17. - -template -T instance() noexcept; -// Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify -// instance(). - -struct DisallowConstCopy { - // Inherit from this, or declare a member variable of this type, to prevent the class from being - // copyable from a const reference -- instead, it will only be copyable from non-const references. - // This is useful for enforcing transitive constness of contained pointers. - // - // For example, say you have a type T which contains a pointer. T has non-const methods which - // modify the value at that pointer, but T's const methods are designed to allow reading only. - // Unfortunately, if T has a regular copy constructor, someone can simply make a copy of T and - // then use it to modify the pointed-to value. However, if T inherits DisallowConstCopy, then - // callers will only be able to copy non-const instances of T. Ideally, there is some - // parallel type ImmutableT which is like a version of T that only has const methods, and can - // be copied from a const T. - // - // Note that due to C++ rules about implicit copy constructors and assignment operators, any - // type that contains or inherits from a type that disallows const copies will also automatically - // disallow const copies. Hey, cool, that's exactly what we want. - - DisallowConstCopy() = default; - DisallowConstCopy(DisallowConstCopy&) = default; - DisallowConstCopy(DisallowConstCopy&&) = default; - DisallowConstCopy& operator=(DisallowConstCopy&) = default; - DisallowConstCopy& operator=(DisallowConstCopy&&) = default; -}; - -template -struct DisallowConstCopyIfNotConst: public DisallowConstCopy { - // Inherit from this when implementing a template that contains a pointer to T and which should - // enforce transitive constness. If T is a const type, this has no effect. Otherwise, it is - // an alias for DisallowConstCopy. -}; - -template -struct DisallowConstCopyIfNotConst {}; - -template struct IsConst_ { static constexpr bool value = false; }; -template struct IsConst_ { static constexpr bool value = true; }; -template constexpr bool isConst() { return IsConst_::value; } - -template struct EnableIfNotConst_ { typedef T Type; }; -template struct EnableIfNotConst_; -template using EnableIfNotConst = typename EnableIfNotConst_::Type; - -template struct EnableIfConst_; -template struct EnableIfConst_ { typedef T Type; }; -template using EnableIfConst = typename EnableIfConst_::Type; - -template struct RemoveConstOrDisable_ { struct Type; }; -template struct RemoveConstOrDisable_ { typedef T Type; }; -template using RemoveConstOrDisable = typename RemoveConstOrDisable_::Type; - -template struct IsReference_ { static constexpr bool value = false; }; -template struct IsReference_ { static constexpr bool value = true; }; -template constexpr bool isReference() { return IsReference_::value; } - -template -struct PropagateConst_ { typedef To Type; }; -template -struct PropagateConst_ { typedef const To Type; }; -template -using PropagateConst = typename PropagateConst_::Type; - -namespace _ { // private - -template -T refIfLvalue(T&&); - -} // namespace _ (private) - -#define KJ_DECLTYPE_REF(exp) decltype(::kj::_::refIfLvalue(exp)) -// Like decltype(exp), but if exp is an lvalue, produces a reference type. -// -// int i; -// decltype(i) i1(i); // i1 has type int. -// KJ_DECLTYPE_REF(i + 1) i2(i + 1); // i2 has type int. -// KJ_DECLTYPE_REF(i) i3(i); // i3 has type int&. -// KJ_DECLTYPE_REF(kj::mv(i)) i4(kj::mv(i)); // i4 has type int. - -template -struct CanConvert_ { - static int sfinae(T); - static bool sfinae(...); -}; - -template -constexpr bool canConvert() { - return sizeof(CanConvert_::sfinae(instance())) == sizeof(int); -} - -#if __clang__ -template -constexpr bool canMemcpy() { - // Returns true if T can be copied using memcpy instead of using the copy constructor or - // assignment operator. - - // Clang unhelpfully defines __has_trivial_{copy,assign}(T) to be true if the copy constructor / - // assign operator are deleted, on the basis that a strict reading of the definition of "trivial" - // according to the standard says that deleted functions are in fact trivial. Meanwhile Clang - // provides these admittedly-better intrinsics, but GCC does not. - return __is_trivially_constructible(T, const T&) && __is_trivially_assignable(T, const T&); -} -#else -template -constexpr bool canMemcpy() { - // Returns true if T can be copied using memcpy instead of using the copy constructor or - // assignment operator. - - // GCC defines these to mean what we want them to mean. - return __has_trivial_copy(T) && __has_trivial_assign(T); -} -#endif - -// ======================================================================================= -// Equivalents to std::move() and std::forward(), since these are very commonly needed and the -// std header pulls in lots of other stuff. -// -// We use abbreviated names mv and fwd because these helpers (especially mv) are so commonly used -// that the cost of typing more letters outweighs the cost of being slightly harder to understand -// when first encountered. - -template constexpr T&& mv(T& t) noexcept { return static_cast(t); } -template constexpr T&& fwd(NoInfer& t) noexcept { return static_cast(t); } - -template constexpr T cp(T& t) noexcept { return t; } -template constexpr T cp(const T& t) noexcept { return t; } -// Useful to force a copy, particularly to pass into a function that expects T&&. - -template struct MinType_; -template struct MinType_ { typedef T Type; }; -template struct MinType_ { typedef U Type; }; - -template -using MinType = typename MinType_::Type; -// Resolves to the smaller of the two input types. - -template -inline constexpr auto min(T&& a, U&& b) -> MinType, Decay> { - return a < b ? MinType, Decay>(a) : MinType, Decay>(b); -} - -template struct MaxType_; -template struct MaxType_ { typedef T Type; }; -template struct MaxType_ { typedef U Type; }; - -template -using MaxType = typename MaxType_= sizeof(U)>::Type; -// Resolves to the larger of the two input types. - -template -inline constexpr auto max(T&& a, U&& b) -> MaxType, Decay> { - return a > b ? MaxType, Decay>(a) : MaxType, Decay>(b); -} - -template -inline constexpr size_t size(T (&arr)[s]) { return s; } -template -inline constexpr size_t size(T&& arr) { return arr.size(); } -// Returns the size of the parameter, whether the parameter is a regular C array or a container -// with a `.size()` method. - -class MaxValue_ { -private: - template - inline constexpr T maxSigned() const { - return (1ull << (sizeof(T) * 8 - 1)) - 1; - } - template - inline constexpr T maxUnsigned() const { - return ~static_cast(0u); - } - -public: -#define _kJ_HANDLE_TYPE(T) \ - inline constexpr operator signed T() const { return MaxValue_::maxSigned < signed T>(); } \ - inline constexpr operator unsigned T() const { return MaxValue_::maxUnsigned(); } - _kJ_HANDLE_TYPE(char) - _kJ_HANDLE_TYPE(short) - _kJ_HANDLE_TYPE(int) - _kJ_HANDLE_TYPE(long) - _kJ_HANDLE_TYPE(long long) -#undef _kJ_HANDLE_TYPE - - inline constexpr operator char() const { - // `char` is different from both `signed char` and `unsigned char`, and may be signed or - // unsigned on different platforms. Ugh. - return char(-1) < 0 ? MaxValue_::maxSigned() - : MaxValue_::maxUnsigned(); - } -}; - -class MinValue_ { -private: - template - inline constexpr T minSigned() const { - return 1ull << (sizeof(T) * 8 - 1); - } - template - inline constexpr T minUnsigned() const { - return 0u; - } - -public: -#define _kJ_HANDLE_TYPE(T) \ - inline constexpr operator signed T() const { return MinValue_::minSigned < signed T>(); } \ - inline constexpr operator unsigned T() const { return MinValue_::minUnsigned(); } - _kJ_HANDLE_TYPE(char) - _kJ_HANDLE_TYPE(short) - _kJ_HANDLE_TYPE(int) - _kJ_HANDLE_TYPE(long) - _kJ_HANDLE_TYPE(long long) -#undef _kJ_HANDLE_TYPE - - inline constexpr operator char() const { - // `char` is different from both `signed char` and `unsigned char`, and may be signed or - // unsigned on different platforms. Ugh. - return char(-1) < 0 ? MinValue_::minSigned() - : MinValue_::minUnsigned(); - } -}; - -static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_(); -// A special constant which, when cast to an integer type, takes on the maximum possible value of -// that type. This is useful to use as e.g. a parameter to a function because it will be robust -// in the face of changes to the parameter's type. -// -// `char` is not supported, but `signed char` and `unsigned char` are. - -static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_(); -// A special constant which, when cast to an integer type, takes on the minimum possible value -// of that type. This is useful to use as e.g. a parameter to a function because it will be robust -// in the face of changes to the parameter's type. -// -// `char` is not supported, but `signed char` and `unsigned char` are. - -#if __GNUC__ -inline constexpr float inf() { return __builtin_huge_valf(); } -inline constexpr float nan() { return __builtin_nanf(""); } - -#elif _MSC_VER - -// Do what MSVC math.h does -#pragma warning(push) -#pragma warning(disable: 4756) // "overflow in constant arithmetic" -inline constexpr float inf() { return (float)(1e300 * 1e300); } -#pragma warning(pop) - -float nan(); -// Unfortunatley, inf() * 0.0f produces a NaN with the sign bit set, whereas our preferred -// canonical NaN should not have the sign bit set. std::numeric_limits::quiet_NaN() -// returns the correct NaN, but we don't want to #include that here. So, we give up and make -// this out-of-line on MSVC. -// -// TODO(msvc): Can we do better? - -#else -#error "Not sure how to support your compiler." -#endif - -inline constexpr bool isNaN(float f) { return f != f; } -inline constexpr bool isNaN(double f) { return f != f; } - -inline int popCount(unsigned int x) { -#if defined(_MSC_VER) - return __popcnt(x); - // Note: __popcnt returns unsigned int, but the value is clearly guaranteed to fit into an int -#else - return __builtin_popcount(x); -#endif -} - -// ======================================================================================= -// Useful fake containers - -template -class Range { -public: - inline constexpr Range(const T& begin, const T& end): begin_(begin), end_(end) {} - - class Iterator { - public: - Iterator() = default; - inline Iterator(const T& value): value(value) {} - - inline const T& operator* () const { return value; } - inline const T& operator[](size_t index) const { return value + index; } - inline Iterator& operator++() { ++value; return *this; } - inline Iterator operator++(int) { return Iterator(value++); } - inline Iterator& operator--() { --value; return *this; } - inline Iterator operator--(int) { return Iterator(value--); } - inline Iterator& operator+=(ptrdiff_t amount) { value += amount; return *this; } - inline Iterator& operator-=(ptrdiff_t amount) { value -= amount; return *this; } - inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value + amount); } - inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value - amount); } - inline ptrdiff_t operator- (const Iterator& other) const { return value - other.value; } - - inline bool operator==(const Iterator& other) const { return value == other.value; } - inline bool operator!=(const Iterator& other) const { return value != other.value; } - inline bool operator<=(const Iterator& other) const { return value <= other.value; } - inline bool operator>=(const Iterator& other) const { return value >= other.value; } - inline bool operator< (const Iterator& other) const { return value < other.value; } - inline bool operator> (const Iterator& other) const { return value > other.value; } - - private: - T value; - }; - - inline Iterator begin() const { return Iterator(begin_); } - inline Iterator end() const { return Iterator(end_); } - - inline auto size() const -> decltype(instance() - instance()) { return end_ - begin_; } - -private: - T begin_; - T end_; -}; - -template -inline constexpr Range> range(T begin, T end) { return Range>(begin, end); } -// Returns a fake iterable container containing all values of T from `begin` (inclusive) to `end` -// (exclusive). Example: -// -// // Prints 1, 2, 3, 4, 5, 6, 7, 8, 9. -// for (int i: kj::range(1, 10)) { print(i); } - -template -inline constexpr Range indices(T&& container) { - // Shortcut for iterating over the indices of a container: - // - // for (size_t i: kj::indices(myArray)) { handle(myArray[i]); } - - return range(0, kj::size(container)); -} - -template -class Repeat { -public: - inline constexpr Repeat(const T& value, size_t count): value(value), count(count) {} - - class Iterator { - public: - Iterator() = default; - inline Iterator(const T& value, size_t index): value(value), index(index) {} - - inline const T& operator* () const { return value; } - inline const T& operator[](ptrdiff_t index) const { return value; } - inline Iterator& operator++() { ++index; return *this; } - inline Iterator operator++(int) { return Iterator(value, index++); } - inline Iterator& operator--() { --index; return *this; } - inline Iterator operator--(int) { return Iterator(value, index--); } - inline Iterator& operator+=(ptrdiff_t amount) { index += amount; return *this; } - inline Iterator& operator-=(ptrdiff_t amount) { index -= amount; return *this; } - inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value, index + amount); } - inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value, index - amount); } - inline ptrdiff_t operator- (const Iterator& other) const { return index - other.index; } - - inline bool operator==(const Iterator& other) const { return index == other.index; } - inline bool operator!=(const Iterator& other) const { return index != other.index; } - inline bool operator<=(const Iterator& other) const { return index <= other.index; } - inline bool operator>=(const Iterator& other) const { return index >= other.index; } - inline bool operator< (const Iterator& other) const { return index < other.index; } - inline bool operator> (const Iterator& other) const { return index > other.index; } - - private: - T value; - size_t index; - }; - - inline Iterator begin() const { return Iterator(value, 0); } - inline Iterator end() const { return Iterator(value, count); } - - inline size_t size() const { return count; } - -private: - T value; - size_t count; -}; - -template -inline constexpr Repeat> repeat(T&& value, size_t count) { - // Returns a fake iterable which contains `count` repeats of `value`. Useful for e.g. creating - // a bunch of spaces: `kj::repeat(' ', indent * 2)` - - return Repeat>(value, count); -} - -// ======================================================================================= -// Manually invoking constructors and destructors -// -// ctor(x, ...) and dtor(x) invoke x's constructor or destructor, respectively. - -// We want placement new, but we don't want to #include . operator new cannot be defined in -// a namespace, and defining it globally conflicts with the definition in . So we have to -// define a dummy type and an operator new that uses it. - -namespace _ { // private -struct PlacementNew {}; -} // namespace _ (private) -} // namespace kj - -inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { - return __p; -} - -inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {} - -namespace kj { - -template -inline void ctor(T& location, Params&&... params) { - new (_::PlacementNew(), &location) T(kj::fwd(params)...); -} - -template -inline void dtor(T& location) { - location.~T(); -} - -// ======================================================================================= -// Maybe -// -// Use in cases where you want to indicate that a value may be null. Using Maybe instead of T* -// forces the caller to handle the null case in order to satisfy the compiler, thus reliably -// preventing null pointer dereferences at runtime. -// -// Maybe can be implicitly constructed from T and from nullptr. Additionally, it can be -// implicitly constructed from T*, in which case the pointer is checked for nullness at runtime. -// To read the value of a Maybe, do: -// -// KJ_IF_MAYBE(value, someFuncReturningMaybe()) { -// doSomething(*value); -// } else { -// maybeWasNull(); -// } -// -// KJ_IF_MAYBE's first parameter is a variable name which will be defined within the following -// block. The variable will behave like a (guaranteed non-null) pointer to the Maybe's value, -// though it may or may not actually be a pointer. -// -// Note that Maybe actually just wraps a pointer, whereas Maybe wraps a T and a boolean -// indicating nullness. - -template -class Maybe; - -namespace _ { // private - -#if _MSC_VER - // TODO(msvc): MSVC barfs on noexcept(instance().~T()) where T = kj::Exception and - // kj::_::Void. It and every other factorization I've tried produces: - // error C2325: 'kj::Blah' unexpected type to the right of '.~': expected 'void' -#define MSVC_NOEXCEPT_DTOR_WORKAROUND(T) __is_nothrow_destructible(T) -#else -#define MSVC_NOEXCEPT_DTOR_WORKAROUND(T) noexcept(instance().~T()) -#endif - -template -class NullableValue { - // Class whose interface behaves much like T*, but actually contains an instance of T and a - // boolean flag indicating nullness. - -public: - inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) - : isSet(other.isSet) { - if (isSet) { - ctor(value, kj::mv(other.value)); - } - } - inline NullableValue(const NullableValue& other) - : isSet(other.isSet) { - if (isSet) { - ctor(value, other.value); - } - } - inline NullableValue(NullableValue& other) - : isSet(other.isSet) { - if (isSet) { - ctor(value, other.value); - } - } - inline ~NullableValue() noexcept(MSVC_NOEXCEPT_DTOR_WORKAROUND(T)) { - if (isSet) { - dtor(value); - } - } - - inline T& operator*() & { return value; } - inline const T& operator*() const & { return value; } - inline T&& operator*() && { return kj::mv(value); } - inline const T&& operator*() const && { return kj::mv(value); } - inline T* operator->() { return &value; } - inline const T* operator->() const { return &value; } - inline operator T*() { return isSet ? &value : nullptr; } - inline operator const T*() const { return isSet ? &value : nullptr; } - - template - inline T& emplace(Params&&... params) { - if (isSet) { - isSet = false; - dtor(value); - } - ctor(value, kj::fwd(params)...); - isSet = true; - return value; - } - -private: // internal interface used by friends only - inline NullableValue() noexcept: isSet(false) {} - inline NullableValue(T&& t) noexcept(noexcept(T(instance()))) - : isSet(true) { - ctor(value, kj::mv(t)); - } - inline NullableValue(T& t) - : isSet(true) { - ctor(value, t); - } - inline NullableValue(const T& t) - : isSet(true) { - ctor(value, t); - } - inline NullableValue(const T* t) - : isSet(t != nullptr) { - if (isSet) ctor(value, *t); - } - template - inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) - : isSet(other.isSet) { - if (isSet) { - ctor(value, kj::mv(other.value)); - } - } - template - inline NullableValue(const NullableValue& other) - : isSet(other.isSet) { - if (isSet) { - ctor(value, other.value); - } - } - template - inline NullableValue(const NullableValue& other) - : isSet(other.isSet) { - if (isSet) { - ctor(value, *other.ptr); - } - } - inline NullableValue(decltype(nullptr)): isSet(false) {} - - inline NullableValue& operator=(NullableValue&& other) { - if (&other != this) { - // Careful about throwing destructors/constructors here. - if (isSet) { - isSet = false; - dtor(value); - } - if (other.isSet) { - ctor(value, kj::mv(other.value)); - isSet = true; - } - } - return *this; - } - - inline NullableValue& operator=(NullableValue& other) { - if (&other != this) { - // Careful about throwing destructors/constructors here. - if (isSet) { - isSet = false; - dtor(value); - } - if (other.isSet) { - ctor(value, other.value); - isSet = true; - } - } - return *this; - } - - inline NullableValue& operator=(const NullableValue& other) { - if (&other != this) { - // Careful about throwing destructors/constructors here. - if (isSet) { - isSet = false; - dtor(value); - } - if (other.isSet) { - ctor(value, other.value); - isSet = true; - } - } - return *this; - } - - inline bool operator==(decltype(nullptr)) const { return !isSet; } - inline bool operator!=(decltype(nullptr)) const { return isSet; } - -private: - bool isSet; - -#if _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4624) -// Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning -// seems broken. -#endif - - union { - T value; - }; - -#if _MSC_VER -#pragma warning(pop) -#endif - - friend class kj::Maybe; - template - friend NullableValue&& readMaybe(Maybe&& maybe); -}; - -template -inline NullableValue&& readMaybe(Maybe&& maybe) { return kj::mv(maybe.ptr); } -template -inline T* readMaybe(Maybe& maybe) { return maybe.ptr; } -template -inline const T* readMaybe(const Maybe& maybe) { return maybe.ptr; } -template -inline T* readMaybe(Maybe&& maybe) { return maybe.ptr; } -template -inline T* readMaybe(const Maybe& maybe) { return maybe.ptr; } - -template -inline T* readMaybe(T* ptr) { return ptr; } -// Allow KJ_IF_MAYBE to work on regular pointers. - -} // namespace _ (private) - -#define KJ_IF_MAYBE(name, exp) if (auto name = ::kj::_::readMaybe(exp)) - -template -class Maybe { - // A T, or nullptr. - - // IF YOU CHANGE THIS CLASS: Note that there is a specialization of it in memory.h. - -public: - Maybe(): ptr(nullptr) {} - Maybe(T&& t) noexcept(noexcept(T(instance()))): ptr(kj::mv(t)) {} - Maybe(T& t): ptr(t) {} - Maybe(const T& t): ptr(t) {} - Maybe(const T* t) noexcept: ptr(t) {} - Maybe(Maybe&& other) noexcept(noexcept(T(instance()))): ptr(kj::mv(other.ptr)) {} - Maybe(const Maybe& other): ptr(other.ptr) {} - Maybe(Maybe& other): ptr(other.ptr) {} - - template - Maybe(Maybe&& other) noexcept(noexcept(T(instance()))) { - KJ_IF_MAYBE(val, kj::mv(other)) { - ptr = *val; - } - } - template - Maybe(const Maybe& other) { - KJ_IF_MAYBE(val, other) { - ptr = *val; - } - } - - Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} - - template - inline T& emplace(Params&&... params) { - // Replace this Maybe's content with a new value constructed by passing the given parametrs to - // T's constructor. This can be used to initialize a Maybe without copying or even moving a T. - // Returns a reference to the newly-constructed value. - - return ptr.emplace(kj::fwd(params)...); - } - - inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } - inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; } - inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; } - - inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } - - T& orDefault(T& defaultValue) { - if (ptr == nullptr) { - return defaultValue; - } else { - return *ptr; - } - } - const T& orDefault(const T& defaultValue) const { - if (ptr == nullptr) { - return defaultValue; - } else { - return *ptr; - } - } - - template - auto map(Func&& f) & -> Maybe()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(*ptr); - } - } - - template - auto map(Func&& f) const & -> Maybe()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(*ptr); - } - } - - template - auto map(Func&& f) && -> Maybe()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(kj::mv(*ptr)); - } - } - - template - auto map(Func&& f) const && -> Maybe()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(kj::mv(*ptr)); - } - } - -private: - _::NullableValue ptr; - - template - friend class Maybe; - template - friend _::NullableValue&& _::readMaybe(Maybe&& maybe); - template - friend U* _::readMaybe(Maybe& maybe); - template - friend const U* _::readMaybe(const Maybe& maybe); -}; - -template -class Maybe: public DisallowConstCopyIfNotConst { -public: - Maybe() noexcept: ptr(nullptr) {} - Maybe(T& t) noexcept: ptr(&t) {} - Maybe(T* t) noexcept: ptr(t) {} - - template - inline Maybe(Maybe& other) noexcept: ptr(other.ptr) {} - template - inline Maybe(const Maybe& other) noexcept: ptr(other.ptr) {} - inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} - - inline Maybe& operator=(T& other) noexcept { ptr = &other; return *this; } - inline Maybe& operator=(T* other) noexcept { ptr = other; return *this; } - template - inline Maybe& operator=(Maybe& other) noexcept { ptr = other.ptr; return *this; } - template - inline Maybe& operator=(const Maybe& other) noexcept { ptr = other.ptr; return *this; } - - inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } - - T& orDefault(T& defaultValue) { - if (ptr == nullptr) { - return defaultValue; - } else { - return *ptr; - } - } - const T& orDefault(const T& defaultValue) const { - if (ptr == nullptr) { - return defaultValue; - } else { - return *ptr; - } - } - - template - auto map(Func&& f) -> Maybe()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(*ptr); - } - } - -private: - T* ptr; - - template - friend class Maybe; - template - friend U* _::readMaybe(Maybe&& maybe); - template - friend U* _::readMaybe(const Maybe& maybe); -}; - -// ======================================================================================= -// ArrayPtr -// -// So common that we put it in common.h rather than array.h. - -template -class ArrayPtr: public DisallowConstCopyIfNotConst { - // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data, - // and passing by value only copies the pointer, not the target. - -public: - inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {} - inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {} - inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {} - inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {} - inline KJ_CONSTEXPR() ArrayPtr(::std::initializer_list> init) - : ptr(init.begin()), size_(init.size()) {} - - template - inline constexpr ArrayPtr(T (&native)[size]): ptr(native), size_(size) {} - // Construct an ArrayPtr from a native C-style array. - - inline operator ArrayPtr() const { - return ArrayPtr(ptr, size_); - } - inline ArrayPtr asConst() const { - return ArrayPtr(ptr, size_); - } - - inline size_t size() const { return size_; } - inline const T& operator[](size_t index) const { - KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); - return ptr[index]; - } - inline T& operator[](size_t index) { - KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); - return ptr[index]; - } - - inline T* begin() { return ptr; } - inline T* end() { return ptr + size_; } - inline T& front() { return *ptr; } - inline T& back() { return *(ptr + size_ - 1); } - inline const T* begin() const { return ptr; } - inline const T* end() const { return ptr + size_; } - inline const T& front() const { return *ptr; } - inline const T& back() const { return *(ptr + size_ - 1); } - - inline ArrayPtr slice(size_t start, size_t end) const { - KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); - return ArrayPtr(ptr + start, end - start); - } - inline ArrayPtr slice(size_t start, size_t end) { - KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); - return ArrayPtr(ptr + start, end - start); - } - - inline ArrayPtr> asBytes() const { - // Reinterpret the array as a byte array. This is explicitly legal under C++ aliasing - // rules. - return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; - } - inline ArrayPtr> asChars() const { - // Reinterpret the array as a char array. This is explicitly legal under C++ aliasing - // rules. - return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; - } - - inline bool operator==(decltype(nullptr)) const { return size_ == 0; } - inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } - - inline bool operator==(const ArrayPtr& other) const { - if (size_ != other.size_) return false; - for (size_t i = 0; i < size_; i++) { - if (ptr[i] != other[i]) return false; - } - return true; - } - inline bool operator!=(const ArrayPtr& other) const { return !(*this == other); } - -private: - T* ptr; - size_t size_; -}; - -template -inline constexpr ArrayPtr arrayPtr(T* ptr, size_t size) { - // Use this function to construct ArrayPtrs without writing out the type name. - return ArrayPtr(ptr, size); -} - -template -inline constexpr ArrayPtr arrayPtr(T* begin, T* end) { - // Use this function to construct ArrayPtrs without writing out the type name. - return ArrayPtr(begin, end); -} - -// ======================================================================================= -// Casts - -template -To implicitCast(From&& from) { - // `implicitCast(value)` casts `value` to type `T` only if the conversion is implicit. Useful - // for e.g. resolving ambiguous overloads without sacrificing type-safety. - return kj::fwd(from); -} - -template -Maybe dynamicDowncastIfAvailable(From& from) { - // If RTTI is disabled, always returns nullptr. Otherwise, works like dynamic_cast. Useful - // in situations where dynamic_cast could allow an optimization, but isn't strictly necessary - // for correctness. It is highly recommended that you try to arrange all your dynamic_casts - // this way, as a dynamic_cast that is necessary for correctness implies a flaw in the interface - // design. - - // Force a compile error if To is not a subtype of From. Cross-casting is rare; if it is needed - // we should have a separate cast function like dynamicCrosscastIfAvailable(). - if (false) { - kj::implicitCast(kj::implicitCast(nullptr)); - } - -#if KJ_NO_RTTI - return nullptr; -#else - return dynamic_cast(&from); -#endif -} - -template -To& downcast(From& from) { - // Down-cast a value to a sub-type, asserting that the cast is valid. In opt mode this is a - // static_cast, but in debug mode (when RTTI is enabled) a dynamic_cast will be used to verify - // that the value really has the requested type. - - // Force a compile error if To is not a subtype of From. - if (false) { - kj::implicitCast(kj::implicitCast(nullptr)); - } - -#if !KJ_NO_RTTI - KJ_IREQUIRE(dynamic_cast(&from) != nullptr, "Value cannot be downcast() to requested type."); -#endif - - return static_cast(from); -} - -// ======================================================================================= -// Defer - -namespace _ { // private - -template -class Deferred { -public: - inline Deferred(Func&& func): func(kj::fwd(func)), canceled(false) {} - inline ~Deferred() noexcept(false) { if (!canceled) func(); } - KJ_DISALLOW_COPY(Deferred); - - // This move constructor is usually optimized away by the compiler. - inline Deferred(Deferred&& other): func(kj::mv(other.func)), canceled(false) { - other.canceled = true; - } -private: - Func func; - bool canceled; -}; - -} // namespace _ (private) - -template -_::Deferred defer(Func&& func) { - // Returns an object which will invoke the given functor in its destructor. The object is not - // copyable but is movable with the semantics you'd expect. Since the return type is private, - // you need to assign to an `auto` variable. - // - // The KJ_DEFER macro provides slightly more convenient syntax for the common case where you - // want some code to run at current scope exit. - - return _::Deferred(kj::fwd(func)); -} - -#define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::defer([&](){code;}) -// Run the given code when the function exits, whether by return or exception. - -} // namespace kj - -#endif // KJ_COMMON_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Header that should be #included by everyone. +// +// This defines very simple utilities that are widely applicable. + +#ifndef KJ_COMMON_H_ +#define KJ_COMMON_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#ifndef KJ_NO_COMPILER_CHECK +#if __cplusplus < 201103L && !__CDT_PARSER__ && !_MSC_VER + #error "This code requires C++11. Either your compiler does not support it or it is not enabled." + #ifdef __GNUC__ + // Compiler claims compatibility with GCC, so presumably supports -std. + #error "Pass -std=c++11 on the compiler command line to enable C++11." + #endif +#endif + +#ifdef __GNUC__ + #if __clang__ + #if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2) + #warning "This library requires at least Clang 3.2." + #elif defined(__apple_build_version__) && __apple_build_version__ <= 4250028 + #warning "This library requires at least Clang 3.2. XCode 4.6's Clang, which claims to be "\ + "version 4.2 (wat?), is actually built from some random SVN revision between 3.1 "\ + "and 3.2. Unfortunately, it is insufficient for compiling this library. You can "\ + "download the real Clang 3.2 (or newer) from the Clang web site. Step-by-step "\ + "instructions can be found in Cap'n Proto's documentation: "\ + "http://kentonv.github.io/capnproto/install.html#clang_32_on_mac_osx" + #elif __cplusplus >= 201103L && !__has_include() + #warning "Your compiler supports C++11 but your C++ standard library does not. If your "\ + "system has libc++ installed (as should be the case on e.g. Mac OSX), try adding "\ + "-stdlib=libc++ to your CXXFLAGS." + #endif + #else + #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) + #warning "This library requires at least GCC 4.7." + #endif + #endif +#elif defined(_MSC_VER) + #if _MSC_VER < 1900 + #error "You need Visual Studio 2015 or better to compile this code." + #endif +#else + #warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\ + "known compilers with enough C++11 support for this library. "\ + "#define KJ_NO_COMPILER_CHECK to make this warning go away." +#endif +#endif + +#include +#include + +#if __linux__ && __cplusplus > 201200L +// Hack around stdlib bug with C++14 that exists on some Linux systems. +// Apparently in this mode the C library decides not to define gets() but the C++ library still +// tries to import it into the std namespace. This bug has been fixed at the source but is still +// widely present in the wild e.g. on Ubuntu 14.04. +#undef _GLIBCXX_HAVE_GETS +#endif + +#if defined(_MSC_VER) +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include // __popcnt +#endif + +// ======================================================================================= + +namespace kj { + +typedef unsigned int uint; +typedef unsigned char byte; + +// ======================================================================================= +// Common macros, especially for common yet compiler-specific features. + +// Detect whether RTTI and exceptions are enabled, assuming they are unless we have specific +// evidence to the contrary. Clients can always define KJ_NO_RTTI or KJ_NO_EXCEPTIONS explicitly +// to override these checks. +#ifdef __GNUC__ + #if !defined(KJ_NO_RTTI) && !__GXX_RTTI + #define KJ_NO_RTTI 1 + #endif + #if !defined(KJ_NO_EXCEPTIONS) && !__EXCEPTIONS + #define KJ_NO_EXCEPTIONS 1 + #endif +#elif defined(_MSC_VER) + #if !defined(KJ_NO_RTTI) && !defined(_CPPRTTI) + #define KJ_NO_RTTI 1 + #endif + #if !defined(KJ_NO_EXCEPTIONS) && !defined(_CPPUNWIND) + #define KJ_NO_EXCEPTIONS 1 + #endif +#endif + +#if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG) +// Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that. +// Otherwise, fall back to checking whether optimization is enabled. +#if defined(DEBUG) || defined(_DEBUG) +#define KJ_DEBUG +#elif defined(NDEBUG) +#define KJ_NDEBUG +#elif __OPTIMIZE__ +#define KJ_NDEBUG +#else +#define KJ_DEBUG +#endif +#endif + +#define KJ_DISALLOW_COPY(classname) \ + classname(const classname&) = delete; \ + classname& operator=(const classname&) = delete +// Deletes the implicit copy constructor and assignment operator. + +#ifdef __GNUC__ +#define KJ_LIKELY(condition) __builtin_expect(condition, true) +#define KJ_UNLIKELY(condition) __builtin_expect(condition, false) +// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we +// expect the condition to be true/false enough of the time that it's worth hard-coding branch +// prediction. +#else +#define KJ_LIKELY(condition) (condition) +#define KJ_UNLIKELY(condition) (condition) +#endif + +#if defined(KJ_DEBUG) || __NO_INLINE__ +#define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ +// Don't force inline in debug mode. +#else +#if defined(_MSC_VER) +#define KJ_ALWAYS_INLINE(...) __forceinline __VA_ARGS__ +#else +#define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ __attribute__((always_inline)) +#endif +// Force a function to always be inlined. Apply only to the prototype, not to the definition. +#endif + +#if defined(_MSC_VER) +#define KJ_NOINLINE __declspec(noinline) +#else +#define KJ_NOINLINE __attribute__((noinline)) +#endif + +#if defined(_MSC_VER) +#define KJ_NORETURN(prototype) __declspec(noreturn) prototype +#define KJ_UNUSED +#define KJ_WARN_UNUSED_RESULT +// TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so +// wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx +// Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix. +#else +#define KJ_NORETURN(prototype) prototype __attribute__((noreturn)) +#define KJ_UNUSED __attribute__((unused)) +#define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + +#if __clang__ +#define KJ_UNUSED_MEMBER __attribute__((unused)) +// Inhibits "unused" warning for member variables. Only Clang produces such a warning, while GCC +// complains if the attribute is set on members. +#else +#define KJ_UNUSED_MEMBER +#endif + +#if __clang__ +#define KJ_DEPRECATED(reason) \ + __attribute__((deprecated(reason))) +#define KJ_UNAVAILABLE(reason) \ + __attribute__((unavailable(reason))) +#elif __GNUC__ +#define KJ_DEPRECATED(reason) \ + __attribute__((deprecated)) +#define KJ_UNAVAILABLE(reason) +#else +#define KJ_DEPRECATED(reason) +#define KJ_UNAVAILABLE(reason) +// TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated). +#endif + +namespace _ { // private + +KJ_NORETURN(void inlineRequireFailure( + const char* file, int line, const char* expectation, const char* macroArgs, + const char* message = nullptr)); + +KJ_NORETURN(void unreachable()); + +} // namespace _ (private) + +#ifdef KJ_DEBUG +#if _MSC_VER +#define KJ_IREQUIRE(condition, ...) \ + if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ + __FILE__, __LINE__, #condition, "" #__VA_ARGS__, __VA_ARGS__) +// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to +// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that +// it will be enabled depending on whether the application is compiled in debug mode rather than +// whether libkj is. +#else +#define KJ_IREQUIRE(condition, ...) \ + if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ + __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) +// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to +// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that +// it will be enabled depending on whether the application is compiled in debug mode rather than +// whether libkj is. +#endif +#else +#define KJ_IREQUIRE(condition, ...) +#endif + +#define KJ_IASSERT KJ_IREQUIRE + +#define KJ_UNREACHABLE ::kj::_::unreachable(); +// Put this on code paths that cannot be reached to suppress compiler warnings about missing +// returns. + +#if __clang__ +#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT +#else +#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT KJ_UNREACHABLE +#endif + +// #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) +// +// Allocate an array, preferably on the stack, unless it is too big. On GCC this will use +// variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack` +// is the stack array size to use if variable-width arrays are not supported. `maxStack` is the +// maximum stack array size if variable-width arrays *are* supported. +#if __GNUC__ && !__clang__ +#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ + size_t name##_size = (size); \ + bool name##_isOnStack = name##_size <= (maxStack); \ + type name##_stack[name##_isOnStack ? size : 0]; \ + ::kj::Array name##_heap = name##_isOnStack ? \ + nullptr : kj::heapArray(name##_size); \ + ::kj::ArrayPtr name = name##_isOnStack ? \ + kj::arrayPtr(name##_stack, name##_size) : name##_heap +#else +#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ + size_t name##_size = (size); \ + bool name##_isOnStack = name##_size <= (minStack); \ + type name##_stack[minStack]; \ + ::kj::Array name##_heap = name##_isOnStack ? \ + nullptr : kj::heapArray(name##_size); \ + ::kj::ArrayPtr name = name##_isOnStack ? \ + kj::arrayPtr(name##_stack, name##_size) : name##_heap +#endif + +#define KJ_CONCAT_(x, y) x##y +#define KJ_CONCAT(x, y) KJ_CONCAT_(x, y) +#define KJ_UNIQUE_NAME(prefix) KJ_CONCAT(prefix, __LINE__) +// Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that +// the name can be used multiple times in the same macro. + +#if _MSC_VER + +#define KJ_CONSTEXPR(...) __VA_ARGS__ +// Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be +// provided, or just leave blank to remove the keyword entirely. +// +// TODO(msvc): Remove this hack once MSVC fully supports constexpr. + +#ifndef __restrict__ +#define __restrict__ __restrict +// TODO(msvc): Would it be better to define a KJ_RESTRICT macro? +#endif + +#pragma warning(disable: 4521 4522) +// This warning complains when there are two copy constructors, one for a const reference and +// one for a non-const reference. It is often quite necessary to do this in wrapper templates, +// therefore this warning is dumb and we disable it. + +#pragma warning(disable: 4458) +// Warns when a parameter name shadows a class member. Unfortunately my code does this a lot, +// since I don't use a special name format for members. + +#else // _MSC_VER +#define KJ_CONSTEXPR(...) constexpr +#endif + +// ======================================================================================= +// Template metaprogramming helpers. + +template struct NoInfer_ { typedef T Type; }; +template using NoInfer = typename NoInfer_::Type; +// Use NoInfer::Type in place of T for a template function parameter to prevent inference of +// the type based on the parameter value. + +template struct RemoveConst_ { typedef T Type; }; +template struct RemoveConst_ { typedef T Type; }; +template using RemoveConst = typename RemoveConst_::Type; + +template struct IsLvalueReference_ { static constexpr bool value = false; }; +template struct IsLvalueReference_ { static constexpr bool value = true; }; +template +inline constexpr bool isLvalueReference() { return IsLvalueReference_::value; } + +template struct Decay_ { typedef T Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template using Decay = typename Decay_::Type; + +template struct EnableIf_; +template <> struct EnableIf_ { typedef void Type; }; +template using EnableIf = typename EnableIf_::Type; +// Use like: +// +// template ()> +// void func(T&& t); + +template struct VoidSfinae_ { using Type = void; }; +template using VoidSfinae = typename VoidSfinae_::Type; +// Note: VoidSfinae is std::void_t from C++17. + +template +T instance() noexcept; +// Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify +// instance(). + +struct DisallowConstCopy { + // Inherit from this, or declare a member variable of this type, to prevent the class from being + // copyable from a const reference -- instead, it will only be copyable from non-const references. + // This is useful for enforcing transitive constness of contained pointers. + // + // For example, say you have a type T which contains a pointer. T has non-const methods which + // modify the value at that pointer, but T's const methods are designed to allow reading only. + // Unfortunately, if T has a regular copy constructor, someone can simply make a copy of T and + // then use it to modify the pointed-to value. However, if T inherits DisallowConstCopy, then + // callers will only be able to copy non-const instances of T. Ideally, there is some + // parallel type ImmutableT which is like a version of T that only has const methods, and can + // be copied from a const T. + // + // Note that due to C++ rules about implicit copy constructors and assignment operators, any + // type that contains or inherits from a type that disallows const copies will also automatically + // disallow const copies. Hey, cool, that's exactly what we want. + +#if CAPNP_DEBUG_TYPES + // Alas! Declaring a defaulted non-const copy constructor tickles a bug which causes GCC and + // Clang to disagree on ABI, using different calling conventions to pass this type, leading to + // immediate segfaults. See: + // https://bugs.llvm.org/show_bug.cgi?id=23764 + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58074 + // + // Because of this, we can't use this technique. We guard it by CAPNP_DEBUG_TYPES so that it + // still applies to the Cap'n Proto developers during internal testing. + + DisallowConstCopy() = default; + DisallowConstCopy(DisallowConstCopy&) = default; + DisallowConstCopy(DisallowConstCopy&&) = default; + DisallowConstCopy& operator=(DisallowConstCopy&) = default; + DisallowConstCopy& operator=(DisallowConstCopy&&) = default; +#endif +}; + +#if _MSC_VER + +#define KJ_CPCAP(obj) obj=::kj::cp(obj) +// TODO(msvc): MSVC refuses to invoke non-const versions of copy constructors in by-value lambda +// captures. Wrap your captured object in this macro to force the compiler to perform a copy. +// Example: +// +// struct Foo: DisallowConstCopy {}; +// Foo foo; +// auto lambda = [KJ_CPCAP(foo)] {}; + +#else + +#define KJ_CPCAP(obj) obj +// Clang and gcc both already perform copy capturing correctly with non-const copy constructors. + +#endif + +template +struct DisallowConstCopyIfNotConst: public DisallowConstCopy { + // Inherit from this when implementing a template that contains a pointer to T and which should + // enforce transitive constness. If T is a const type, this has no effect. Otherwise, it is + // an alias for DisallowConstCopy. +}; + +template +struct DisallowConstCopyIfNotConst {}; + +template struct IsConst_ { static constexpr bool value = false; }; +template struct IsConst_ { static constexpr bool value = true; }; +template constexpr bool isConst() { return IsConst_::value; } + +template struct EnableIfNotConst_ { typedef T Type; }; +template struct EnableIfNotConst_; +template using EnableIfNotConst = typename EnableIfNotConst_::Type; + +template struct EnableIfConst_; +template struct EnableIfConst_ { typedef T Type; }; +template using EnableIfConst = typename EnableIfConst_::Type; + +template struct RemoveConstOrDisable_ { struct Type; }; +template struct RemoveConstOrDisable_ { typedef T Type; }; +template using RemoveConstOrDisable = typename RemoveConstOrDisable_::Type; + +template struct IsReference_ { static constexpr bool value = false; }; +template struct IsReference_ { static constexpr bool value = true; }; +template constexpr bool isReference() { return IsReference_::value; } + +template +struct PropagateConst_ { typedef To Type; }; +template +struct PropagateConst_ { typedef const To Type; }; +template +using PropagateConst = typename PropagateConst_::Type; + +namespace _ { // private + +template +T refIfLvalue(T&&); + +} // namespace _ (private) + +#define KJ_DECLTYPE_REF(exp) decltype(::kj::_::refIfLvalue(exp)) +// Like decltype(exp), but if exp is an lvalue, produces a reference type. +// +// int i; +// decltype(i) i1(i); // i1 has type int. +// KJ_DECLTYPE_REF(i + 1) i2(i + 1); // i2 has type int. +// KJ_DECLTYPE_REF(i) i3(i); // i3 has type int&. +// KJ_DECLTYPE_REF(kj::mv(i)) i4(kj::mv(i)); // i4 has type int. + +template +struct CanConvert_ { + static int sfinae(T); + static bool sfinae(...); +}; + +template +constexpr bool canConvert() { + return sizeof(CanConvert_::sfinae(instance())) == sizeof(int); +} + +#if __GNUC__ && !__clang__ && __GNUC__ < 5 +template +constexpr bool canMemcpy() { + // Returns true if T can be copied using memcpy instead of using the copy constructor or + // assignment operator. + + // GCC 4 does not have __is_trivially_constructible and friends, and there doesn't seem to be + // any reliable alternative. __has_trivial_copy() and __has_trivial_assign() return the right + // thing at one point but later on they changed such that a deleted copy constructor was + // considered "trivial" (apparently technically correct, though useless). So, on GCC 4 we give up + // and assume we can't memcpy() at all, and must explicitly copy-construct everything. + return false; +} +#define KJ_ASSERT_CAN_MEMCPY(T) +#else +template +constexpr bool canMemcpy() { + // Returns true if T can be copied using memcpy instead of using the copy constructor or + // assignment operator. + + return __is_trivially_constructible(T, const T&) && __is_trivially_assignable(T, const T&); +} +#define KJ_ASSERT_CAN_MEMCPY(T) \ + static_assert(kj::canMemcpy(), "this code expects this type to be memcpy()-able"); +#endif + +// ======================================================================================= +// Equivalents to std::move() and std::forward(), since these are very commonly needed and the +// std header pulls in lots of other stuff. +// +// We use abbreviated names mv and fwd because these helpers (especially mv) are so commonly used +// that the cost of typing more letters outweighs the cost of being slightly harder to understand +// when first encountered. + +template constexpr T&& mv(T& t) noexcept { return static_cast(t); } +template constexpr T&& fwd(NoInfer& t) noexcept { return static_cast(t); } + +template constexpr T cp(T& t) noexcept { return t; } +template constexpr T cp(const T& t) noexcept { return t; } +// Useful to force a copy, particularly to pass into a function that expects T&&. + +template struct ChooseType_; +template struct ChooseType_ { typedef T Type; }; +template struct ChooseType_ { typedef T Type; }; +template struct ChooseType_ { typedef U Type; }; + +template +using WiderType = typename ChooseType_= sizeof(U)>::Type; + +template +inline constexpr auto min(T&& a, U&& b) -> WiderType, Decay> { + return a < b ? WiderType, Decay>(a) : WiderType, Decay>(b); +} + +template +inline constexpr auto max(T&& a, U&& b) -> WiderType, Decay> { + return a > b ? WiderType, Decay>(a) : WiderType, Decay>(b); +} + +template +inline constexpr size_t size(T (&arr)[s]) { return s; } +template +inline constexpr size_t size(T&& arr) { return arr.size(); } +// Returns the size of the parameter, whether the parameter is a regular C array or a container +// with a `.size()` method. + +class MaxValue_ { +private: + template + inline constexpr T maxSigned() const { + return (1ull << (sizeof(T) * 8 - 1)) - 1; + } + template + inline constexpr T maxUnsigned() const { + return ~static_cast(0u); + } + +public: +#define _kJ_HANDLE_TYPE(T) \ + inline constexpr operator signed T() const { return MaxValue_::maxSigned < signed T>(); } \ + inline constexpr operator unsigned T() const { return MaxValue_::maxUnsigned(); } + _kJ_HANDLE_TYPE(char) + _kJ_HANDLE_TYPE(short) + _kJ_HANDLE_TYPE(int) + _kJ_HANDLE_TYPE(long) + _kJ_HANDLE_TYPE(long long) +#undef _kJ_HANDLE_TYPE + + inline constexpr operator char() const { + // `char` is different from both `signed char` and `unsigned char`, and may be signed or + // unsigned on different platforms. Ugh. + return char(-1) < 0 ? MaxValue_::maxSigned() + : MaxValue_::maxUnsigned(); + } +}; + +class MinValue_ { +private: + template + inline constexpr T minSigned() const { + return 1ull << (sizeof(T) * 8 - 1); + } + template + inline constexpr T minUnsigned() const { + return 0u; + } + +public: +#define _kJ_HANDLE_TYPE(T) \ + inline constexpr operator signed T() const { return MinValue_::minSigned < signed T>(); } \ + inline constexpr operator unsigned T() const { return MinValue_::minUnsigned(); } + _kJ_HANDLE_TYPE(char) + _kJ_HANDLE_TYPE(short) + _kJ_HANDLE_TYPE(int) + _kJ_HANDLE_TYPE(long) + _kJ_HANDLE_TYPE(long long) +#undef _kJ_HANDLE_TYPE + + inline constexpr operator char() const { + // `char` is different from both `signed char` and `unsigned char`, and may be signed or + // unsigned on different platforms. Ugh. + return char(-1) < 0 ? MinValue_::minSigned() + : MinValue_::minUnsigned(); + } +}; + +static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_(); +// A special constant which, when cast to an integer type, takes on the maximum possible value of +// that type. This is useful to use as e.g. a parameter to a function because it will be robust +// in the face of changes to the parameter's type. +// +// `char` is not supported, but `signed char` and `unsigned char` are. + +static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_(); +// A special constant which, when cast to an integer type, takes on the minimum possible value +// of that type. This is useful to use as e.g. a parameter to a function because it will be robust +// in the face of changes to the parameter's type. +// +// `char` is not supported, but `signed char` and `unsigned char` are. + +template +inline bool operator==(T t, MaxValue_) { return t == Decay(maxValue); } +template +inline bool operator==(T t, MinValue_) { return t == Decay(minValue); } + +template +inline constexpr unsigned long long maxValueForBits() { + // Get the maximum integer representable in the given number of bits. + + // 1ull << 64 is unfortunately undefined. + return (bits == 64 ? 0 : (1ull << bits)) - 1; +} + +struct ThrowOverflow { + // Functor which throws an exception complaining about integer overflow. Usually this is used + // with the interfaces in units.h, but is defined here because Cap'n Proto wants to avoid + // including units.h when not using CAPNP_DEBUG_TYPES. + void operator()() const; +}; + +#if __GNUC__ +inline constexpr float inf() { return __builtin_huge_valf(); } +inline constexpr float nan() { return __builtin_nanf(""); } + +#elif _MSC_VER + +// Do what MSVC math.h does +#pragma warning(push) +#pragma warning(disable: 4756) // "overflow in constant arithmetic" +inline constexpr float inf() { return (float)(1e300 * 1e300); } +#pragma warning(pop) + +float nan(); +// Unfortunatley, inf() * 0.0f produces a NaN with the sign bit set, whereas our preferred +// canonical NaN should not have the sign bit set. std::numeric_limits::quiet_NaN() +// returns the correct NaN, but we don't want to #include that here. So, we give up and make +// this out-of-line on MSVC. +// +// TODO(msvc): Can we do better? + +#else +#error "Not sure how to support your compiler." +#endif + +inline constexpr bool isNaN(float f) { return f != f; } +inline constexpr bool isNaN(double f) { return f != f; } + +inline int popCount(unsigned int x) { +#if defined(_MSC_VER) + return __popcnt(x); + // Note: __popcnt returns unsigned int, but the value is clearly guaranteed to fit into an int +#else + return __builtin_popcount(x); +#endif +} + +// ======================================================================================= +// Useful fake containers + +template +class Range { +public: + inline constexpr Range(const T& begin, const T& end): begin_(begin), end_(end) {} + inline explicit constexpr Range(const T& end): begin_(0), end_(end) {} + + class Iterator { + public: + Iterator() = default; + inline Iterator(const T& value): value(value) {} + + inline const T& operator* () const { return value; } + inline const T& operator[](size_t index) const { return value + index; } + inline Iterator& operator++() { ++value; return *this; } + inline Iterator operator++(int) { return Iterator(value++); } + inline Iterator& operator--() { --value; return *this; } + inline Iterator operator--(int) { return Iterator(value--); } + inline Iterator& operator+=(ptrdiff_t amount) { value += amount; return *this; } + inline Iterator& operator-=(ptrdiff_t amount) { value -= amount; return *this; } + inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value + amount); } + inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value - amount); } + inline ptrdiff_t operator- (const Iterator& other) const { return value - other.value; } + + inline bool operator==(const Iterator& other) const { return value == other.value; } + inline bool operator!=(const Iterator& other) const { return value != other.value; } + inline bool operator<=(const Iterator& other) const { return value <= other.value; } + inline bool operator>=(const Iterator& other) const { return value >= other.value; } + inline bool operator< (const Iterator& other) const { return value < other.value; } + inline bool operator> (const Iterator& other) const { return value > other.value; } + + private: + T value; + }; + + inline Iterator begin() const { return Iterator(begin_); } + inline Iterator end() const { return Iterator(end_); } + + inline auto size() const -> decltype(instance() - instance()) { return end_ - begin_; } + +private: + T begin_; + T end_; +}; + +template +inline constexpr Range, Decay>> range(T begin, U end) { + return Range, Decay>>(begin, end); +} + +template +inline constexpr Range> range(T begin, T end) { return Range>(begin, end); } +// Returns a fake iterable container containing all values of T from `begin` (inclusive) to `end` +// (exclusive). Example: +// +// // Prints 1, 2, 3, 4, 5, 6, 7, 8, 9. +// for (int i: kj::range(1, 10)) { print(i); } + +template +inline constexpr Range> zeroTo(T end) { return Range>(end); } +// Returns a fake iterable container containing all values of T from zero (inclusive) to `end` +// (exclusive). Example: +// +// // Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. +// for (int i: kj::zeroTo(10)) { print(i); } + +template +inline constexpr Range indices(T&& container) { + // Shortcut for iterating over the indices of a container: + // + // for (size_t i: kj::indices(myArray)) { handle(myArray[i]); } + + return range(0, kj::size(container)); +} + +template +class Repeat { +public: + inline constexpr Repeat(const T& value, size_t count): value(value), count(count) {} + + class Iterator { + public: + Iterator() = default; + inline Iterator(const T& value, size_t index): value(value), index(index) {} + + inline const T& operator* () const { return value; } + inline const T& operator[](ptrdiff_t index) const { return value; } + inline Iterator& operator++() { ++index; return *this; } + inline Iterator operator++(int) { return Iterator(value, index++); } + inline Iterator& operator--() { --index; return *this; } + inline Iterator operator--(int) { return Iterator(value, index--); } + inline Iterator& operator+=(ptrdiff_t amount) { index += amount; return *this; } + inline Iterator& operator-=(ptrdiff_t amount) { index -= amount; return *this; } + inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value, index + amount); } + inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value, index - amount); } + inline ptrdiff_t operator- (const Iterator& other) const { return index - other.index; } + + inline bool operator==(const Iterator& other) const { return index == other.index; } + inline bool operator!=(const Iterator& other) const { return index != other.index; } + inline bool operator<=(const Iterator& other) const { return index <= other.index; } + inline bool operator>=(const Iterator& other) const { return index >= other.index; } + inline bool operator< (const Iterator& other) const { return index < other.index; } + inline bool operator> (const Iterator& other) const { return index > other.index; } + + private: + T value; + size_t index; + }; + + inline Iterator begin() const { return Iterator(value, 0); } + inline Iterator end() const { return Iterator(value, count); } + + inline size_t size() const { return count; } + inline const T& operator[](ptrdiff_t) const { return value; } + +private: + T value; + size_t count; +}; + +template +inline constexpr Repeat> repeat(T&& value, size_t count) { + // Returns a fake iterable which contains `count` repeats of `value`. Useful for e.g. creating + // a bunch of spaces: `kj::repeat(' ', indent * 2)` + + return Repeat>(value, count); +} + +// ======================================================================================= +// Manually invoking constructors and destructors +// +// ctor(x, ...) and dtor(x) invoke x's constructor or destructor, respectively. + +// We want placement new, but we don't want to #include . operator new cannot be defined in +// a namespace, and defining it globally conflicts with the definition in . So we have to +// define a dummy type and an operator new that uses it. + +namespace _ { // private +struct PlacementNew {}; +} // namespace _ (private) +} // namespace kj + +inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { + return __p; +} + +inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {} + +namespace kj { + +template +inline void ctor(T& location, Params&&... params) { + new (_::PlacementNew(), &location) T(kj::fwd(params)...); +} + +template +inline void dtor(T& location) { + location.~T(); +} + +// ======================================================================================= +// Maybe +// +// Use in cases where you want to indicate that a value may be null. Using Maybe instead of T* +// forces the caller to handle the null case in order to satisfy the compiler, thus reliably +// preventing null pointer dereferences at runtime. +// +// Maybe can be implicitly constructed from T and from nullptr. Additionally, it can be +// implicitly constructed from T*, in which case the pointer is checked for nullness at runtime. +// To read the value of a Maybe, do: +// +// KJ_IF_MAYBE(value, someFuncReturningMaybe()) { +// doSomething(*value); +// } else { +// maybeWasNull(); +// } +// +// KJ_IF_MAYBE's first parameter is a variable name which will be defined within the following +// block. The variable will behave like a (guaranteed non-null) pointer to the Maybe's value, +// though it may or may not actually be a pointer. +// +// Note that Maybe actually just wraps a pointer, whereas Maybe wraps a T and a boolean +// indicating nullness. + +template +class Maybe; + +namespace _ { // private + +template +class NullableValue { + // Class whose interface behaves much like T*, but actually contains an instance of T and a + // boolean flag indicating nullness. + +public: + inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) + : isSet(other.isSet) { + if (isSet) { + ctor(value, kj::mv(other.value)); + } + } + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + inline NullableValue(NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + inline ~NullableValue() +#if _MSC_VER + // TODO(msvc): MSVC has a hard time with noexcept specifier expressions that are more complex + // than `true` or `false`. We had a workaround for VS2015, but VS2017 regressed. + noexcept(false) +#else + noexcept(noexcept(instance().~T())) +#endif + { + if (isSet) { + dtor(value); + } + } + + inline T& operator*() & { return value; } + inline const T& operator*() const & { return value; } + inline T&& operator*() && { return kj::mv(value); } + inline const T&& operator*() const && { return kj::mv(value); } + inline T* operator->() { return &value; } + inline const T* operator->() const { return &value; } + inline operator T*() { return isSet ? &value : nullptr; } + inline operator const T*() const { return isSet ? &value : nullptr; } + + template + inline T& emplace(Params&&... params) { + if (isSet) { + isSet = false; + dtor(value); + } + ctor(value, kj::fwd(params)...); + isSet = true; + return value; + } + +private: // internal interface used by friends only + inline NullableValue() noexcept: isSet(false) {} + inline NullableValue(T&& t) noexcept(noexcept(T(instance()))) + : isSet(true) { + ctor(value, kj::mv(t)); + } + inline NullableValue(T& t) + : isSet(true) { + ctor(value, t); + } + inline NullableValue(const T& t) + : isSet(true) { + ctor(value, t); + } + inline NullableValue(const T* t) + : isSet(t != nullptr) { + if (isSet) ctor(value, *t); + } + template + inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) + : isSet(other.isSet) { + if (isSet) { + ctor(value, kj::mv(other.value)); + } + } + template + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + template + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, *other.ptr); + } + } + inline NullableValue(decltype(nullptr)): isSet(false) {} + + inline NullableValue& operator=(NullableValue&& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, kj::mv(other.value)); + isSet = true; + } + } + return *this; + } + + inline NullableValue& operator=(NullableValue& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, other.value); + isSet = true; + } + } + return *this; + } + + inline NullableValue& operator=(const NullableValue& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, other.value); + isSet = true; + } + } + return *this; + } + + inline bool operator==(decltype(nullptr)) const { return !isSet; } + inline bool operator!=(decltype(nullptr)) const { return isSet; } + +private: + bool isSet; + +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4624) +// Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning +// seems broken. +#endif + + union { + T value; + }; + +#if _MSC_VER +#pragma warning(pop) +#endif + + friend class kj::Maybe; + template + friend NullableValue&& readMaybe(Maybe&& maybe); +}; + +template +inline NullableValue&& readMaybe(Maybe&& maybe) { return kj::mv(maybe.ptr); } +template +inline T* readMaybe(Maybe& maybe) { return maybe.ptr; } +template +inline const T* readMaybe(const Maybe& maybe) { return maybe.ptr; } +template +inline T* readMaybe(Maybe&& maybe) { return maybe.ptr; } +template +inline T* readMaybe(const Maybe& maybe) { return maybe.ptr; } + +template +inline T* readMaybe(T* ptr) { return ptr; } +// Allow KJ_IF_MAYBE to work on regular pointers. + +} // namespace _ (private) + +#define KJ_IF_MAYBE(name, exp) if (auto name = ::kj::_::readMaybe(exp)) + +template +class Maybe { + // A T, or nullptr. + + // IF YOU CHANGE THIS CLASS: Note that there is a specialization of it in memory.h. + +public: + Maybe(): ptr(nullptr) {} + Maybe(T&& t) noexcept(noexcept(T(instance()))): ptr(kj::mv(t)) {} + Maybe(T& t): ptr(t) {} + Maybe(const T& t): ptr(t) {} + Maybe(const T* t) noexcept: ptr(t) {} + Maybe(Maybe&& other) noexcept(noexcept(T(instance()))): ptr(kj::mv(other.ptr)) {} + Maybe(const Maybe& other): ptr(other.ptr) {} + Maybe(Maybe& other): ptr(other.ptr) {} + + template + Maybe(Maybe&& other) noexcept(noexcept(T(instance()))) { + KJ_IF_MAYBE(val, kj::mv(other)) { + ptr.emplace(kj::mv(*val)); + } + } + template + Maybe(const Maybe& other) { + KJ_IF_MAYBE(val, other) { + ptr.emplace(*val); + } + } + + Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} + + template + inline T& emplace(Params&&... params) { + // Replace this Maybe's content with a new value constructed by passing the given parametrs to + // T's constructor. This can be used to initialize a Maybe without copying or even moving a T. + // Returns a reference to the newly-constructed value. + + return ptr.emplace(kj::fwd(params)...); + } + + inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } + inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; } + inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; } + + inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T& orDefault(T& defaultValue) { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + const T& orDefault(const T& defaultValue) const { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + + template + auto map(Func&& f) & -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + + template + auto map(Func&& f) const & -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + + template + auto map(Func&& f) && -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(*ptr)); + } + } + + template + auto map(Func&& f) const && -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(*ptr)); + } + } + +private: + _::NullableValue ptr; + + template + friend class Maybe; + template + friend _::NullableValue&& _::readMaybe(Maybe&& maybe); + template + friend U* _::readMaybe(Maybe& maybe); + template + friend const U* _::readMaybe(const Maybe& maybe); +}; + +template +class Maybe: public DisallowConstCopyIfNotConst { +public: + Maybe() noexcept: ptr(nullptr) {} + Maybe(T& t) noexcept: ptr(&t) {} + Maybe(T* t) noexcept: ptr(t) {} + + template + inline Maybe(Maybe& other) noexcept: ptr(other.ptr) {} + template + inline Maybe(const Maybe& other) noexcept: ptr(other.ptr) {} + inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} + + inline Maybe& operator=(T& other) noexcept { ptr = &other; return *this; } + inline Maybe& operator=(T* other) noexcept { ptr = other; return *this; } + template + inline Maybe& operator=(Maybe& other) noexcept { ptr = other.ptr; return *this; } + template + inline Maybe& operator=(const Maybe& other) noexcept { ptr = other.ptr; return *this; } + + inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T& orDefault(T& defaultValue) { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + const T& orDefault(const T& defaultValue) const { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + + template + auto map(Func&& f) -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + +private: + T* ptr; + + template + friend class Maybe; + template + friend U* _::readMaybe(Maybe&& maybe); + template + friend U* _::readMaybe(const Maybe& maybe); +}; + +// ======================================================================================= +// ArrayPtr +// +// So common that we put it in common.h rather than array.h. + +template +class ArrayPtr: public DisallowConstCopyIfNotConst { + // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data, + // and passing by value only copies the pointer, not the target. + +public: + inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {} + inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {} + inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {} + inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {} + inline KJ_CONSTEXPR() ArrayPtr(::std::initializer_list> init) + : ptr(init.begin()), size_(init.size()) {} + + template + inline constexpr ArrayPtr(T (&native)[size]): ptr(native), size_(size) {} + // Construct an ArrayPtr from a native C-style array. + + inline operator ArrayPtr() const { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asConst() const { + return ArrayPtr(ptr, size_); + } + + inline size_t size() const { return size_; } + inline const T& operator[](size_t index) const { + KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); + return ptr[index]; + } + inline T& operator[](size_t index) { + KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); + return ptr[index]; + } + + inline T* begin() { return ptr; } + inline T* end() { return ptr + size_; } + inline T& front() { return *ptr; } + inline T& back() { return *(ptr + size_ - 1); } + inline const T* begin() const { return ptr; } + inline const T* end() const { return ptr + size_; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(ptr + size_ - 1); } + + inline ArrayPtr slice(size_t start, size_t end) const { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); + return ArrayPtr(ptr + start, end - start); + } + inline ArrayPtr slice(size_t start, size_t end) { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); + return ArrayPtr(ptr + start, end - start); + } + + inline ArrayPtr> asBytes() const { + // Reinterpret the array as a byte array. This is explicitly legal under C++ aliasing + // rules. + return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; + } + inline ArrayPtr> asChars() const { + // Reinterpret the array as a char array. This is explicitly legal under C++ aliasing + // rules. + return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; + } + + inline bool operator==(decltype(nullptr)) const { return size_ == 0; } + inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } + + inline bool operator==(const ArrayPtr& other) const { + if (size_ != other.size_) return false; + for (size_t i = 0; i < size_; i++) { + if (ptr[i] != other[i]) return false; + } + return true; + } + inline bool operator!=(const ArrayPtr& other) const { return !(*this == other); } + +private: + T* ptr; + size_t size_; +}; + +template +inline constexpr ArrayPtr arrayPtr(T* ptr, size_t size) { + // Use this function to construct ArrayPtrs without writing out the type name. + return ArrayPtr(ptr, size); +} + +template +inline constexpr ArrayPtr arrayPtr(T* begin, T* end) { + // Use this function to construct ArrayPtrs without writing out the type name. + return ArrayPtr(begin, end); +} + +// ======================================================================================= +// Casts + +template +To implicitCast(From&& from) { + // `implicitCast(value)` casts `value` to type `T` only if the conversion is implicit. Useful + // for e.g. resolving ambiguous overloads without sacrificing type-safety. + return kj::fwd(from); +} + +template +Maybe dynamicDowncastIfAvailable(From& from) { + // If RTTI is disabled, always returns nullptr. Otherwise, works like dynamic_cast. Useful + // in situations where dynamic_cast could allow an optimization, but isn't strictly necessary + // for correctness. It is highly recommended that you try to arrange all your dynamic_casts + // this way, as a dynamic_cast that is necessary for correctness implies a flaw in the interface + // design. + + // Force a compile error if To is not a subtype of From. Cross-casting is rare; if it is needed + // we should have a separate cast function like dynamicCrosscastIfAvailable(). + if (false) { + kj::implicitCast(kj::implicitCast(nullptr)); + } + +#if KJ_NO_RTTI + return nullptr; +#else + return dynamic_cast(&from); +#endif +} + +template +To& downcast(From& from) { + // Down-cast a value to a sub-type, asserting that the cast is valid. In opt mode this is a + // static_cast, but in debug mode (when RTTI is enabled) a dynamic_cast will be used to verify + // that the value really has the requested type. + + // Force a compile error if To is not a subtype of From. + if (false) { + kj::implicitCast(kj::implicitCast(nullptr)); + } + +#if !KJ_NO_RTTI + KJ_IREQUIRE(dynamic_cast(&from) != nullptr, "Value cannot be downcast() to requested type."); +#endif + + return static_cast(from); +} + +// ======================================================================================= +// Defer + +namespace _ { // private + +template +class Deferred { +public: + inline Deferred(Func&& func): func(kj::fwd(func)), canceled(false) {} + inline ~Deferred() noexcept(false) { if (!canceled) func(); } + KJ_DISALLOW_COPY(Deferred); + + // This move constructor is usually optimized away by the compiler. + inline Deferred(Deferred&& other): func(kj::mv(other.func)), canceled(false) { + other.canceled = true; + } +private: + Func func; + bool canceled; +}; + +} // namespace _ (private) + +template +_::Deferred defer(Func&& func) { + // Returns an object which will invoke the given functor in its destructor. The object is not + // copyable but is movable with the semantics you'd expect. Since the return type is private, + // you need to assign to an `auto` variable. + // + // The KJ_DEFER macro provides slightly more convenient syntax for the common case where you + // want some code to run at current scope exit. + + return _::Deferred(kj::fwd(func)); +} + +#define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::defer([&](){code;}) +// Run the given code when the function exits, whether by return or exception. + +} // namespace kj + +#endif // KJ_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/compat/gtest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/compat/gtest.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,122 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_COMPAT_GTEST_H_ +#define KJ_COMPAT_GTEST_H_ +// This file defines compatibility macros converting Google Test tests into KJ tests. +// +// This is only intended to cover the most common functionality. Many tests will likely need +// additional tweaks. For instance: +// - Using operator<< to print information on failure is not supported. Instead, switch to +// KJ_ASSERT/KJ_EXPECT and pass in stuff to print as additional parameters. +// - Test fixtures are not supported. Allocate your "test fixture" on the stack instead. Do setup +// in the constructor, teardown in the destructor. + +#include "../test.h" + +namespace kj { + +namespace _ { // private + +template +T abs(T value) { return value < 0 ? -value : value; } + +inline bool floatAlmostEqual(float a, float b) { + return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-5; +} + +inline bool doubleAlmostEqual(double a, double b) { + return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-12; +} + +} // namespace _ (private) + +#define EXPECT_FALSE(x) KJ_EXPECT(!(x)) +#define EXPECT_TRUE(x) KJ_EXPECT(x) +#define EXPECT_EQ(x, y) KJ_EXPECT((x) == (y), x, y) +#define EXPECT_NE(x, y) KJ_EXPECT((x) != (y), x, y) +#define EXPECT_LE(x, y) KJ_EXPECT((x) <= (y), x, y) +#define EXPECT_GE(x, y) KJ_EXPECT((x) >= (y), x, y) +#define EXPECT_LT(x, y) KJ_EXPECT((x) < (y), x, y) +#define EXPECT_GT(x, y) KJ_EXPECT((x) > (y), x, y) +#define EXPECT_STREQ(x, y) KJ_EXPECT(::strcmp(x, y) == 0, x, y) +#define EXPECT_FLOAT_EQ(x, y) KJ_EXPECT(::kj::_::floatAlmostEqual(y, x), y, x); +#define EXPECT_DOUBLE_EQ(x, y) KJ_EXPECT(::kj::_::doubleAlmostEqual(y, x), y, x); + +#define ASSERT_FALSE(x) KJ_ASSERT(!(x)) +#define ASSERT_TRUE(x) KJ_ASSERT(x) +#define ASSERT_EQ(x, y) KJ_ASSERT((x) == (y), x, y) +#define ASSERT_NE(x, y) KJ_ASSERT((x) != (y), x, y) +#define ASSERT_LE(x, y) KJ_ASSERT((x) <= (y), x, y) +#define ASSERT_GE(x, y) KJ_ASSERT((x) >= (y), x, y) +#define ASSERT_LT(x, y) KJ_ASSERT((x) < (y), x, y) +#define ASSERT_GT(x, y) KJ_ASSERT((x) > (y), x, y) +#define ASSERT_STREQ(x, y) KJ_ASSERT(::strcmp(x, y) == 0, x, y) +#define ASSERT_FLOAT_EQ(x, y) KJ_ASSERT(::kj::_::floatAlmostEqual(y, x), y, x); +#define ASSERT_DOUBLE_EQ(x, y) KJ_ASSERT(::kj::_::doubleAlmostEqual(y, x), y, x); + +class AddFailureAdapter { +public: + AddFailureAdapter(const char* file, int line): file(file), line(line) {} + + ~AddFailureAdapter() { + if (!handled) { + _::Debug::log(file, line, LogSeverity::ERROR, "expectation failed"); + } + } + + template + void operator<<(T&& info) { + handled = true; + _::Debug::log(file, line, LogSeverity::ERROR, "\"expectation failed\", info", + "expectation failed", kj::fwd(info)); + } + +private: + bool handled = false; + const char* file; + int line; +}; + +#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__) + +#if KJ_NO_EXCEPTIONS +#define EXPECT_ANY_THROW(code) \ + KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, nullptr, [&]() { code; })) +#else +#define EXPECT_ANY_THROW(code) \ + KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr) +#endif + +#define EXPECT_NONFATAL_FAILURE(code) \ + EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr); + +#ifdef KJ_DEBUG +#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW +#else +#define EXPECT_DEBUG_ANY_THROW(EXP) +#endif + +#define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y) + +} // namespace kj + +#endif // KJ_COMPAT_GTEST_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/compat/http.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/compat/http.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,636 @@ +// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_COMPAT_HTTP_H_ +#define KJ_COMPAT_HTTP_H_ +// The KJ HTTP client/server library. +// +// This is a simple library which can be used to implement an HTTP client or server. Properties +// of this library include: +// - Uses KJ async framework. +// - Agnostic to transport layer -- you can provide your own. +// - Header parsing is zero-copy -- it results in strings that point directly into the buffer +// received off the wire. +// - Application code which reads and writes headers refers to headers by symbolic names, not by +// string literals, with lookups being array-index-based, not map-based. To make this possible, +// the application announces what headers it cares about in advance, in order to assign numeric +// values to them. +// - Methods are identified by an enum. + +#include +#include +#include +#include +#include + +namespace kj { + +#define KJ_HTTP_FOR_EACH_METHOD(MACRO) \ + MACRO(GET) \ + MACRO(HEAD) \ + MACRO(POST) \ + MACRO(PUT) \ + MACRO(DELETE) \ + MACRO(PATCH) \ + MACRO(PURGE) \ + MACRO(OPTIONS) \ + MACRO(TRACE) \ + /* standard methods */ \ + /* */ \ + /* (CONNECT is intentionally omitted since it is handled specially in HttpHandler) */ \ + \ + MACRO(COPY) \ + MACRO(LOCK) \ + MACRO(MKCOL) \ + MACRO(MOVE) \ + MACRO(PROPFIND) \ + MACRO(PROPPATCH) \ + MACRO(SEARCH) \ + MACRO(UNLOCK) \ + /* WebDAV */ \ + \ + MACRO(REPORT) \ + MACRO(MKACTIVITY) \ + MACRO(CHECKOUT) \ + MACRO(MERGE) \ + /* Subversion */ \ + \ + MACRO(MSEARCH) \ + MACRO(NOTIFY) \ + MACRO(SUBSCRIBE) \ + MACRO(UNSUBSCRIBE) + /* UPnP */ + +#define KJ_HTTP_FOR_EACH_CONNECTION_HEADER(MACRO) \ + MACRO(connection, "Connection") \ + MACRO(contentLength, "Content-Length") \ + MACRO(keepAlive, "Keep-Alive") \ + MACRO(te, "TE") \ + MACRO(trailer, "Trailer") \ + MACRO(transferEncoding, "Transfer-Encoding") \ + MACRO(upgrade, "Upgrade") + +enum class HttpMethod { + // Enum of known HTTP methods. + // + // We use an enum rather than a string to allow for faster parsing and switching and to reduce + // ambiguity. + +#define DECLARE_METHOD(id) id, +KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD) +#undef DECALRE_METHOD +}; + +kj::StringPtr KJ_STRINGIFY(HttpMethod method); +kj::Maybe tryParseHttpMethod(kj::StringPtr name); + +class HttpHeaderTable; + +class HttpHeaderId { + // Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable. + // + // The KJ HTTP API prefers that headers be identified by these IDs for a few reasons: + // - Integer lookups are much more efficient than string lookups. + // - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup + // method. + // - Writing out strings less often means fewer typos. + // + // See HttpHeaderTable for usage hints. + +public: + HttpHeaderId() = default; + + inline bool operator==(const HttpHeaderId& other) const { return id == other.id; } + inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; } + inline bool operator< (const HttpHeaderId& other) const { return id < other.id; } + inline bool operator> (const HttpHeaderId& other) const { return id > other.id; } + inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; } + inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; } + + inline size_t hashCode() const { return id; } + + kj::StringPtr toString() const; + + void requireFrom(HttpHeaderTable& table) const; + // In debug mode, throws an exception if the HttpHeaderId is not from the given table. + // + // In opt mode, no-op. + +#define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \ + MACRO(HOST, "Host") \ + MACRO(DATE, "Date") \ + MACRO(LOCATION, "Location") \ + MACRO(CONTENT_TYPE, "Content-Type") + // For convenience, these very-common headers are valid for all HttpHeaderTables. You can refer + // to them like: + // + // HttpHeaderId::HOST + // + // TODO(0.7): Fill this out with more common headers. + +#define DECLARE_HEADER(id, name) \ + static const HttpHeaderId id; + // Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION + + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER); +#undef DECLARE_HEADER + +private: + HttpHeaderTable* table; + uint id; + + inline explicit constexpr HttpHeaderId(HttpHeaderTable* table, uint id): table(table), id(id) {} + friend class HttpHeaderTable; + friend class HttpHeaders; +}; + +class HttpHeaderTable { + // Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and + // to manufacture IDs for them. + // + // Example: + // + // // Build a header table with the headers we are interested in. + // kj::HttpHeaderTable::Builder builder; + // const HttpHeaderId accept = builder.add("Accept"); + // const HttpHeaderId contentType = builder.add("Content-Type"); + // kj::HttpHeaderTable table(kj::mv(builder)); + // + // // Create an HTTP client. + // auto client = kj::newHttpClient(table, network); + // + // // Get http://example.com. + // HttpHeaders headers(table); + // headers.set(accept, "text/html"); + // auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers) + // .wait(waitScope); + // auto msg = kj::str("Response content type: ", response.headers.get(contentType)); + + struct IdsByNameMap; + +public: + HttpHeaderTable(); + // Constructs a table that only contains the builtin headers. + + class Builder { + public: + Builder(); + HttpHeaderId add(kj::StringPtr name); + Own build(); + + HttpHeaderTable& getFutureTable(); + // Get the still-unbuilt header table. You cannot actually use it until build() has been + // called. + // + // This method exists to help when building a shared header table -- the Builder may be passed + // to several components, each of which will register the headers they need and get a reference + // to the future table. + + private: + kj::Own table; + }; + + KJ_DISALLOW_COPY(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table. + ~HttpHeaderTable() noexcept(false); + + uint idCount(); + // Return the number of IDs in the table. + + kj::Maybe stringToId(kj::StringPtr name); + // Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec. + // + // Note: if `name` contains characters that aren't allowed in HTTP header names, this may return + // a bogus value rather than null, due to optimizations used in case-insensitive matching. + + kj::StringPtr idToString(HttpHeaderId id); + // Get the canonical string name for the given ID. + +private: + kj::Vector namesById; + kj::Own idsByName; +}; + +class HttpHeaders { + // Represents a set of HTTP headers. + // + // This class guards against basic HTTP header injection attacks: Trying to set a header name or + // value containing a newline, carriage return, or other invalid character will throw an + // exception. + +public: + explicit HttpHeaders(HttpHeaderTable& table); + + KJ_DISALLOW_COPY(HttpHeaders); + HttpHeaders(HttpHeaders&&) = default; + HttpHeaders& operator=(HttpHeaders&&) = default; + + void clear(); + // Clears all contents, as if the object was freshly-allocated. However, calling this rather + // than actually re-allocating the object may avoid re-allocation of internal objects. + + HttpHeaders clone() const; + // Creates a deep clone of the HttpHeaders. The returned object owns all strings it references. + + HttpHeaders cloneShallow() const; + // Creates a shallow clone of the HttpHeaders. The returned object references the same strings + // as the original, owning none of them. + + kj::Maybe get(HttpHeaderId id) const; + // Read a header. + + template + void forEach(Func&& func) const; + // Calls `func(name, value)` for each header in the set -- including headers that aren't mapped + // to IDs in the header table. Both inputs are of type kj::StringPtr. + + void set(HttpHeaderId id, kj::StringPtr value); + void set(HttpHeaderId id, kj::String&& value); + // Sets a header value, overwriting the existing value. + // + // The String&& version is equivalent to calling the other version followed by takeOwnership(). + // + // WARNING: It is the caller's responsibility to ensure that `value` remains valid until the + // HttpHeaders object is destroyed. This allows string literals to be passed without making a + // copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`. + + void add(kj::StringPtr name, kj::StringPtr value); + void add(kj::StringPtr name, kj::String&& value); + void add(kj::String&& name, kj::String&& value); + // Append a header. `name` will be looked up in the header table, but if it's not mapped, the + // header will be added to the list of unmapped headers. + // + // The String&& versions are equivalent to calling the other version followed by takeOwnership(). + // + // WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid + // until the HttpHeaders object is destroyed. This allows string literals to be passed without + // making a copy, but complicates the use of dynamic values. Hint: Consider using + // `takeOwnership()`. + + void unset(HttpHeaderId id); + // Removes a header. + // + // It's not possible to remove a header by string name because non-indexed headers would take + // O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents. + + void takeOwnership(kj::String&& string); + void takeOwnership(kj::Array&& chars); + void takeOwnership(HttpHeaders&& otherHeaders); + // Takes overship of a string so that it lives until the HttpHeaders object is destroyed. Useful + // when you've passed a dynamic value to set() or add() or parse*(). + + struct ConnectionHeaders { + // These headers govern details of the specific HTTP connection or framing of the content. + // Hence, they are managed internally within the HTTP library, and never appear in an + // HttpHeaders structure. + +#define DECLARE_HEADER(id, name) \ + kj::StringPtr id; + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(DECLARE_HEADER) +#undef DECLARE_HEADER + }; + + struct Request { + HttpMethod method; + kj::StringPtr url; + ConnectionHeaders connectionHeaders; + }; + struct Response { + uint statusCode; + kj::StringPtr statusText; + ConnectionHeaders connectionHeaders; + }; + + kj::Maybe tryParseRequest(kj::ArrayPtr content); + kj::Maybe tryParseResponse(kj::ArrayPtr content); + // Parse an HTTP header blob and add all the headers to this object. + // + // `content` should be all text from the start of the request to the first occurrance of two + // newlines in a row -- including the first of these two newlines, but excluding the second. + // + // The parse is performed with zero copies: The callee clobbers `content` with '\0' characters + // to split it into a bunch of shorter strings. The caller must keep `content` valid until the + // `HttpHeaders` is destroyed, or pass it to `takeOwnership()`. + + kj::String serializeRequest(HttpMethod method, kj::StringPtr url, + const ConnectionHeaders& connectionHeaders) const; + kj::String serializeResponse(uint statusCode, kj::StringPtr statusText, + const ConnectionHeaders& connectionHeaders) const; + // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines + // and includes the double-newline to indicate the end of the headers. + + kj::String toString() const; + +private: + HttpHeaderTable* table; + + kj::Array indexedHeaders; + // Size is always table->idCount(). + + struct Header { + kj::StringPtr name; + kj::StringPtr value; + }; + kj::Vector

unindexedHeaders; + + kj::Vector> ownedStrings; + + kj::Maybe addNoCheck(kj::StringPtr name, kj::StringPtr value); + + kj::StringPtr cloneToOwn(kj::StringPtr str); + + kj::String serialize(kj::ArrayPtr word1, + kj::ArrayPtr word2, + kj::ArrayPtr word3, + const ConnectionHeaders& connectionHeaders) const; + + bool parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders); + + // TODO(perf): Arguably we should store a map, but header sets are never very long + // TODO(perf): We could optimize for common headers by storing them directly as fields. We could + // also add direct accessors for those headers. +}; + +class WebSocket { +public: + WebSocket(kj::Own stream); + // Create a WebSocket wrapping the given I/O stream. + + kj::Promise send(kj::ArrayPtr message); + kj::Promise send(kj::ArrayPtr message); +}; + +class HttpClient { + // Interface to the client end of an HTTP connection. + // + // There are two kinds of clients: + // * Host clients are used when talking to a specific host. The `url` specified in a request + // is actually just a path. (A `Host` header is still required in all requests.) + // * Proxy clients are used when the target could be any arbitrary host on the internet. + // The `url` specified in a request is a full URL including protocol and hostname. + +public: + struct Response { + uint statusCode; + kj::StringPtr statusText; + const HttpHeaders* headers; + kj::Own body; + // `statusText` and `headers` remain valid until `body` is dropped. + }; + + struct Request { + kj::Own body; + // Write the request entity body to this stream, then drop it when done. + // + // May be null for GET and HEAD requests (which have no body) and requests that have + // Content-Length: 0. + + kj::Promise response; + // Promise for the eventual respnose. + }; + + virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::Maybe expectedBodySize = nullptr) = 0; + // Perform an HTTP request. + // + // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, + // depending on whether the client is a proxy client or a host client. + // + // `url` and `headers` need only remain valid until `request()` returns (they can be + // stack-allocated). + // + // `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to + // the body. This will trigger use of the `Content-Length` connection header. Otherwise, + // `Transfer-Encoding: chunked` will be used. + + struct WebSocketResponse { + uint statusCode; + kj::StringPtr statusText; + const HttpHeaders* headers; + kj::OneOf, kj::Own> upstreamOrBody; + // `statusText` and `headers` remain valid until `upstreamOrBody` is dropped. + }; + virtual kj::Promise openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, kj::Own downstream); + // Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket. + // + // `url` and `headers` are invalidated when the returned promise resolves. + + virtual kj::Promise> connect(kj::String host); + // Handles CONNECT requests. Only relevant for proxy clients. Default implementation throws + // UNIMPLEMENTED. +}; + +class HttpService { + // Interface which HTTP services should implement. + // + // This interface is functionally equivalent to HttpClient, but is intended for applications to + // implement rather than call. The ergonomics and performance of the method signatures are + // optimized for the serving end. + // + // As with clients, there are two kinds of services: + // * Host services are used when talking to a specific host. The `url` specified in a request + // is actually just a path. (A `Host` header is still required in all requests, and the service + // may in fact serve multiple origins via this header.) + // * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to + // implement an HTTP proxy. The `url` specified in a request is a full URL including protocol + // and hostname. + +public: + class Response { + public: + virtual kj::Own send( + uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, + kj::Maybe expectedBodySize = nullptr) = 0; + // Begin the response. + // + // `statusText` and `headers` need only remain valid until send() returns (they can be + // stack-allocated). + }; + + virtual kj::Promise request( + HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::AsyncInputStream& requestBody, Response& response) = 0; + // Perform an HTTP request. + // + // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, + // depending on whether the service is a proxy service or a host service. + // + // `url` and `headers` are invalidated on the first read from `requestBody` or when the returned + // promise resolves, whichever comes first. + + class WebSocketResponse: public Response { + public: + kj::Own startWebSocket( + uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, + WebSocket& upstream); + // Begin the response. + // + // `statusText` and `headers` need only remain valid until startWebSocket() returns (they can + // be stack-allocated). + }; + + virtual kj::Promise openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response); + // Tries to open a WebSocket. Default implementation calls request() and never returns a + // WebSocket. + // + // `url` and `headers` are invalidated when the returned promise resolves. + + virtual kj::Promise> connect(kj::String host); + // Handles CONNECT requests. Only relevant for proxy services. Default implementation throws + // UNIMPLEMENTED. +}; + +kj::Own newHttpClient(HttpHeaderTable& responseHeaderTable, kj::Network& network, + kj::Maybe tlsNetwork = nullptr); +// Creates a proxy HttpClient that connects to hosts over the given network. +// +// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table. +// +// `tlsNetwork` is required to support HTTPS destination URLs. Otherwise, only HTTP URLs can be +// fetched. + +kj::Own newHttpClient(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream); +// Creates an HttpClient that speaks over the given pre-established connection. The client may +// be used as a proxy client or a host client depending on whether the peer is operating as +// a proxy. +// +// Note that since this client has only one stream to work with, it will try to pipeline all +// requests on this stream. If one request or response has an I/O failure, all subsequent requests +// fail as well. If the destination server chooses to close the connection after a response, +// subsequent requests will fail. If a response takes a long time, it blocks subsequent responses. +// If a WebSocket is opened successfully, all subsequent requests fail. + +kj::Own newHttpClient(HttpService& service); +kj::Own newHttpService(HttpClient& client); +// Adapts an HttpClient to an HttpService and vice versa. + +struct HttpServerSettings { + kj::Duration headerTimeout = 15 * kj::SECONDS; + // After initial connection open, or after receiving the first byte of a pipelined request, + // the client must send the complete request within this time. + + kj::Duration pipelineTimeout = 5 * kj::SECONDS; + // After one request/response completes, we'll wait up to this long for a pipelined request to + // arrive. +}; + +class HttpServer: private kj::TaskSet::ErrorHandler { + // Class which listens for requests on ports or connections and sends them to an HttpService. + +public: + typedef HttpServerSettings Settings; + + HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings = Settings()); + // Set up an HttpServer that directs incoming connections to the given service. The service + // may be a host service or a proxy service depending on whether you are intending to implement + // an HTTP server or an HTTP proxy. + + kj::Promise drain(); + // Stop accepting new connections or new requests on existing connections. Finish any requests + // that are already executing, then close the connections. Returns once no more requests are + // in-flight. + + kj::Promise listenHttp(kj::ConnectionReceiver& port); + // Accepts HTTP connections on the given port and directs them to the handler. + // + // The returned promise never completes normally. It may throw if port.accept() throws. Dropping + // the returned promise will cause the server to stop listening on the port, but already-open + // connections will continue to be served. Destroy the whole HttpServer to cancel all I/O. + + kj::Promise listenHttp(kj::Own connection); + // Reads HTTP requests from the given connection and directs them to the handler. A successful + // completion of the promise indicates that all requests received on the connection resulted in + // a complete response, and the client closed the connection gracefully or drain() was called. + // The promise throws if an unparseable request is received or if some I/O error occurs. Dropping + // the returned promise will cancel all I/O on the connection and cancel any in-flight requests. + +private: + class Connection; + + kj::Timer& timer; + HttpHeaderTable& requestHeaderTable; + HttpService& service; + Settings settings; + + bool draining = false; + kj::ForkedPromise onDrain; + kj::Own> drainFulfiller; + + uint connectionCount = 0; + kj::Maybe>> zeroConnectionsFulfiller; + + kj::TaskSet tasks; + + HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings, kj::PromiseFulfillerPair paf); + + kj::Promise listenLoop(kj::ConnectionReceiver& port); + + void taskFailed(kj::Exception&& exception) override; +}; + +// ======================================================================================= +// inline implementation + +inline void HttpHeaderId::requireFrom(HttpHeaderTable& table) const { + KJ_IREQUIRE(this->table == nullptr || this->table == &table, + "the provided HttpHeaderId is from the wrong HttpHeaderTable"); +} + +inline kj::Own HttpHeaderTable::Builder::build() { return kj::mv(table); } +inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; } + +inline uint HttpHeaderTable::idCount() { return namesById.size(); } + +inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) { + id.requireFrom(*this); + return namesById[id.id]; +} + +inline kj::Maybe HttpHeaders::get(HttpHeaderId id) const { + id.requireFrom(*table); + auto result = indexedHeaders[id.id]; + return result == nullptr ? kj::Maybe(nullptr) : result; +} + +inline void HttpHeaders::unset(HttpHeaderId id) { + id.requireFrom(*table); + indexedHeaders[id.id] = nullptr; +} + +template +inline void HttpHeaders::forEach(Func&& func) const { + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]); + } + } + + for (auto& header: unindexedHeaders) { + func(header.name, header.value); + } +} + +} // namespace kj + +#endif // KJ_COMPAT_HTTP_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/debug.h --- a/osx/include/kj/debug.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/debug.h Mon May 22 10:01:37 2017 +0100 @@ -1,455 +1,555 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file declares convenient macros for debug logging and error handling. The macros make -// it excessively easy to extract useful context information from code. Example: -// -// KJ_ASSERT(a == b, a, b, "a and b must be the same."); -// -// On failure, this will throw an exception whose description looks like: -// -// myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same. -// -// As you can see, all arguments after the first provide additional context. -// -// The macros available are: -// -// * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can -// intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`, -// `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the -// user should be able to pass a flag like `--verbose` to enable them. Other log levels are -// enabled by default. Log messages -- like exceptions -- can be intercepted by registering an -// ExceptionCallback. -// -// * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while -// debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing -// code. It is suggested that you set up a pre-commit hook that checks for this. -// -// * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if -// exceptions are disabled. This macro should be used to check for bugs in the surrounding code -// and its dependencies, but NOT to check for invalid input. The macro may be followed by a -// brace-delimited code block; if so, the block will be executed in the case where the assertion -// fails, before throwing the exception. If control jumps out of the block (e.g. with "break", -// "return", or "goto"), then the error is considered "recoverable" -- in this case, if -// exceptions are disabled, execution will continue normally rather than aborting (but if -// exceptions are enabled, an exception will still be thrown on exiting the block). A "break" -// statement in particular will jump to the code immediately after the block (it does not break -// any surrounding loop or switch). Example: -// -// KJ_ASSERT(value >= 0, "Value cannot be negative.", value) { -// // Assertion failed. Set value to zero to "recover". -// value = 0; -// // Don't abort if exceptions are disabled. Continue normally. -// // (Still throw an exception if they are enabled, though.) -// break; -// } -// // When exceptions are disabled, we'll get here even if the assertion fails. -// // Otherwise, we get here only if the assertion passes. -// -// * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to -// validate parameters passed from a caller. A failure indicates that the caller is buggy. -// -// * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result -// is considered an error, with error code reported via `errno`. EINTR is handled by retrying. -// Other errors are handled by throwing an exception. If you need to examine the return code, -// assign it to a variable like so: -// -// int fd; -// KJ_SYSCALL(fd = open(filename, O_RDONLY), filename); -// -// `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`. -// -// * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on -// EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it -// indicates an error; in this case, it can assume the error was EAGAIN because any other error -// would have caused an exception to be thrown. -// -// * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown -// from within the current scope. That is, until control exits the block in which KJ_CONTEXT() -// is used, if any exception is generated, it will contain the given information in its context -// chain. This is helpful because it can otherwise be very difficult to come up with error -// messages that make sense within low-level helper code. Note that the parameters to -// KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables -// used must remain valid until the end of the scope. -// -// Notes: -// * Do not write expressions with side-effects in the message content part of the macro, as the -// message will not necessarily be evaluated. -// * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report -// failures that already happened. For the macros that check a boolean condition, `FAIL_FOO` -// omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and -// `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters. -// The string should be the name of the failed system call. -// * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only -// executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically -// by common.h when compiling without optimization (unless NDEBUG is defined), but you can also -// define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG -// as it may enable expensive checks that are unlikely to fail. - -#ifndef KJ_DEBUG_H_ -#define KJ_DEBUG_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "string.h" -#include "exception.h" - -#ifdef ERROR -// This is problematic because windows.h #defines ERROR, which we use in an enum here. -#error "Make sure to to undefine ERROR (or just #include ) before this file" -#endif - -namespace kj { - -#if _MSC_VER -// MSVC does __VA_ARGS__ differently from GCC: -// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants -// you to request this behavior with "##__VA_ARGS__". -// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a -// *single* argument rather than an argument list. This can be worked around by wrapping the -// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before -// the macro is evaluated. I don't understand the C preprocessor. -// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is -// empty, rather than expanding to an empty string literal. We can work around by concatenating -// with an empty string literal. - -#define KJ_EXPAND(X) X - -#define KJ_LOG(severity, ...) \ - if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ - ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ - "" #__VA_ARGS__, __VA_ARGS__) - -#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__)) - -#define KJ_REQUIRE(cond, ...) \ - if (KJ_LIKELY(cond)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - #cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_FAIL_REQUIRE(...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_SYSCALL(call, ...) \ - if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_NONBLOCKING_SYSCALL(call, ...) \ - if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_UNIMPLEMENTED(...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ - nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) - -#define KJ_CONTEXT(...) \ - auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ - return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ - ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \ - }; \ - ::kj::_::Debug::ContextImpl \ - KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) - -#define KJ_REQUIRE_NONNULL(value, ...) \ - (*[&] { \ - auto _kj_result = ::kj::_::readMaybe(value); \ - if (KJ_UNLIKELY(!_kj_result)) { \ - ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - #value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \ - } \ - return _kj_result; \ - }()) - -#define KJ_EXCEPTION(type, ...) \ - ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ - ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)) - -#else - -#define KJ_LOG(severity, ...) \ - if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ - ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ - #__VA_ARGS__, ##__VA_ARGS__) - -#define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__) - -#define KJ_REQUIRE(cond, ...) \ - if (KJ_LIKELY(cond)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - #cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_FAIL_REQUIRE(...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_SYSCALL(call, ...) \ - if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_NONBLOCKING_SYSCALL(call, ...) \ - if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ - errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_UNIMPLEMENTED(...) \ - for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ - nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) - -#define KJ_CONTEXT(...) \ - auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ - return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ - ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \ - }; \ - ::kj::_::Debug::ContextImpl \ - KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) - -#define KJ_REQUIRE_NONNULL(value, ...) \ - (*({ \ - auto _kj_result = ::kj::_::readMaybe(value); \ - if (KJ_UNLIKELY(!_kj_result)) { \ - ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ - #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \ - } \ - kj::mv(_kj_result); \ - })) - -#define KJ_EXCEPTION(type, ...) \ - ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ - ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)) - -#endif - -#define KJ_ASSERT KJ_REQUIRE -#define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE -#define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL -// Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code. -// That is, if the assert ever fails, it indicates that the immediate surrounding code is broken. - -#ifdef KJ_DEBUG -#define KJ_DLOG KJ_LOG -#define KJ_DASSERT KJ_ASSERT -#define KJ_DREQUIRE KJ_REQUIRE -#else -#define KJ_DLOG(...) do {} while (false) -#define KJ_DASSERT(...) do {} while (false) -#define KJ_DREQUIRE(...) do {} while (false) -#endif - -namespace _ { // private - -class Debug { -public: - Debug() = delete; - - typedef LogSeverity Severity; // backwards-compatibility - - static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; } - // Returns whether messages of the given severity should be logged. - - static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; } - // Set the minimum message severity which will be logged. - // - // TODO(someday): Expose publicly. - - template - static void log(const char* file, int line, LogSeverity severity, const char* macroArgs, - Params&&... params); - - class Fault { - public: - template - Fault(const char* file, int line, Exception::Type type, - const char* condition, const char* macroArgs, Params&&... params); - template - Fault(const char* file, int line, int osErrorNumber, - const char* condition, const char* macroArgs, Params&&... params); - Fault(const char* file, int line, Exception::Type type, - const char* condition, const char* macroArgs); - Fault(const char* file, int line, int osErrorNumber, - const char* condition, const char* macroArgs); - ~Fault() noexcept(false); - - KJ_NOINLINE KJ_NORETURN(void fatal()); - // Throw the exception. - - private: - void init(const char* file, int line, Exception::Type type, - const char* condition, const char* macroArgs, ArrayPtr argValues); - void init(const char* file, int line, int osErrorNumber, - const char* condition, const char* macroArgs, ArrayPtr argValues); - - Exception* exception; - }; - - class SyscallResult { - public: - inline SyscallResult(int errorNumber): errorNumber(errorNumber) {} - inline operator void*() { return errorNumber == 0 ? this : nullptr; } - inline int getErrorNumber() { return errorNumber; } - - private: - int errorNumber; - }; - - template - static SyscallResult syscall(Call&& call, bool nonblocking); - - class Context: public ExceptionCallback { - public: - Context(); - KJ_DISALLOW_COPY(Context); - virtual ~Context() noexcept(false); - - struct Value { - const char* file; - int line; - String description; - - inline Value(const char* file, int line, String&& description) - : file(file), line(line), description(mv(description)) {} - }; - - virtual Value evaluate() = 0; - - virtual void onRecoverableException(Exception&& exception) override; - virtual void onFatalException(Exception&& exception) override; - virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, - String&& text) override; - - private: - bool logged; - Maybe value; - - Value ensureInitialized(); - }; - - template - class ContextImpl: public Context { - public: - inline ContextImpl(Func& func): func(func) {} - KJ_DISALLOW_COPY(ContextImpl); - - Value evaluate() override { - return func(); - } - private: - Func& func; - }; - - template - static String makeDescription(const char* macroArgs, Params&&... params); - -private: - static LogSeverity minSeverity; - - static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs, - ArrayPtr argValues); - static String makeDescriptionInternal(const char* macroArgs, ArrayPtr argValues); - - static int getOsErrorNumber(bool nonblocking); - // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR. -}; - -template -void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs, - Params&&... params) { - String argValues[sizeof...(Params)] = {str(params)...}; - logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params))); -} - -template <> -inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) { - logInternal(file, line, severity, macroArgs, nullptr); -} - -template -Debug::Fault::Fault(const char* file, int line, Exception::Type type, - const char* condition, const char* macroArgs, Params&&... params) - : exception(nullptr) { - String argValues[sizeof...(Params)] = {str(params)...}; - init(file, line, type, condition, macroArgs, - arrayPtr(argValues, sizeof...(Params))); -} - -template -Debug::Fault::Fault(const char* file, int line, int osErrorNumber, - const char* condition, const char* macroArgs, Params&&... params) - : exception(nullptr) { - String argValues[sizeof...(Params)] = {str(params)...}; - init(file, line, osErrorNumber, condition, macroArgs, - arrayPtr(argValues, sizeof...(Params))); -} - -inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber, - const char* condition, const char* macroArgs) - : exception(nullptr) { - init(file, line, osErrorNumber, condition, macroArgs, nullptr); -} - -inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type, - const char* condition, const char* macroArgs) - : exception(nullptr) { - init(file, line, type, condition, macroArgs, nullptr); -} - -template -Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) { - while (call() < 0) { - int errorNum = getOsErrorNumber(nonblocking); - // getOsErrorNumber() returns -1 to indicate EINTR. - // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a - // non-error. - if (errorNum != -1) { - return SyscallResult(errorNum); - } - } - return SyscallResult(0); -} - -template -String Debug::makeDescription(const char* macroArgs, Params&&... params) { - String argValues[sizeof...(Params)] = {str(params)...}; - return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params))); -} - -template <> -inline String Debug::makeDescription<>(const char* macroArgs) { - return makeDescriptionInternal(macroArgs, nullptr); -} - -} // namespace _ (private) -} // namespace kj - -#endif // KJ_DEBUG_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file declares convenient macros for debug logging and error handling. The macros make +// it excessively easy to extract useful context information from code. Example: +// +// KJ_ASSERT(a == b, a, b, "a and b must be the same."); +// +// On failure, this will throw an exception whose description looks like: +// +// myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same. +// +// As you can see, all arguments after the first provide additional context. +// +// The macros available are: +// +// * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can +// intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`, +// `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the +// user should be able to pass a flag like `--verbose` to enable them. Other log levels are +// enabled by default. Log messages -- like exceptions -- can be intercepted by registering an +// ExceptionCallback. +// +// * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while +// debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing +// code. It is suggested that you set up a pre-commit hook that checks for this. +// +// * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if +// exceptions are disabled. This macro should be used to check for bugs in the surrounding code +// and its dependencies, but NOT to check for invalid input. The macro may be followed by a +// brace-delimited code block; if so, the block will be executed in the case where the assertion +// fails, before throwing the exception. If control jumps out of the block (e.g. with "break", +// "return", or "goto"), then the error is considered "recoverable" -- in this case, if +// exceptions are disabled, execution will continue normally rather than aborting (but if +// exceptions are enabled, an exception will still be thrown on exiting the block). A "break" +// statement in particular will jump to the code immediately after the block (it does not break +// any surrounding loop or switch). Example: +// +// KJ_ASSERT(value >= 0, "Value cannot be negative.", value) { +// // Assertion failed. Set value to zero to "recover". +// value = 0; +// // Don't abort if exceptions are disabled. Continue normally. +// // (Still throw an exception if they are enabled, though.) +// break; +// } +// // When exceptions are disabled, we'll get here even if the assertion fails. +// // Otherwise, we get here only if the assertion passes. +// +// * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to +// validate parameters passed from a caller. A failure indicates that the caller is buggy. +// +// * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result +// is considered an error, with error code reported via `errno`. EINTR is handled by retrying. +// Other errors are handled by throwing an exception. If you need to examine the return code, +// assign it to a variable like so: +// +// int fd; +// KJ_SYSCALL(fd = open(filename, O_RDONLY), filename); +// +// `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`. +// +// * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on +// EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it +// indicates an error; in this case, it can assume the error was EAGAIN because any other error +// would have caused an exception to be thrown. +// +// * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown +// from within the current scope. That is, until control exits the block in which KJ_CONTEXT() +// is used, if any exception is generated, it will contain the given information in its context +// chain. This is helpful because it can otherwise be very difficult to come up with error +// messages that make sense within low-level helper code. Note that the parameters to +// KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables +// used must remain valid until the end of the scope. +// +// Notes: +// * Do not write expressions with side-effects in the message content part of the macro, as the +// message will not necessarily be evaluated. +// * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report +// failures that already happened. For the macros that check a boolean condition, `FAIL_FOO` +// omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and +// `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters. +// The string should be the name of the failed system call. +// * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only +// executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically +// by common.h when compiling without optimization (unless NDEBUG is defined), but you can also +// define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG +// as it may enable expensive checks that are unlikely to fail. + +#ifndef KJ_DEBUG_H_ +#define KJ_DEBUG_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "string.h" +#include "exception.h" + +#ifdef ERROR +// This is problematic because windows.h #defines ERROR, which we use in an enum here. +#error "Make sure to to undefine ERROR (or just #include ) before this file" +#endif + +namespace kj { + +#if _MSC_VER +// MSVC does __VA_ARGS__ differently from GCC: +// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants +// you to request this behavior with "##__VA_ARGS__". +// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a +// *single* argument rather than an argument list. This can be worked around by wrapping the +// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before +// the macro is evaluated. I don't understand the C preprocessor. +// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is +// empty, rather than expanding to an empty string literal. We can work around by concatenating +// with an empty string literal. + +#define KJ_EXPAND(X) X + +#define KJ_LOG(severity, ...) \ + if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ + ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ + "" #__VA_ARGS__, __VA_ARGS__) + +#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__)) + +#define KJ_REQUIRE(cond, ...) \ + if (KJ_LIKELY(cond)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_REQUIRE(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_NONBLOCKING_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#if _WIN32 + +#define KJ_WIN32(call, ...) \ + if (::kj::_::Debug::isWin32Success(call)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_WINSOCK(call, ...) \ + if ((call) != SOCKET_ERROR) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_WIN32(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#endif + +#define KJ_UNIMPLEMENTED(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ + nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +// TODO(msvc): MSVC mis-deduces `ContextImpl` as `ContextImpl` in some edge +// cases, such as inside nested lambdas inside member functions. Wrapping the type in +// `decltype(instance<...>())` helps it deduce the context function's type correctly. +#define KJ_CONTEXT(...) \ + auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ + return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \ + }; \ + decltype(::kj::instance<::kj::_::Debug::ContextImpl>()) \ + KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) + +#define KJ_REQUIRE_NONNULL(value, ...) \ + (*[&] { \ + auto _kj_result = ::kj::_::readMaybe(value); \ + if (KJ_UNLIKELY(!_kj_result)) { \ + ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \ + } \ + return _kj_result; \ + }()) + +#define KJ_EXCEPTION(type, ...) \ + ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)) + +#else + +#define KJ_LOG(severity, ...) \ + if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ + ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ + #__VA_ARGS__, ##__VA_ARGS__) + +#define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__) + +#define KJ_REQUIRE(cond, ...) \ + if (KJ_LIKELY(cond)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_REQUIRE(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_NONBLOCKING_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#if _WIN32 + +#define KJ_WIN32(call, ...) \ + if (::kj::_::Debug::isWin32Success(call)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_WINSOCK(call, ...) \ + if ((call) != SOCKET_ERROR) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_WIN32(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#endif + +#define KJ_UNIMPLEMENTED(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ + nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_CONTEXT(...) \ + auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ + return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \ + }; \ + ::kj::_::Debug::ContextImpl \ + KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) + +#define KJ_REQUIRE_NONNULL(value, ...) \ + (*({ \ + auto _kj_result = ::kj::_::readMaybe(value); \ + if (KJ_UNLIKELY(!_kj_result)) { \ + ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \ + } \ + kj::mv(_kj_result); \ + })) + +#define KJ_EXCEPTION(type, ...) \ + ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)) + +#endif + +#define KJ_SYSCALL_HANDLE_ERRORS(call) \ + if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \ + switch (int error = _kjSyscallError) +// Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the +// error. Additionally, the int value `error` is defined within the block. So you can do: +// +// KJ_SYSCALL_HANDLE_ERRORS(foo()) { +// case ENOENT: +// handleNoSuchFile(); +// break; +// case EEXIST: +// handleExists(); +// break; +// default: +// KJ_FAIL_SYSCALL("foo()", error); +// } else { +// handleSuccessCase(); +// } + +#define KJ_ASSERT KJ_REQUIRE +#define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE +#define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL +// Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code. +// That is, if the assert ever fails, it indicates that the immediate surrounding code is broken. + +#ifdef KJ_DEBUG +#define KJ_DLOG KJ_LOG +#define KJ_DASSERT KJ_ASSERT +#define KJ_DREQUIRE KJ_REQUIRE +#else +#define KJ_DLOG(...) do {} while (false) +#define KJ_DASSERT(...) do {} while (false) +#define KJ_DREQUIRE(...) do {} while (false) +#endif + +namespace _ { // private + +class Debug { +public: + Debug() = delete; + + typedef LogSeverity Severity; // backwards-compatibility + +#if _WIN32 + struct Win32Error { + // Hack for overloading purposes. + uint number; + inline explicit Win32Error(uint number): number(number) {} + }; +#endif + + static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; } + // Returns whether messages of the given severity should be logged. + + static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; } + // Set the minimum message severity which will be logged. + // + // TODO(someday): Expose publicly. + + template + static void log(const char* file, int line, LogSeverity severity, const char* macroArgs, + Params&&... params); + + class Fault { + public: + template + Fault(const char* file, int line, Code code, + const char* condition, const char* macroArgs, Params&&... params); + Fault(const char* file, int line, Exception::Type type, + const char* condition, const char* macroArgs); + Fault(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs); +#if _WIN32 + Fault(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs); +#endif + ~Fault() noexcept(false); + + KJ_NOINLINE KJ_NORETURN(void fatal()); + // Throw the exception. + + private: + void init(const char* file, int line, Exception::Type type, + const char* condition, const char* macroArgs, ArrayPtr argValues); + void init(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues); +#if _WIN32 + void init(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues); +#endif + + Exception* exception; + }; + + class SyscallResult { + public: + inline SyscallResult(int errorNumber): errorNumber(errorNumber) {} + inline operator void*() { return errorNumber == 0 ? this : nullptr; } + inline int getErrorNumber() { return errorNumber; } + + private: + int errorNumber; + }; + + template + static SyscallResult syscall(Call&& call, bool nonblocking); + template + static int syscallError(Call&& call, bool nonblocking); + +#if _WIN32 + static bool isWin32Success(int boolean); + static bool isWin32Success(void* handle); + static Win32Error getWin32Error(); +#endif + + class Context: public ExceptionCallback { + public: + Context(); + KJ_DISALLOW_COPY(Context); + virtual ~Context() noexcept(false); + + struct Value { + const char* file; + int line; + String description; + + inline Value(const char* file, int line, String&& description) + : file(file), line(line), description(mv(description)) {} + }; + + virtual Value evaluate() = 0; + + virtual void onRecoverableException(Exception&& exception) override; + virtual void onFatalException(Exception&& exception) override; + virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) override; + + private: + bool logged; + Maybe value; + + Value ensureInitialized(); + }; + + template + class ContextImpl: public Context { + public: + inline ContextImpl(Func& func): func(func) {} + KJ_DISALLOW_COPY(ContextImpl); + + Value evaluate() override { + return func(); + } + private: + Func& func; + }; + + template + static String makeDescription(const char* macroArgs, Params&&... params); + +private: + static LogSeverity minSeverity; + + static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs, + ArrayPtr argValues); + static String makeDescriptionInternal(const char* macroArgs, ArrayPtr argValues); + + static int getOsErrorNumber(bool nonblocking); + // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR. +}; + +template +void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs, + Params&&... params) { + String argValues[sizeof...(Params)] = {str(params)...}; + logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params))); +} + +template <> +inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) { + logInternal(file, line, severity, macroArgs, nullptr); +} + +template +Debug::Fault::Fault(const char* file, int line, Code code, + const char* condition, const char* macroArgs, Params&&... params) + : exception(nullptr) { + String argValues[sizeof...(Params)] = {str(params)...}; + init(file, line, code, condition, macroArgs, + arrayPtr(argValues, sizeof...(Params))); +} + +inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, osErrorNumber, condition, macroArgs, nullptr); +} + +inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, type, condition, macroArgs, nullptr); +} + +#if _WIN32 +inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, osErrorNumber, condition, macroArgs, nullptr); +} + +inline bool Debug::isWin32Success(int boolean) { + return boolean; +} +inline bool Debug::isWin32Success(void* handle) { + // Assume null and INVALID_HANDLE_VALUE mean failure. + return handle != nullptr && handle != (void*)-1; +} +#endif + +template +Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) { + while (call() < 0) { + int errorNum = getOsErrorNumber(nonblocking); + // getOsErrorNumber() returns -1 to indicate EINTR. + // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a + // non-error. + if (errorNum != -1) { + return SyscallResult(errorNum); + } + } + return SyscallResult(0); +} + +template +int Debug::syscallError(Call&& call, bool nonblocking) { + while (call() < 0) { + int errorNum = getOsErrorNumber(nonblocking); + // getOsErrorNumber() returns -1 to indicate EINTR. + // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a + // non-error. + if (errorNum != -1) { + return errorNum; + } + } + return 0; +} + +template +String Debug::makeDescription(const char* macroArgs, Params&&... params) { + String argValues[sizeof...(Params)] = {str(params)...}; + return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params))); +} + +template <> +inline String Debug::makeDescription<>(const char* macroArgs) { + return makeDescriptionInternal(macroArgs, nullptr); +} + +} // namespace _ (private) +} // namespace kj + +#endif // KJ_DEBUG_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/exception.h --- a/osx/include/kj/exception.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/exception.h Mon May 22 10:01:37 2017 +0100 @@ -1,337 +1,363 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_EXCEPTION_H_ -#define KJ_EXCEPTION_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "memory.h" -#include "array.h" -#include "string.h" - -namespace kj { - -class ExceptionImpl; - -class Exception { - // Exception thrown in case of fatal errors. - // - // Actually, a subclass of this which also implements std::exception will be thrown, but we hide - // that fact from the interface to avoid #including . - -public: - enum class Type { - // What kind of failure? - - FAILED = 0, - // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this - // error type. - - OVERLOADED = 1, - // The call failed because of a temporary lack of resources. This could be space resources - // (out of memory, out of disk space) or time resources (request queue overflow, operation - // timed out). - // - // The operation might work if tried again, but it should NOT be repeated immediately as this - // may simply exacerbate the problem. - - DISCONNECTED = 2, - // The call required communication over a connection that has been lost. The callee will need - // to re-establish connections and try again. - - UNIMPLEMENTED = 3 - // The requested method is not implemented. The caller may wish to revert to a fallback - // approach based on other methods. - - // IF YOU ADD A NEW VALUE: - // - Update the stringifier. - // - Update Cap'n Proto's RPC protocol's Exception.Type enum. - }; - - Exception(Type type, const char* file, int line, String description = nullptr) noexcept; - Exception(Type type, String file, int line, String description = nullptr) noexcept; - Exception(const Exception& other) noexcept; - Exception(Exception&& other) = default; - ~Exception() noexcept; - - const char* getFile() const { return file; } - int getLine() const { return line; } - Type getType() const { return type; } - StringPtr getDescription() const { return description; } - ArrayPtr getStackTrace() const { return arrayPtr(trace, traceCount); } - - struct Context { - // Describes a bit about what was going on when the exception was thrown. - - const char* file; - int line; - String description; - Maybe> next; - - Context(const char* file, int line, String&& description, Maybe>&& next) - : file(file), line(line), description(mv(description)), next(mv(next)) {} - Context(const Context& other) noexcept; - }; - - inline Maybe getContext() const { - KJ_IF_MAYBE(c, context) { - return **c; - } else { - return nullptr; - } - } - - void wrapContext(const char* file, int line, String&& description); - // Wraps the context in a new node. This becomes the head node returned by getContext() -- it - // is expected that contexts will be added in reverse order as the exception passes up the - // callback stack. - - KJ_NOINLINE void extendTrace(uint ignoreCount); - // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount` - // frames (see `getStackTrace()` for discussion of `ignoreCount`). - - KJ_NOINLINE void truncateCommonTrace(); - // Remove the part of the stack trace which the exception shares with the caller of this method. - // This is used by the async library to remove the async infrastructure from the stack trace - // before replacing it with the async trace. - - void addTrace(void* ptr); - // Append the given pointer to the backtrace, if it is not already full. This is used by the - // async library to trace through the promise chain that led to the exception. - -private: - String ownFile; - const char* file; - int line; - Type type; - String description; - Maybe> context; - void* trace[32]; - uint traceCount; - - friend class ExceptionImpl; -}; - -StringPtr KJ_STRINGIFY(Exception::Type type); -String KJ_STRINGIFY(const Exception& e); - -// ======================================================================================= - -enum class LogSeverity { - INFO, // Information describing what the code is up to, which users may request to see - // with a flag like `--verbose`. Does not indicate a problem. Not printed by - // default; you must call setLogLevel(INFO) to enable. - WARNING, // A problem was detected but execution can continue with correct output. - ERROR, // Something is wrong, but execution can continue with garbage output. - FATAL, // Something went wrong, and execution cannot continue. - DBG // Temporary debug logging. See KJ_DBG. - - // Make sure to update the stringifier if you add a new severity level. -}; - -StringPtr KJ_STRINGIFY(LogSeverity severity); - -class ExceptionCallback { - // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order - // to perform your own exception handling. For example, a reasonable thing to do is to have - // onRecoverableException() set a flag indicating that an error occurred, and then check for that - // flag just before writing to storage and/or returning results to the user. If the flag is set, - // discard whatever you have and return an error instead. - // - // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the - // newest ExceptionCallback on the calling thread's stack is called. The default implementation - // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks - // behave a lot like try/catch blocks, except that they are called before any stack unwinding - // occurs. - -public: - ExceptionCallback(); - KJ_DISALLOW_COPY(ExceptionCallback); - virtual ~ExceptionCallback() noexcept(false); - - virtual void onRecoverableException(Exception&& exception); - // Called when an exception has been raised, but the calling code has the ability to continue by - // producing garbage output. This method _should_ throw the exception, but is allowed to simply - // return if garbage output is acceptable. - // - // The global default implementation throws an exception unless the library was compiled with - // -fno-exceptions, in which case it logs an error and returns. - - virtual void onFatalException(Exception&& exception); - // Called when an exception has been raised and the calling code cannot continue. If this method - // returns normally, abort() will be called. The method must throw the exception to avoid - // aborting. - // - // The global default implementation throws an exception unless the library was compiled with - // -fno-exceptions, in which case it logs an error and returns. - - virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, - String&& text); - // Called when something wants to log some debug text. `contextDepth` indicates how many levels - // of context the message passed through; it may make sense to indent the message accordingly. - // - // The global default implementation writes the text to stderr. - -protected: - ExceptionCallback& next; - -private: - ExceptionCallback(ExceptionCallback& next); - - class RootExceptionCallback; - friend ExceptionCallback& getExceptionCallback(); -}; - -ExceptionCallback& getExceptionCallback(); -// Returns the current exception callback. - -KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0)); -// Invoke the exception callback to throw the given fatal exception. If the exception callback -// returns, abort. - -KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0); -// Invoke the exception callback to throw the given recoverable exception. If the exception -// callback returns, return normally. - -// ======================================================================================= - -namespace _ { class Runnable; } - -template -Maybe runCatchingExceptions(Func&& func) noexcept; -// Executes the given function (usually, a lambda returning nothing) catching any exceptions that -// are thrown. Returns the Exception if there was one, or null if the operation completed normally. -// Non-KJ exceptions will be wrapped. -// -// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any -// recoverable exceptions occurred while running the function and will return those. - -class UnwindDetector { - // Utility for detecting when a destructor is called due to unwind. Useful for: - // - Avoiding throwing exceptions in this case, which would terminate the program. - // - Detecting whether to commit or roll back a transaction. - // - // To use this class, either inherit privately from it or declare it as a member. The detector - // works by comparing the exception state against that when the constructor was called, so for - // an object that was actually constructed during exception unwind, it will behave as if no - // unwind is taking place. This is usually the desired behavior. - -public: - UnwindDetector(); - - bool isUnwinding() const; - // Returns true if the current thread is in a stack unwind that it wasn't in at the time the - // object was constructed. - - template - void catchExceptionsIfUnwinding(Func&& func) const; - // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are - // caught and treated as secondary faults, meaning they are considered to be side-effects of the - // exception that is unwinding the stack. Otherwise, exceptions are passed through normally. - -private: - uint uncaughtCount; - - void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const; -}; - -namespace _ { // private - -class Runnable { -public: - virtual void run() = 0; -}; - -template -class RunnableImpl: public Runnable { -public: - RunnableImpl(Func&& func): func(kj::mv(func)) {} - void run() override { - func(); - } -private: - Func func; -}; - -Maybe runCatchingExceptions(Runnable& runnable) noexcept; - -} // namespace _ (private) - -template -Maybe runCatchingExceptions(Func&& func) noexcept { - _::RunnableImpl> runnable(kj::fwd(func)); - return _::runCatchingExceptions(runnable); -} - -template -void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const { - if (isUnwinding()) { - _::RunnableImpl> runnable(kj::fwd(func)); - catchExceptionsAsSecondaryFaults(runnable); - } else { - func(); - } -} - -#define KJ_ON_SCOPE_SUCCESS(code) \ - ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ - KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) -// Runs `code` if the current scope is exited normally (not due to an exception). - -#define KJ_ON_SCOPE_FAILURE(code) \ - ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ - KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) -// Runs `code` if the current scope is exited due to an exception. - -// ======================================================================================= - -KJ_NOINLINE ArrayPtr getStackTrace(ArrayPtr space, uint ignoreCount); -// Attempt to get the current stack trace, returning a list of pointers to instructions. The -// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace. -// If the platform doesn't support stack traces, returns an empty array. -// -// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping -// off a prefix of the trace that is uninteresting to the developer because it's just locations -// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as -// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the -// ignored entries will still waste space in the `space` array (and the returned array's `begin()` -// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero -// since `getStackTrace()` needs to ignore its own internal frames). - -String stringifyStackTrace(ArrayPtr); -// Convert the stack trace to a string with file names and line numbers. This may involve executing -// suprocesses. - -void printStackTraceOnCrash(); -// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print -// a stack trace. You should call this as early as possible on program startup. Programs using -// KJ_MAIN get this automatically. - -kj::StringPtr trimSourceFilename(kj::StringPtr filename); -// Given a source code file name, trim off noisy prefixes like "src/" or -// "/ekam-provider/canonical/". - -} // namespace kj - -#endif // KJ_EXCEPTION_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_EXCEPTION_H_ +#define KJ_EXCEPTION_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" +#include "array.h" +#include "string.h" + +namespace kj { + +class ExceptionImpl; + +class Exception { + // Exception thrown in case of fatal errors. + // + // Actually, a subclass of this which also implements std::exception will be thrown, but we hide + // that fact from the interface to avoid #including . + +public: + enum class Type { + // What kind of failure? + + FAILED = 0, + // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this + // error type. + + OVERLOADED = 1, + // The call failed because of a temporary lack of resources. This could be space resources + // (out of memory, out of disk space) or time resources (request queue overflow, operation + // timed out). + // + // The operation might work if tried again, but it should NOT be repeated immediately as this + // may simply exacerbate the problem. + + DISCONNECTED = 2, + // The call required communication over a connection that has been lost. The callee will need + // to re-establish connections and try again. + + UNIMPLEMENTED = 3 + // The requested method is not implemented. The caller may wish to revert to a fallback + // approach based on other methods. + + // IF YOU ADD A NEW VALUE: + // - Update the stringifier. + // - Update Cap'n Proto's RPC protocol's Exception.Type enum. + }; + + Exception(Type type, const char* file, int line, String description = nullptr) noexcept; + Exception(Type type, String file, int line, String description = nullptr) noexcept; + Exception(const Exception& other) noexcept; + Exception(Exception&& other) = default; + ~Exception() noexcept; + + const char* getFile() const { return file; } + int getLine() const { return line; } + Type getType() const { return type; } + StringPtr getDescription() const { return description; } + ArrayPtr getStackTrace() const { return arrayPtr(trace, traceCount); } + + struct Context { + // Describes a bit about what was going on when the exception was thrown. + + const char* file; + int line; + String description; + Maybe> next; + + Context(const char* file, int line, String&& description, Maybe>&& next) + : file(file), line(line), description(mv(description)), next(mv(next)) {} + Context(const Context& other) noexcept; + }; + + inline Maybe getContext() const { + KJ_IF_MAYBE(c, context) { + return **c; + } else { + return nullptr; + } + } + + void wrapContext(const char* file, int line, String&& description); + // Wraps the context in a new node. This becomes the head node returned by getContext() -- it + // is expected that contexts will be added in reverse order as the exception passes up the + // callback stack. + + KJ_NOINLINE void extendTrace(uint ignoreCount); + // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount` + // frames (see `getStackTrace()` for discussion of `ignoreCount`). + + KJ_NOINLINE void truncateCommonTrace(); + // Remove the part of the stack trace which the exception shares with the caller of this method. + // This is used by the async library to remove the async infrastructure from the stack trace + // before replacing it with the async trace. + + void addTrace(void* ptr); + // Append the given pointer to the backtrace, if it is not already full. This is used by the + // async library to trace through the promise chain that led to the exception. + +private: + String ownFile; + const char* file; + int line; + Type type; + String description; + Maybe> context; + void* trace[32]; + uint traceCount; + + friend class ExceptionImpl; +}; + +StringPtr KJ_STRINGIFY(Exception::Type type); +String KJ_STRINGIFY(const Exception& e); + +// ======================================================================================= + +enum class LogSeverity { + INFO, // Information describing what the code is up to, which users may request to see + // with a flag like `--verbose`. Does not indicate a problem. Not printed by + // default; you must call setLogLevel(INFO) to enable. + WARNING, // A problem was detected but execution can continue with correct output. + ERROR, // Something is wrong, but execution can continue with garbage output. + FATAL, // Something went wrong, and execution cannot continue. + DBG // Temporary debug logging. See KJ_DBG. + + // Make sure to update the stringifier if you add a new severity level. +}; + +StringPtr KJ_STRINGIFY(LogSeverity severity); + +class ExceptionCallback { + // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order + // to perform your own exception handling. For example, a reasonable thing to do is to have + // onRecoverableException() set a flag indicating that an error occurred, and then check for that + // flag just before writing to storage and/or returning results to the user. If the flag is set, + // discard whatever you have and return an error instead. + // + // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the + // newest ExceptionCallback on the calling thread's stack is called. The default implementation + // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks + // behave a lot like try/catch blocks, except that they are called before any stack unwinding + // occurs. + +public: + ExceptionCallback(); + KJ_DISALLOW_COPY(ExceptionCallback); + virtual ~ExceptionCallback() noexcept(false); + + virtual void onRecoverableException(Exception&& exception); + // Called when an exception has been raised, but the calling code has the ability to continue by + // producing garbage output. This method _should_ throw the exception, but is allowed to simply + // return if garbage output is acceptable. + // + // The global default implementation throws an exception unless the library was compiled with + // -fno-exceptions, in which case it logs an error and returns. + + virtual void onFatalException(Exception&& exception); + // Called when an exception has been raised and the calling code cannot continue. If this method + // returns normally, abort() will be called. The method must throw the exception to avoid + // aborting. + // + // The global default implementation throws an exception unless the library was compiled with + // -fno-exceptions, in which case it logs an error and returns. + + virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text); + // Called when something wants to log some debug text. `contextDepth` indicates how many levels + // of context the message passed through; it may make sense to indent the message accordingly. + // + // The global default implementation writes the text to stderr. + + enum class StackTraceMode { + FULL, + // Stringifying a stack trace will attempt to determine source file and line numbers. This may + // be expensive. For example, on Linux, this shells out to `addr2line`. + // + // This is the default in debug builds. + + ADDRESS_ONLY, + // Stringifying a stack trace will only generate a list of code addresses. + // + // This is the default in release builds. + + NONE + // Generating a stack trace will always return an empty array. + // + // This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library + // has been observed to be pretty slow, so exception-heavy code might benefit significantly + // from this setting. (But exceptions should be rare...) + }; + + virtual StackTraceMode stackTraceMode(); + // Returns the current preferred stack trace mode. + +protected: + ExceptionCallback& next; + +private: + ExceptionCallback(ExceptionCallback& next); + + class RootExceptionCallback; + friend ExceptionCallback& getExceptionCallback(); +}; + +ExceptionCallback& getExceptionCallback(); +// Returns the current exception callback. + +KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0)); +// Invoke the exception callback to throw the given fatal exception. If the exception callback +// returns, abort. + +KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0); +// Invoke the exception callback to throw the given recoverable exception. If the exception +// callback returns, return normally. + +// ======================================================================================= + +namespace _ { class Runnable; } + +template +Maybe runCatchingExceptions(Func&& func) noexcept; +// Executes the given function (usually, a lambda returning nothing) catching any exceptions that +// are thrown. Returns the Exception if there was one, or null if the operation completed normally. +// Non-KJ exceptions will be wrapped. +// +// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any +// recoverable exceptions occurred while running the function and will return those. + +class UnwindDetector { + // Utility for detecting when a destructor is called due to unwind. Useful for: + // - Avoiding throwing exceptions in this case, which would terminate the program. + // - Detecting whether to commit or roll back a transaction. + // + // To use this class, either inherit privately from it or declare it as a member. The detector + // works by comparing the exception state against that when the constructor was called, so for + // an object that was actually constructed during exception unwind, it will behave as if no + // unwind is taking place. This is usually the desired behavior. + +public: + UnwindDetector(); + + bool isUnwinding() const; + // Returns true if the current thread is in a stack unwind that it wasn't in at the time the + // object was constructed. + + template + void catchExceptionsIfUnwinding(Func&& func) const; + // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are + // caught and treated as secondary faults, meaning they are considered to be side-effects of the + // exception that is unwinding the stack. Otherwise, exceptions are passed through normally. + +private: + uint uncaughtCount; + + void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const; +}; + +namespace _ { // private + +class Runnable { +public: + virtual void run() = 0; +}; + +template +class RunnableImpl: public Runnable { +public: + RunnableImpl(Func&& func): func(kj::mv(func)) {} + void run() override { + func(); + } +private: + Func func; +}; + +Maybe runCatchingExceptions(Runnable& runnable) noexcept; + +} // namespace _ (private) + +template +Maybe runCatchingExceptions(Func&& func) noexcept { + _::RunnableImpl> runnable(kj::fwd(func)); + return _::runCatchingExceptions(runnable); +} + +template +void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const { + if (isUnwinding()) { + _::RunnableImpl> runnable(kj::fwd(func)); + catchExceptionsAsSecondaryFaults(runnable); + } else { + func(); + } +} + +#define KJ_ON_SCOPE_SUCCESS(code) \ + ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ + KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) +// Runs `code` if the current scope is exited normally (not due to an exception). + +#define KJ_ON_SCOPE_FAILURE(code) \ + ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ + KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) +// Runs `code` if the current scope is exited due to an exception. + +// ======================================================================================= + +KJ_NOINLINE ArrayPtr getStackTrace(ArrayPtr space, uint ignoreCount); +// Attempt to get the current stack trace, returning a list of pointers to instructions. The +// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace. +// If the platform doesn't support stack traces, returns an empty array. +// +// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping +// off a prefix of the trace that is uninteresting to the developer because it's just locations +// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as +// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the +// ignored entries will still waste space in the `space` array (and the returned array's `begin()` +// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero +// since `getStackTrace()` needs to ignore its own internal frames). + +String stringifyStackTrace(ArrayPtr); +// Convert the stack trace to a string with file names and line numbers. This may involve executing +// suprocesses. + +String getStackTrace(); +// Get a stack trace right now and stringify it. Useful for debugging. + +void printStackTraceOnCrash(); +// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print +// a stack trace. You should call this as early as possible on program startup. Programs using +// KJ_MAIN get this automatically. + +kj::StringPtr trimSourceFilename(kj::StringPtr filename); +// Given a source code file name, trim off noisy prefixes like "src/" or +// "/ekam-provider/canonical/". + +} // namespace kj + +#endif // KJ_EXCEPTION_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/function.h --- a/osx/include/kj/function.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/function.h Mon May 22 10:01:37 2017 +0100 @@ -1,277 +1,277 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_FUNCTION_H_ -#define KJ_FUNCTION_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "memory.h" - -namespace kj { - -template -class Function; -// Function wrapper using virtual-based polymorphism. Use this when template polymorphism is -// not possible. You can, for example, accept a Function as a parameter: -// -// void setFilter(Function filter); -// -// The caller of `setFilter()` may then pass any callable object as the parameter. The callable -// object does not have to have the exact signature specified, just one that is "compatible" -- -// i.e. the return type is covariant and the parameters are contravariant. -// -// Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This -// is to avoid unexpected heap allocation or slow atomic reference counting. -// -// When a `Function` is constructed from an lvalue, it captures only a reference to the value. -// When constructed from an rvalue, it invokes the value's move constructor. So, for example: -// -// struct AddN { -// int n; -// int operator(int i) { return i + n; } -// } -// -// Function f1 = AddN{2}; -// // f1 owns an instance of AddN. It may safely be moved out -// // of the local scope. -// -// AddN adder(2); -// Function f2 = adder; -// // f2 contains a reference to `adder`. Thus, it becomes invalid -// // when `adder` goes out-of-scope. -// -// AddN adder2(2); -// Function f3 = kj::mv(adder2); -// // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely -// // be moved out of the local scope. -// -// Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName). -// For example: -// -// class Printer { -// public: -// void print(int i); -// void print(kj::StringPtr s); -// }; -// -// Printer p; -// -// Function intPrinter = KJ_BIND_METHOD(p, print); -// // Will call Printer::print(int). -// -// Function strPrinter = KJ_BIND_METHOD(p, print); -// // Will call Printer::print(kj::StringPtr). -// -// Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of -// Function it is binding to. - -template -class ConstFunction; -// Like Function, but wraps a "const" (i.e. thread-safe) call. - -template -class Function { -public: - template - inline Function(F&& f): impl(heap>(kj::fwd(f))) {} - Function() = default; - - // Make sure people don't accidentally end up wrapping a reference when they meant to return - // a function. - KJ_DISALLOW_COPY(Function); - Function(Function&) = delete; - Function& operator=(Function&) = delete; - template Function(const Function&) = delete; - template Function& operator=(const Function&) = delete; - template Function(const ConstFunction&) = delete; - template Function& operator=(const ConstFunction&) = delete; - Function(Function&&) = default; - Function& operator=(Function&&) = default; - - inline Return operator()(Params... params) { - return (*impl)(kj::fwd(params)...); - } - - Function reference() { - // Forms a new Function of the same type that delegates to this Function by reference. - // Therefore, this Function must outlive the returned Function, but otherwise they behave - // exactly the same. - - return *impl; - } - -private: - class Iface { - public: - virtual Return operator()(Params... params) = 0; - }; - - template - class Impl final: public Iface { - public: - explicit Impl(F&& f): f(kj::fwd(f)) {} - - Return operator()(Params... params) override { - return f(kj::fwd(params)...); - } - - private: - F f; - }; - - Own impl; -}; - -template -class ConstFunction { -public: - template - inline ConstFunction(F&& f): impl(heap>(kj::fwd(f))) {} - ConstFunction() = default; - - // Make sure people don't accidentally end up wrapping a reference when they meant to return - // a function. - KJ_DISALLOW_COPY(ConstFunction); - ConstFunction(ConstFunction&) = delete; - ConstFunction& operator=(ConstFunction&) = delete; - template ConstFunction(const ConstFunction&) = delete; - template ConstFunction& operator=(const ConstFunction&) = delete; - template ConstFunction(const Function&) = delete; - template ConstFunction& operator=(const Function&) = delete; - ConstFunction(ConstFunction&&) = default; - ConstFunction& operator=(ConstFunction&&) = default; - - inline Return operator()(Params... params) const { - return (*impl)(kj::fwd(params)...); - } - - ConstFunction reference() const { - // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference. - // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they - // behave exactly the same. - - return *impl; - } - -private: - class Iface { - public: - virtual Return operator()(Params... params) const = 0; - }; - - template - class Impl final: public Iface { - public: - explicit Impl(F&& f): f(kj::fwd(f)) {} - - Return operator()(Params... params) const override { - return f(kj::fwd(params)...); - } - - private: - F f; - }; - - Own impl; -}; - -#if 1 - -namespace _ { // private - -template -class BoundMethod; - -template ::*method)(Params...)> -class BoundMethod::*)(Params...), method> { -public: - BoundMethod(T&& t): t(kj::fwd(t)) {} - - Return operator()(Params&&... params) { - return (t.*method)(kj::fwd(params)...); - } - -private: - T t; -}; - -template ::*method)(Params...) const> -class BoundMethod::*)(Params...) const, method> { -public: - BoundMethod(T&& t): t(kj::fwd(t)) {} - - Return operator()(Params&&... params) const { - return (t.*method)(kj::fwd(params)...); - } - -private: - T t; -}; - -} // namespace _ (private) - -#define KJ_BIND_METHOD(obj, method) \ - ::kj::_::BoundMethod::method), \ - &::kj::Decay::method>(obj) -// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an -// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will -// contain a copy (by move) of it. -// -// The current implementation requires that the method is not overloaded. -// -// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and -// probably make it work with overloaded methods. - -#else -// Here's a better implementation of the above that doesn't work with GCC (but does with Clang) -// because it uses a local class with a template method. Sigh. This implementation supports -// overloaded methods. - -#define KJ_BIND_METHOD(obj, method) \ - ({ \ - typedef KJ_DECLTYPE_REF(obj) T; \ - class F { \ - public: \ - inline F(T&& t): t(::kj::fwd(t)) {} \ - template \ - auto operator()(Params&&... params) \ - -> decltype(::kj::instance().method(::kj::fwd(params)...)) { \ - return t.method(::kj::fwd(params)...); \ - } \ - private: \ - T t; \ - }; \ - (F(obj)); \ - }) -// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an -// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will -// contain a copy (by move) of it. - -#endif - -} // namespace kj - -#endif // KJ_FUNCTION_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_FUNCTION_H_ +#define KJ_FUNCTION_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" + +namespace kj { + +template +class Function; +// Function wrapper using virtual-based polymorphism. Use this when template polymorphism is +// not possible. You can, for example, accept a Function as a parameter: +// +// void setFilter(Function filter); +// +// The caller of `setFilter()` may then pass any callable object as the parameter. The callable +// object does not have to have the exact signature specified, just one that is "compatible" -- +// i.e. the return type is covariant and the parameters are contravariant. +// +// Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This +// is to avoid unexpected heap allocation or slow atomic reference counting. +// +// When a `Function` is constructed from an lvalue, it captures only a reference to the value. +// When constructed from an rvalue, it invokes the value's move constructor. So, for example: +// +// struct AddN { +// int n; +// int operator(int i) { return i + n; } +// } +// +// Function f1 = AddN{2}; +// // f1 owns an instance of AddN. It may safely be moved out +// // of the local scope. +// +// AddN adder(2); +// Function f2 = adder; +// // f2 contains a reference to `adder`. Thus, it becomes invalid +// // when `adder` goes out-of-scope. +// +// AddN adder2(2); +// Function f3 = kj::mv(adder2); +// // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely +// // be moved out of the local scope. +// +// Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName). +// For example: +// +// class Printer { +// public: +// void print(int i); +// void print(kj::StringPtr s); +// }; +// +// Printer p; +// +// Function intPrinter = KJ_BIND_METHOD(p, print); +// // Will call Printer::print(int). +// +// Function strPrinter = KJ_BIND_METHOD(p, print); +// // Will call Printer::print(kj::StringPtr). +// +// Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of +// Function it is binding to. + +template +class ConstFunction; +// Like Function, but wraps a "const" (i.e. thread-safe) call. + +template +class Function { +public: + template + inline Function(F&& f): impl(heap>(kj::fwd(f))) {} + Function() = default; + + // Make sure people don't accidentally end up wrapping a reference when they meant to return + // a function. + KJ_DISALLOW_COPY(Function); + Function(Function&) = delete; + Function& operator=(Function&) = delete; + template Function(const Function&) = delete; + template Function& operator=(const Function&) = delete; + template Function(const ConstFunction&) = delete; + template Function& operator=(const ConstFunction&) = delete; + Function(Function&&) = default; + Function& operator=(Function&&) = default; + + inline Return operator()(Params... params) { + return (*impl)(kj::fwd(params)...); + } + + Function reference() { + // Forms a new Function of the same type that delegates to this Function by reference. + // Therefore, this Function must outlive the returned Function, but otherwise they behave + // exactly the same. + + return *impl; + } + +private: + class Iface { + public: + virtual Return operator()(Params... params) = 0; + }; + + template + class Impl final: public Iface { + public: + explicit Impl(F&& f): f(kj::fwd(f)) {} + + Return operator()(Params... params) override { + return f(kj::fwd(params)...); + } + + private: + F f; + }; + + Own impl; +}; + +template +class ConstFunction { +public: + template + inline ConstFunction(F&& f): impl(heap>(kj::fwd(f))) {} + ConstFunction() = default; + + // Make sure people don't accidentally end up wrapping a reference when they meant to return + // a function. + KJ_DISALLOW_COPY(ConstFunction); + ConstFunction(ConstFunction&) = delete; + ConstFunction& operator=(ConstFunction&) = delete; + template ConstFunction(const ConstFunction&) = delete; + template ConstFunction& operator=(const ConstFunction&) = delete; + template ConstFunction(const Function&) = delete; + template ConstFunction& operator=(const Function&) = delete; + ConstFunction(ConstFunction&&) = default; + ConstFunction& operator=(ConstFunction&&) = default; + + inline Return operator()(Params... params) const { + return (*impl)(kj::fwd(params)...); + } + + ConstFunction reference() const { + // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference. + // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they + // behave exactly the same. + + return *impl; + } + +private: + class Iface { + public: + virtual Return operator()(Params... params) const = 0; + }; + + template + class Impl final: public Iface { + public: + explicit Impl(F&& f): f(kj::fwd(f)) {} + + Return operator()(Params... params) const override { + return f(kj::fwd(params)...); + } + + private: + F f; + }; + + Own impl; +}; + +#if 1 + +namespace _ { // private + +template +class BoundMethod; + +template ::*method)(Params...)> +class BoundMethod::*)(Params...), method> { +public: + BoundMethod(T&& t): t(kj::fwd(t)) {} + + Return operator()(Params&&... params) { + return (t.*method)(kj::fwd(params)...); + } + +private: + T t; +}; + +template ::*method)(Params...) const> +class BoundMethod::*)(Params...) const, method> { +public: + BoundMethod(T&& t): t(kj::fwd(t)) {} + + Return operator()(Params&&... params) const { + return (t.*method)(kj::fwd(params)...); + } + +private: + T t; +}; + +} // namespace _ (private) + +#define KJ_BIND_METHOD(obj, method) \ + ::kj::_::BoundMethod::method), \ + &::kj::Decay::method>(obj) +// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an +// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will +// contain a copy (by move) of it. +// +// The current implementation requires that the method is not overloaded. +// +// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and +// probably make it work with overloaded methods. + +#else +// Here's a better implementation of the above that doesn't work with GCC (but does with Clang) +// because it uses a local class with a template method. Sigh. This implementation supports +// overloaded methods. + +#define KJ_BIND_METHOD(obj, method) \ + ({ \ + typedef KJ_DECLTYPE_REF(obj) T; \ + class F { \ + public: \ + inline F(T&& t): t(::kj::fwd(t)) {} \ + template \ + auto operator()(Params&&... params) \ + -> decltype(::kj::instance().method(::kj::fwd(params)...)) { \ + return t.method(::kj::fwd(params)...); \ + } \ + private: \ + T t; \ + }; \ + (F(obj)); \ + }) +// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an +// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will +// contain a copy (by move) of it. + +#endif + +} // namespace kj + +#endif // KJ_FUNCTION_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/io.h --- a/osx/include/kj/io.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/io.h Mon May 22 10:01:37 2017 +0100 @@ -1,331 +1,419 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_IO_H_ -#define KJ_IO_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include -#include "common.h" -#include "array.h" -#include "exception.h" - -namespace kj { - -// ======================================================================================= -// Abstract interfaces - -class InputStream { -public: - virtual ~InputStream() noexcept(false); - - size_t read(void* buffer, size_t minBytes, size_t maxBytes); - // Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns - // the size read. Throws an exception on errors. Implemented in terms of tryRead(). - // - // maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount - // needed by the caller before it can start doing useful processing. If the stream returns less - // than maxBytes, the caller will usually call read() again later to get the rest. Returning - // less than maxBytes is useful when it makes sense for the caller to parallelize processing - // with I/O. - // - // Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may - // attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes. - // To detect EOF without throwing an exception, use tryRead(). - // - // If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not - // expected to understand how to deal with partial reads. - - virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; - // Like read(), but may return fewer than minBytes on EOF. - - inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); } - // Convenience method for reading an exact number of bytes. - - virtual void skip(size_t bytes); - // Skips past the given number of bytes, discarding them. The default implementation read()s - // into a scratch buffer. -}; - -class OutputStream { -public: - virtual ~OutputStream() noexcept(false); - - virtual void write(const void* buffer, size_t size) = 0; - // Always writes the full size. Throws exception on error. - - virtual void write(ArrayPtr> pieces); - // Equivalent to write()ing each byte array in sequence, which is what the default implementation - // does. Override if you can do something better, e.g. use writev() to do the write in a single - // syscall. -}; - -class BufferedInputStream: public InputStream { - // An input stream which buffers some bytes in memory to reduce system call overhead. - // - OR - - // An input stream that actually reads from some in-memory data structure and wants to give its - // caller a direct pointer to that memory to potentially avoid a copy. - -public: - virtual ~BufferedInputStream() noexcept(false); - - ArrayPtr getReadBuffer(); - // Get a direct pointer into the read buffer, which contains the next bytes in the input. If the - // caller consumes any bytes, it should then call skip() to indicate this. This always returns a - // non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer(). - - virtual ArrayPtr tryGetReadBuffer() = 0; - // Like getReadBuffer() but may return an empty buffer on EOF. -}; - -class BufferedOutputStream: public OutputStream { - // An output stream which buffers some bytes in memory to reduce system call overhead. - // - OR - - // An output stream that actually writes into some in-memory data structure and wants to give its - // caller a direct pointer to that memory to potentially avoid a copy. - -public: - virtual ~BufferedOutputStream() noexcept(false); - - virtual ArrayPtr getWriteBuffer() = 0; - // Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of - // this buffer and then pass it to write(), in which case write() may avoid a copy. It is - // incorrect to pass to write any slice of this buffer which is not a prefix. -}; - -// ======================================================================================= -// Buffered streams implemented as wrappers around regular streams - -class BufferedInputStreamWrapper: public BufferedInputStream { - // Implements BufferedInputStream in terms of an InputStream. - // - // Note that the underlying stream's position is unpredictable once the wrapper is destroyed, - // unless the entire stream was consumed. To read a predictable number of bytes in a buffered - // way without going over, you'd need this wrapper to wrap some other wrapper which itself - // implements an artificial EOF at the desired point. Such a stream should be trivial to write - // but is not provided by the library at this time. - -public: - explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr buffer = nullptr); - // Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about - // the position of the inner stream after a buffered wrapper has been created unless the entire - // input is read. - // - // If the second parameter is non-null, the stream uses the given buffer instead of allocating - // its own. This may improve performance if the buffer can be reused. - - KJ_DISALLOW_COPY(BufferedInputStreamWrapper); - ~BufferedInputStreamWrapper() noexcept(false); - - // implements BufferedInputStream ---------------------------------- - ArrayPtr tryGetReadBuffer() override; - size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; - void skip(size_t bytes) override; - -private: - InputStream& inner; - Array ownedBuffer; - ArrayPtr buffer; - ArrayPtr bufferAvailable; -}; - -class BufferedOutputStreamWrapper: public BufferedOutputStream { - // Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the - // underlying stream may be delayed until flush() is called or the wrapper is destroyed. - -public: - explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr buffer = nullptr); - // Creates a buffered stream wrapping the given non-buffered stream. - // - // If the second parameter is non-null, the stream uses the given buffer instead of allocating - // its own. This may improve performance if the buffer can be reused. - - KJ_DISALLOW_COPY(BufferedOutputStreamWrapper); - ~BufferedOutputStreamWrapper() noexcept(false); - - void flush(); - // Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that - // this only flushes this object's buffer; this object has no idea how to flush any other buffers - // that may be present in the underlying stream. - - // implements BufferedOutputStream --------------------------------- - ArrayPtr getWriteBuffer() override; - void write(const void* buffer, size_t size) override; - -private: - OutputStream& inner; - Array ownedBuffer; - ArrayPtr buffer; - byte* bufferPos; - UnwindDetector unwindDetector; -}; - -// ======================================================================================= -// Array I/O - -class ArrayInputStream: public BufferedInputStream { -public: - explicit ArrayInputStream(ArrayPtr array); - KJ_DISALLOW_COPY(ArrayInputStream); - ~ArrayInputStream() noexcept(false); - - // implements BufferedInputStream ---------------------------------- - ArrayPtr tryGetReadBuffer() override; - size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; - void skip(size_t bytes) override; - -private: - ArrayPtr array; -}; - -class ArrayOutputStream: public BufferedOutputStream { -public: - explicit ArrayOutputStream(ArrayPtr array); - KJ_DISALLOW_COPY(ArrayOutputStream); - ~ArrayOutputStream() noexcept(false); - - ArrayPtr getArray() { - // Get the portion of the array which has been filled in. - return arrayPtr(array.begin(), fillPos); - } - - // implements BufferedInputStream ---------------------------------- - ArrayPtr getWriteBuffer() override; - void write(const void* buffer, size_t size) override; - -private: - ArrayPtr array; - byte* fillPos; -}; - -class VectorOutputStream: public BufferedOutputStream { -public: - explicit VectorOutputStream(size_t initialCapacity = 4096); - KJ_DISALLOW_COPY(VectorOutputStream); - ~VectorOutputStream() noexcept(false); - - ArrayPtr getArray() { - // Get the portion of the array which has been filled in. - return arrayPtr(vector.begin(), fillPos); - } - - // implements BufferedInputStream ---------------------------------- - ArrayPtr getWriteBuffer() override; - void write(const void* buffer, size_t size) override; - -private: - Array vector; - byte* fillPos; - - void grow(size_t minSize); -}; - -// ======================================================================================= -// File descriptor I/O - -class AutoCloseFd { - // A wrapper around a file descriptor which automatically closes the descriptor when destroyed. - // The wrapper supports move construction for transferring ownership of the descriptor. If - // close() returns an error, the destructor throws an exception, UNLESS the destructor is being - // called during unwind from another exception, in which case the close error is ignored. - // - // If your code is not exception-safe, you should not use AutoCloseFd. In this case you will - // have to call close() yourself and handle errors appropriately. - -public: - inline AutoCloseFd(): fd(-1) {} - inline AutoCloseFd(decltype(nullptr)): fd(-1) {} - inline explicit AutoCloseFd(int fd): fd(fd) {} - inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; } - KJ_DISALLOW_COPY(AutoCloseFd); - ~AutoCloseFd() noexcept(false); - - inline AutoCloseFd& operator=(AutoCloseFd&& other) { - AutoCloseFd old(kj::mv(*this)); - fd = other.fd; - other.fd = -1; - return *this; - } - - inline AutoCloseFd& operator=(decltype(nullptr)) { - AutoCloseFd old(kj::mv(*this)); - return *this; - } - - inline operator int() const { return fd; } - inline int get() const { return fd; } - - operator bool() const = delete; - // Deleting this operator prevents accidental use in boolean contexts, which - // the int conversion operator above would otherwise allow. - - inline bool operator==(decltype(nullptr)) { return fd < 0; } - inline bool operator!=(decltype(nullptr)) { return fd >= 0; } - -private: - int fd; - UnwindDetector unwindDetector; -}; - -inline auto KJ_STRINGIFY(const AutoCloseFd& fd) - -> decltype(kj::toCharSequence(implicitCast(fd))) { - return kj::toCharSequence(implicitCast(fd)); -} - -class FdInputStream: public InputStream { - // An InputStream wrapping a file descriptor. - -public: - explicit FdInputStream(int fd): fd(fd) {} - explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} - KJ_DISALLOW_COPY(FdInputStream); - ~FdInputStream() noexcept(false); - - size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; - -private: - int fd; - AutoCloseFd autoclose; -}; - -class FdOutputStream: public OutputStream { - // An OutputStream wrapping a file descriptor. - -public: - explicit FdOutputStream(int fd): fd(fd) {} - explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} - KJ_DISALLOW_COPY(FdOutputStream); - ~FdOutputStream() noexcept(false); - - void write(const void* buffer, size_t size) override; - void write(ArrayPtr> pieces) override; - -private: - int fd; - AutoCloseFd autoclose; -}; - -} // namespace kj - -#endif // KJ_IO_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_IO_H_ +#define KJ_IO_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include +#include "common.h" +#include "array.h" +#include "exception.h" + +namespace kj { + +// ======================================================================================= +// Abstract interfaces + +class InputStream { +public: + virtual ~InputStream() noexcept(false); + + size_t read(void* buffer, size_t minBytes, size_t maxBytes); + // Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns + // the size read. Throws an exception on errors. Implemented in terms of tryRead(). + // + // maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount + // needed by the caller before it can start doing useful processing. If the stream returns less + // than maxBytes, the caller will usually call read() again later to get the rest. Returning + // less than maxBytes is useful when it makes sense for the caller to parallelize processing + // with I/O. + // + // Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may + // attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes. + // To detect EOF without throwing an exception, use tryRead(). + // + // If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not + // expected to understand how to deal with partial reads. + + virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; + // Like read(), but may return fewer than minBytes on EOF. + + inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); } + // Convenience method for reading an exact number of bytes. + + virtual void skip(size_t bytes); + // Skips past the given number of bytes, discarding them. The default implementation read()s + // into a scratch buffer. +}; + +class OutputStream { +public: + virtual ~OutputStream() noexcept(false); + + virtual void write(const void* buffer, size_t size) = 0; + // Always writes the full size. Throws exception on error. + + virtual void write(ArrayPtr> pieces); + // Equivalent to write()ing each byte array in sequence, which is what the default implementation + // does. Override if you can do something better, e.g. use writev() to do the write in a single + // syscall. +}; + +class BufferedInputStream: public InputStream { + // An input stream which buffers some bytes in memory to reduce system call overhead. + // - OR - + // An input stream that actually reads from some in-memory data structure and wants to give its + // caller a direct pointer to that memory to potentially avoid a copy. + +public: + virtual ~BufferedInputStream() noexcept(false); + + ArrayPtr getReadBuffer(); + // Get a direct pointer into the read buffer, which contains the next bytes in the input. If the + // caller consumes any bytes, it should then call skip() to indicate this. This always returns a + // non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer(). + + virtual ArrayPtr tryGetReadBuffer() = 0; + // Like getReadBuffer() but may return an empty buffer on EOF. +}; + +class BufferedOutputStream: public OutputStream { + // An output stream which buffers some bytes in memory to reduce system call overhead. + // - OR - + // An output stream that actually writes into some in-memory data structure and wants to give its + // caller a direct pointer to that memory to potentially avoid a copy. + +public: + virtual ~BufferedOutputStream() noexcept(false); + + virtual ArrayPtr getWriteBuffer() = 0; + // Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of + // this buffer and then pass it to write(), in which case write() may avoid a copy. It is + // incorrect to pass to write any slice of this buffer which is not a prefix. +}; + +// ======================================================================================= +// Buffered streams implemented as wrappers around regular streams + +class BufferedInputStreamWrapper: public BufferedInputStream { + // Implements BufferedInputStream in terms of an InputStream. + // + // Note that the underlying stream's position is unpredictable once the wrapper is destroyed, + // unless the entire stream was consumed. To read a predictable number of bytes in a buffered + // way without going over, you'd need this wrapper to wrap some other wrapper which itself + // implements an artificial EOF at the desired point. Such a stream should be trivial to write + // but is not provided by the library at this time. + +public: + explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr buffer = nullptr); + // Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about + // the position of the inner stream after a buffered wrapper has been created unless the entire + // input is read. + // + // If the second parameter is non-null, the stream uses the given buffer instead of allocating + // its own. This may improve performance if the buffer can be reused. + + KJ_DISALLOW_COPY(BufferedInputStreamWrapper); + ~BufferedInputStreamWrapper() noexcept(false); + + // implements BufferedInputStream ---------------------------------- + ArrayPtr tryGetReadBuffer() override; + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + InputStream& inner; + Array ownedBuffer; + ArrayPtr buffer; + ArrayPtr bufferAvailable; +}; + +class BufferedOutputStreamWrapper: public BufferedOutputStream { + // Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the + // underlying stream may be delayed until flush() is called or the wrapper is destroyed. + +public: + explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr buffer = nullptr); + // Creates a buffered stream wrapping the given non-buffered stream. + // + // If the second parameter is non-null, the stream uses the given buffer instead of allocating + // its own. This may improve performance if the buffer can be reused. + + KJ_DISALLOW_COPY(BufferedOutputStreamWrapper); + ~BufferedOutputStreamWrapper() noexcept(false); + + void flush(); + // Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that + // this only flushes this object's buffer; this object has no idea how to flush any other buffers + // that may be present in the underlying stream. + + // implements BufferedOutputStream --------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + OutputStream& inner; + Array ownedBuffer; + ArrayPtr buffer; + byte* bufferPos; + UnwindDetector unwindDetector; +}; + +// ======================================================================================= +// Array I/O + +class ArrayInputStream: public BufferedInputStream { +public: + explicit ArrayInputStream(ArrayPtr array); + KJ_DISALLOW_COPY(ArrayInputStream); + ~ArrayInputStream() noexcept(false); + + // implements BufferedInputStream ---------------------------------- + ArrayPtr tryGetReadBuffer() override; + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + ArrayPtr array; +}; + +class ArrayOutputStream: public BufferedOutputStream { +public: + explicit ArrayOutputStream(ArrayPtr array); + KJ_DISALLOW_COPY(ArrayOutputStream); + ~ArrayOutputStream() noexcept(false); + + ArrayPtr getArray() { + // Get the portion of the array which has been filled in. + return arrayPtr(array.begin(), fillPos); + } + + // implements BufferedInputStream ---------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + ArrayPtr array; + byte* fillPos; +}; + +class VectorOutputStream: public BufferedOutputStream { +public: + explicit VectorOutputStream(size_t initialCapacity = 4096); + KJ_DISALLOW_COPY(VectorOutputStream); + ~VectorOutputStream() noexcept(false); + + ArrayPtr getArray() { + // Get the portion of the array which has been filled in. + return arrayPtr(vector.begin(), fillPos); + } + + // implements BufferedInputStream ---------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + Array vector; + byte* fillPos; + + void grow(size_t minSize); +}; + +// ======================================================================================= +// File descriptor I/O + +class AutoCloseFd { + // A wrapper around a file descriptor which automatically closes the descriptor when destroyed. + // The wrapper supports move construction for transferring ownership of the descriptor. If + // close() returns an error, the destructor throws an exception, UNLESS the destructor is being + // called during unwind from another exception, in which case the close error is ignored. + // + // If your code is not exception-safe, you should not use AutoCloseFd. In this case you will + // have to call close() yourself and handle errors appropriately. + +public: + inline AutoCloseFd(): fd(-1) {} + inline AutoCloseFd(decltype(nullptr)): fd(-1) {} + inline explicit AutoCloseFd(int fd): fd(fd) {} + inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; } + KJ_DISALLOW_COPY(AutoCloseFd); + ~AutoCloseFd() noexcept(false); + + inline AutoCloseFd& operator=(AutoCloseFd&& other) { + AutoCloseFd old(kj::mv(*this)); + fd = other.fd; + other.fd = -1; + return *this; + } + + inline AutoCloseFd& operator=(decltype(nullptr)) { + AutoCloseFd old(kj::mv(*this)); + return *this; + } + + inline operator int() const { return fd; } + inline int get() const { return fd; } + + operator bool() const = delete; + // Deleting this operator prevents accidental use in boolean contexts, which + // the int conversion operator above would otherwise allow. + + inline bool operator==(decltype(nullptr)) { return fd < 0; } + inline bool operator!=(decltype(nullptr)) { return fd >= 0; } + +private: + int fd; + UnwindDetector unwindDetector; +}; + +inline auto KJ_STRINGIFY(const AutoCloseFd& fd) + -> decltype(kj::toCharSequence(implicitCast(fd))) { + return kj::toCharSequence(implicitCast(fd)); +} + +class FdInputStream: public InputStream { + // An InputStream wrapping a file descriptor. + +public: + explicit FdInputStream(int fd): fd(fd) {} + explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} + KJ_DISALLOW_COPY(FdInputStream); + ~FdInputStream() noexcept(false); + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + + inline int getFd() const { return fd; } + +private: + int fd; + AutoCloseFd autoclose; +}; + +class FdOutputStream: public OutputStream { + // An OutputStream wrapping a file descriptor. + +public: + explicit FdOutputStream(int fd): fd(fd) {} + explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} + KJ_DISALLOW_COPY(FdOutputStream); + ~FdOutputStream() noexcept(false); + + void write(const void* buffer, size_t size) override; + void write(ArrayPtr> pieces) override; + + inline int getFd() const { return fd; } + +private: + int fd; + AutoCloseFd autoclose; +}; + +// ======================================================================================= +// Win32 Handle I/O + +#ifdef _WIN32 + +class AutoCloseHandle { + // A wrapper around a Win32 HANDLE which automatically closes the handle when destroyed. + // The wrapper supports move construction for transferring ownership of the handle. If + // CloseHandle() returns an error, the destructor throws an exception, UNLESS the destructor is + // being called during unwind from another exception, in which case the close error is ignored. + // + // If your code is not exception-safe, you should not use AutoCloseHandle. In this case you will + // have to call close() yourself and handle errors appropriately. + +public: + inline AutoCloseHandle(): handle((void*)-1) {} + inline AutoCloseHandle(decltype(nullptr)): handle((void*)-1) {} + inline explicit AutoCloseHandle(void* handle): handle(handle) {} + inline AutoCloseHandle(AutoCloseHandle&& other) noexcept: handle(other.handle) { + other.handle = (void*)-1; + } + KJ_DISALLOW_COPY(AutoCloseHandle); + ~AutoCloseHandle() noexcept(false); + + inline AutoCloseHandle& operator=(AutoCloseHandle&& other) { + AutoCloseHandle old(kj::mv(*this)); + handle = other.handle; + other.handle = (void*)-1; + return *this; + } + + inline AutoCloseHandle& operator=(decltype(nullptr)) { + AutoCloseHandle old(kj::mv(*this)); + return *this; + } + + inline operator void*() const { return handle; } + inline void* get() const { return handle; } + + operator bool() const = delete; + // Deleting this operator prevents accidental use in boolean contexts, which + // the void* conversion operator above would otherwise allow. + + inline bool operator==(decltype(nullptr)) { return handle != (void*)-1; } + inline bool operator!=(decltype(nullptr)) { return handle == (void*)-1; } + +private: + void* handle; // -1 (aka INVALID_HANDLE_VALUE) if not valid. +}; + +class HandleInputStream: public InputStream { + // An InputStream wrapping a Win32 HANDLE. + +public: + explicit HandleInputStream(void* handle): handle(handle) {} + explicit HandleInputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {} + KJ_DISALLOW_COPY(HandleInputStream); + ~HandleInputStream() noexcept(false); + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + +private: + void* handle; + AutoCloseHandle autoclose; +}; + +class HandleOutputStream: public OutputStream { + // An OutputStream wrapping a Win32 HANDLE. + +public: + explicit HandleOutputStream(void* handle): handle(handle) {} + explicit HandleOutputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {} + KJ_DISALLOW_COPY(HandleOutputStream); + ~HandleOutputStream() noexcept(false); + + void write(const void* buffer, size_t size) override; + +private: + void* handle; + AutoCloseHandle autoclose; +}; + +#endif // _WIN32 + +} // namespace kj + +#endif // KJ_IO_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/main.h --- a/osx/include/kj/main.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/main.h Mon May 22 10:01:37 2017 +0100 @@ -1,407 +1,407 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_MAIN_H_ -#define KJ_MAIN_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "array.h" -#include "string.h" -#include "vector.h" -#include "function.h" - -namespace kj { - -class ProcessContext { - // Context for command-line programs. - -public: - virtual StringPtr getProgramName() = 0; - // Get argv[0] as passed to main(). - - KJ_NORETURN(virtual void exit()) = 0; - // Indicates program completion. The program is considered successful unless `error()` was - // called. Typically this exits with _Exit(), meaning that the stack is not unwound, buffers - // are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that - // matter. However, an alternate context implementation e.g. for unit testing purposes could - // choose to throw an exception instead. - // - // At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if - // you lose data? However, it turns out that if you look at each common class of program, _Exit() - // is almost always preferable. Let's break it down: - // - // * Commands: A typical program you might run from the command line is single-threaded and - // exits quickly and deterministically. Commands often use buffered I/O and need to flush - // those buffers before exit. However, most of the work performed by destructors is not - // flushing buffers, but rather freeing up memory, placing objects into freelists, and closing - // file descriptors. All of this is irrelevant if the process is about to exit anyway, and - // for a command that runs quickly, time wasted freeing heap space may make a real difference - // in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what - // resources need to be flushed before exit, and easy to tell if they are not being flushed - // (because the command fails to produce the expected output). Therefore, it is reasonably - // easy for commands to explicitly ensure all output is flushed before exiting, and it is - // probably a good idea for them to do so anyway, because write failures should be detected - // and handled. For commands, a good strategy is to allocate any objects that require clean - // destruction on the stack, and allow them to go out of scope before the command exits. - // Meanwhile, any resources which do not need to be cleaned up should be allocated as members - // of the command's main class, whose destructor normally will not be called. - // - // * Interactive apps: Programs that interact with the user (whether they be graphical apps - // with windows or console-based apps like emacs) generally exit only when the user asks them - // to. Such applications may store large data structures in memory which need to be synced - // to disk, such as documents or user preferences. However, relying on stack unwind or global - // destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of - // all, it's 2013, and applications ought to be actively syncing changes to non-volatile - // storage the moment those changes are made. Applications can crash at any time and a crash - // should never lose data that is more than half a second old. Meanwhile, if a user actually - // does try to close an application while unsaved changes exist, the application UI should - // prompt the user to decide what to do. Such a UI mechanism is obviously too high level to - // be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here. - // - // * Servers: A good server is fault-tolerant, prepared for the possibility that at any time - // it could crash, the OS could decide to kill it off, or the machine it is running on could - // just die. So, using _Exit() should be no problem. In fact, servers generally never even - // call exit anyway; they are killed externally. - // - // * Batch jobs: A long-running batch job is something between a command and a server. It - // probably knows exactly what needs to be flushed before exiting, and it probably should be - // fault-tolerant. - // - // Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of - // _Exit() shouldn't be a problem anyway: - // - // * KJ style forbids global mutable state (singletons) in general and global constructors and - // destructors in particular. Therefore, everything that could possibly need cleanup either - // lives on the stack or is transitively owned by something living on the stack. - // - // * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you - // have resources that require cleanup before exit, make sure they are owned by stack frames - // beyond the one that eventually calls exit(). To be as safe as possible, don't place any - // state in your program's main class, and don't call exit() yourself. Then, runMainAndExit() - // will do it, and the only thing on the stack at that time will be your main class, which - // has no state anyway. - // - // TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is - // available for those who really think they need it. Unfortunately, it is not yet available - // on many platforms. - - virtual void warning(StringPtr message) = 0; - // Print the given message to standard error. A newline is printed after the message if it - // doesn't already have one. - - virtual void error(StringPtr message) = 0; - // Like `warning()`, but also sets a flag indicating that the process has failed, and that when - // it eventually exits it should indicate an error status. - - KJ_NORETURN(virtual void exitError(StringPtr message)) = 0; - // Equivalent to `error(message)` followed by `exit()`. - - KJ_NORETURN(virtual void exitInfo(StringPtr message)) = 0; - // Displays the given non-error message to the user and then calls `exit()`. This is used to - // implement things like --help. - - virtual void increaseLoggingVerbosity() = 0; - // Increase the level of detail produced by the debug logging system. `MainBuilder` invokes - // this if the caller uses the -v flag. - - // TODO(someday): Add interfaces representing standard OS resources like the filesystem, so that - // these things can be mocked out. -}; - -class TopLevelProcessContext final: public ProcessContext { - // A ProcessContext implementation appropriate for use at the actual entry point of a process - // (as opposed to when you are trying to call a program's main function from within some other - // program). This implementation writes errors to stderr, and its `exit()` method actually - // calls the C `quick_exit()` function. - -public: - explicit TopLevelProcessContext(StringPtr programName); - - struct CleanShutdownException { int exitCode; }; - // If the environment variable KJ_CLEAN_SHUTDOWN is set, then exit() will actually throw this - // exception rather than exiting. `kj::runMain()` catches this exception and returns normally. - // This is useful primarily for testing purposes, to assist tools like memory leak checkers that - // are easily confused by quick_exit(). - - StringPtr getProgramName() override; - KJ_NORETURN(void exit() override); - void warning(StringPtr message) override; - void error(StringPtr message) override; - KJ_NORETURN(void exitError(StringPtr message) override); - KJ_NORETURN(void exitInfo(StringPtr message) override); - void increaseLoggingVerbosity() override; - -private: - StringPtr programName; - bool cleanShutdown; - bool hadErrors = false; -}; - -typedef Function params)> MainFunc; - -int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]); -// Runs the given main function and then exits using the given context. If an exception is thrown, -// this will catch it, report it via the context and exit with an error code. -// -// Normally this function does not return, because returning would probably lead to wasting time -// on cleanup when the process is just going to exit anyway. However, to facilitate memory leak -// checkers and other tools that require a clean shutdown to do their job, if the environment -// variable KJ_CLEAN_SHUTDOWN is set, the function will in fact return an exit code, which should -// then be returned from main(). -// -// Most users will use the KJ_MAIN() macro rather than call this function directly. - -#define KJ_MAIN(MainClass) \ - int main(int argc, char* argv[]) { \ - ::kj::TopLevelProcessContext context(argv[0]); \ - MainClass mainObject(context); \ - return ::kj::runMainAndExit(context, mainObject.getMain(), argc, argv); \ - } -// Convenience macro for declaring a main function based on the given class. The class must have -// a constructor that accepts a ProcessContext& and a method getMain() which returns -// kj::MainFunc (probably building it using a MainBuilder). - -class MainBuilder { - // Builds a main() function with nice argument parsing. As options and arguments are parsed, - // corresponding callbacks are called, so that you never have to write a massive switch() - // statement to interpret arguments. Additionally, this approach encourages you to write - // main classes that have a reasonable API that can be used as an alternative to their - // command-line interface. - // - // All StringPtrs passed to MainBuilder must remain valid until option parsing completes. The - // assumption is that these strings will all be literals, making this an easy requirement. If - // not, consider allocating them in an Arena. - // - // Some flags are automatically recognized by the main functions built by this class: - // --help: Prints help text and exits. The help text is constructed based on the - // information you provide to the builder as you define each flag. - // --verbose: Increase logging verbosity. - // --version: Print version information and exit. - // - // Example usage: - // - // class FooMain { - // public: - // FooMain(kj::ProcessContext& context): context(context) {} - // - // bool setAll() { all = true; return true; } - // // Enable the --all flag. - // - // kj::MainBuilder::Validity setOutput(kj::StringPtr name) { - // // Set the output file. - // - // if (name.endsWith(".foo")) { - // outputFile = name; - // return true; - // } else { - // return "Output file must have extension .foo."; - // } - // } - // - // kj::MainBuilder::Validity processInput(kj::StringPtr name) { - // // Process an input file. - // - // if (!exists(name)) { - // return kj::str(name, ": file not found"); - // } - // // ... process the input file ... - // return true; - // } - // - // kj::MainFunc getMain() { - // return MainBuilder(context, "Foo Builder v1.5", "Reads s and builds a Foo.") - // .addOption({'a', "all"}, KJ_BIND_METHOD(*this, setAll), - // "Frob all the widgets. Otherwise, only some widgets are frobbed.") - // .addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput), - // "", "Output to . Must be a .foo file.") - // .expectOneOrMoreArgs("", KJ_BIND_METHOD(*this, processInput)) - // .build(); - // } - // - // private: - // bool all = false; - // kj::StringPtr outputFile; - // kj::ProcessContext& context; - // }; - -public: - MainBuilder(ProcessContext& context, StringPtr version, - StringPtr briefDescription, StringPtr extendedDescription = nullptr); - ~MainBuilder() noexcept(false); - - class OptionName { - public: - OptionName() = default; - inline OptionName(char shortName): isLong(false), shortName(shortName) {} - inline OptionName(const char* longName): isLong(true), longName(longName) {} - - private: - bool isLong; - union { - char shortName; - const char* longName; - }; - friend class MainBuilder; - }; - - class Validity { - public: - inline Validity(bool valid) { - if (!valid) errorMessage = heapString("invalid argument"); - } - inline Validity(const char* errorMessage) - : errorMessage(heapString(errorMessage)) {} - inline Validity(String&& errorMessage) - : errorMessage(kj::mv(errorMessage)) {} - - inline const Maybe& getError() const { return errorMessage; } - inline Maybe releaseError() { return kj::mv(errorMessage); } - - private: - Maybe errorMessage; - friend class MainBuilder; - }; - - MainBuilder& addOption(std::initializer_list names, Function callback, - StringPtr helpText); - // Defines a new option (flag). `names` is a list of characters and strings that can be used to - // specify the option on the command line. Single-character names are used with "-" while string - // names are used with "--". `helpText` is a natural-language description of the flag. - // - // `callback` is called when the option is seen. Its return value indicates whether the option - // was accepted. If not, further option processing stops, and error is written, and the process - // exits. - // - // Example: - // - // builder.addOption({'a', "all"}, KJ_BIND_METHOD(*this, showAll), "Show all files."); - // - // This option could be specified in the following ways: - // - // -a - // --all - // - // Note that single-character option names can be combined into a single argument. For example, - // `-abcd` is equivalent to `-a -b -c -d`. - // - // The help text for this option would look like: - // - // -a, --all - // Show all files. - // - // Note that help text is automatically word-wrapped. - - MainBuilder& addOptionWithArg(std::initializer_list names, - Function callback, - StringPtr argumentTitle, StringPtr helpText); - // Like `addOption()`, but adds an option which accepts an argument. `argumentTitle` is used in - // the help text. The argument text is passed to the callback. - // - // Example: - // - // builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput), - // "", "Output to ."); - // - // This option could be specified with an argument of "foo" in the following ways: - // - // -ofoo - // -o foo - // --output=foo - // --output foo - // - // Note that single-character option names can be combined, but only the last option can have an - // argument, since the characters after the option letter are interpreted as the argument. E.g. - // `-abofoo` would be equivalent to `-a -b -o foo`. - // - // The help text for this option would look like: - // - // -o FILENAME, --output=FILENAME - // Output to FILENAME. - - MainBuilder& addSubCommand(StringPtr name, Function getSubParser, - StringPtr briefHelpText); - // If exactly the given name is seen as an argument, invoke getSubParser() and then pass all - // remaining arguments to the parser it returns. This is useful for implementing commands which - // have lots of sub-commands, like "git" (which has sub-commands "checkout", "branch", "pull", - // etc.). - // - // `getSubParser` is only called if the command is seen. This avoids building main functions - // for commands that aren't used. - // - // `briefHelpText` should be brief enough to show immediately after the command name on a single - // line. It will not be wrapped. Users can use the built-in "help" command to get extended - // help on a particular command. - - MainBuilder& expectArg(StringPtr title, Function callback); - MainBuilder& expectOptionalArg(StringPtr title, Function callback); - MainBuilder& expectZeroOrMoreArgs(StringPtr title, Function callback); - MainBuilder& expectOneOrMoreArgs(StringPtr title, Function callback); - // Set callbacks to handle arguments. `expectArg()` and `expectOptionalArg()` specify positional - // arguments with special handling, while `expect{Zero,One}OrMoreArgs()` specifies a handler for - // an argument list (the handler is called once for each argument in the list). `title` - // specifies how the argument should be represented in the usage text. - // - // All options callbacks are called before argument callbacks, regardless of their ordering on - // the command line. This matches GNU getopt's behavior of permuting non-flag arguments to the - // end of the argument list. Also matching getopt, the special option "--" indicates that the - // rest of the command line is all arguments, not options, even if they start with '-'. - // - // The interpretation of positional arguments is fairly flexible. The non-optional arguments can - // be expected at the beginning, end, or in the middle. If more arguments are specified than - // the number of non-optional args, they are assigned to the optional argument handlers in the - // order of registration. - // - // For example, say you called: - // builder.expectArg("", ...); - // builder.expectOptionalArg("", ...); - // builder.expectArg("", ...); - // builder.expectZeroOrMoreArgs("", ...); - // builder.expectArg("", ...); - // - // This command requires at least three arguments: foo, baz, and corge. If four arguments are - // given, the second is assigned to bar. If five or more arguments are specified, then the - // arguments between the third and last are assigned to qux. Note that it never makes sense - // to call `expect*OrMoreArgs()` more than once since only the first call would ever be used. - // - // In practice, you probably shouldn't create such complicated commands as in the above example. - // But, this flexibility seems necessary to support commands where the first argument is special - // as well as commands (like `cp`) where the last argument is special. - - MainBuilder& callAfterParsing(Function callback); - // Call the given function after all arguments have been parsed. - - MainFunc build(); - // Build the "main" function, which simply parses the arguments. Once this returns, the - // `MainBuilder` is no longer valid. - -private: - struct Impl; - Own impl; - - class MainImpl; -}; - -} // namespace kj - -#endif // KJ_MAIN_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_MAIN_H_ +#define KJ_MAIN_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "array.h" +#include "string.h" +#include "vector.h" +#include "function.h" + +namespace kj { + +class ProcessContext { + // Context for command-line programs. + +public: + virtual StringPtr getProgramName() = 0; + // Get argv[0] as passed to main(). + + KJ_NORETURN(virtual void exit()) = 0; + // Indicates program completion. The program is considered successful unless `error()` was + // called. Typically this exits with _Exit(), meaning that the stack is not unwound, buffers + // are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that + // matter. However, an alternate context implementation e.g. for unit testing purposes could + // choose to throw an exception instead. + // + // At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if + // you lose data? However, it turns out that if you look at each common class of program, _Exit() + // is almost always preferable. Let's break it down: + // + // * Commands: A typical program you might run from the command line is single-threaded and + // exits quickly and deterministically. Commands often use buffered I/O and need to flush + // those buffers before exit. However, most of the work performed by destructors is not + // flushing buffers, but rather freeing up memory, placing objects into freelists, and closing + // file descriptors. All of this is irrelevant if the process is about to exit anyway, and + // for a command that runs quickly, time wasted freeing heap space may make a real difference + // in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what + // resources need to be flushed before exit, and easy to tell if they are not being flushed + // (because the command fails to produce the expected output). Therefore, it is reasonably + // easy for commands to explicitly ensure all output is flushed before exiting, and it is + // probably a good idea for them to do so anyway, because write failures should be detected + // and handled. For commands, a good strategy is to allocate any objects that require clean + // destruction on the stack, and allow them to go out of scope before the command exits. + // Meanwhile, any resources which do not need to be cleaned up should be allocated as members + // of the command's main class, whose destructor normally will not be called. + // + // * Interactive apps: Programs that interact with the user (whether they be graphical apps + // with windows or console-based apps like emacs) generally exit only when the user asks them + // to. Such applications may store large data structures in memory which need to be synced + // to disk, such as documents or user preferences. However, relying on stack unwind or global + // destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of + // all, it's 2013, and applications ought to be actively syncing changes to non-volatile + // storage the moment those changes are made. Applications can crash at any time and a crash + // should never lose data that is more than half a second old. Meanwhile, if a user actually + // does try to close an application while unsaved changes exist, the application UI should + // prompt the user to decide what to do. Such a UI mechanism is obviously too high level to + // be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here. + // + // * Servers: A good server is fault-tolerant, prepared for the possibility that at any time + // it could crash, the OS could decide to kill it off, or the machine it is running on could + // just die. So, using _Exit() should be no problem. In fact, servers generally never even + // call exit anyway; they are killed externally. + // + // * Batch jobs: A long-running batch job is something between a command and a server. It + // probably knows exactly what needs to be flushed before exiting, and it probably should be + // fault-tolerant. + // + // Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of + // _Exit() shouldn't be a problem anyway: + // + // * KJ style forbids global mutable state (singletons) in general and global constructors and + // destructors in particular. Therefore, everything that could possibly need cleanup either + // lives on the stack or is transitively owned by something living on the stack. + // + // * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you + // have resources that require cleanup before exit, make sure they are owned by stack frames + // beyond the one that eventually calls exit(). To be as safe as possible, don't place any + // state in your program's main class, and don't call exit() yourself. Then, runMainAndExit() + // will do it, and the only thing on the stack at that time will be your main class, which + // has no state anyway. + // + // TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is + // available for those who really think they need it. Unfortunately, it is not yet available + // on many platforms. + + virtual void warning(StringPtr message) = 0; + // Print the given message to standard error. A newline is printed after the message if it + // doesn't already have one. + + virtual void error(StringPtr message) = 0; + // Like `warning()`, but also sets a flag indicating that the process has failed, and that when + // it eventually exits it should indicate an error status. + + KJ_NORETURN(virtual void exitError(StringPtr message)) = 0; + // Equivalent to `error(message)` followed by `exit()`. + + KJ_NORETURN(virtual void exitInfo(StringPtr message)) = 0; + // Displays the given non-error message to the user and then calls `exit()`. This is used to + // implement things like --help. + + virtual void increaseLoggingVerbosity() = 0; + // Increase the level of detail produced by the debug logging system. `MainBuilder` invokes + // this if the caller uses the -v flag. + + // TODO(someday): Add interfaces representing standard OS resources like the filesystem, so that + // these things can be mocked out. +}; + +class TopLevelProcessContext final: public ProcessContext { + // A ProcessContext implementation appropriate for use at the actual entry point of a process + // (as opposed to when you are trying to call a program's main function from within some other + // program). This implementation writes errors to stderr, and its `exit()` method actually + // calls the C `quick_exit()` function. + +public: + explicit TopLevelProcessContext(StringPtr programName); + + struct CleanShutdownException { int exitCode; }; + // If the environment variable KJ_CLEAN_SHUTDOWN is set, then exit() will actually throw this + // exception rather than exiting. `kj::runMain()` catches this exception and returns normally. + // This is useful primarily for testing purposes, to assist tools like memory leak checkers that + // are easily confused by quick_exit(). + + StringPtr getProgramName() override; + KJ_NORETURN(void exit() override); + void warning(StringPtr message) override; + void error(StringPtr message) override; + KJ_NORETURN(void exitError(StringPtr message) override); + KJ_NORETURN(void exitInfo(StringPtr message) override); + void increaseLoggingVerbosity() override; + +private: + StringPtr programName; + bool cleanShutdown; + bool hadErrors = false; +}; + +typedef Function params)> MainFunc; + +int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]); +// Runs the given main function and then exits using the given context. If an exception is thrown, +// this will catch it, report it via the context and exit with an error code. +// +// Normally this function does not return, because returning would probably lead to wasting time +// on cleanup when the process is just going to exit anyway. However, to facilitate memory leak +// checkers and other tools that require a clean shutdown to do their job, if the environment +// variable KJ_CLEAN_SHUTDOWN is set, the function will in fact return an exit code, which should +// then be returned from main(). +// +// Most users will use the KJ_MAIN() macro rather than call this function directly. + +#define KJ_MAIN(MainClass) \ + int main(int argc, char* argv[]) { \ + ::kj::TopLevelProcessContext context(argv[0]); \ + MainClass mainObject(context); \ + return ::kj::runMainAndExit(context, mainObject.getMain(), argc, argv); \ + } +// Convenience macro for declaring a main function based on the given class. The class must have +// a constructor that accepts a ProcessContext& and a method getMain() which returns +// kj::MainFunc (probably building it using a MainBuilder). + +class MainBuilder { + // Builds a main() function with nice argument parsing. As options and arguments are parsed, + // corresponding callbacks are called, so that you never have to write a massive switch() + // statement to interpret arguments. Additionally, this approach encourages you to write + // main classes that have a reasonable API that can be used as an alternative to their + // command-line interface. + // + // All StringPtrs passed to MainBuilder must remain valid until option parsing completes. The + // assumption is that these strings will all be literals, making this an easy requirement. If + // not, consider allocating them in an Arena. + // + // Some flags are automatically recognized by the main functions built by this class: + // --help: Prints help text and exits. The help text is constructed based on the + // information you provide to the builder as you define each flag. + // --verbose: Increase logging verbosity. + // --version: Print version information and exit. + // + // Example usage: + // + // class FooMain { + // public: + // FooMain(kj::ProcessContext& context): context(context) {} + // + // bool setAll() { all = true; return true; } + // // Enable the --all flag. + // + // kj::MainBuilder::Validity setOutput(kj::StringPtr name) { + // // Set the output file. + // + // if (name.endsWith(".foo")) { + // outputFile = name; + // return true; + // } else { + // return "Output file must have extension .foo."; + // } + // } + // + // kj::MainBuilder::Validity processInput(kj::StringPtr name) { + // // Process an input file. + // + // if (!exists(name)) { + // return kj::str(name, ": file not found"); + // } + // // ... process the input file ... + // return true; + // } + // + // kj::MainFunc getMain() { + // return MainBuilder(context, "Foo Builder v1.5", "Reads s and builds a Foo.") + // .addOption({'a', "all"}, KJ_BIND_METHOD(*this, setAll), + // "Frob all the widgets. Otherwise, only some widgets are frobbed.") + // .addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput), + // "", "Output to . Must be a .foo file.") + // .expectOneOrMoreArgs("", KJ_BIND_METHOD(*this, processInput)) + // .build(); + // } + // + // private: + // bool all = false; + // kj::StringPtr outputFile; + // kj::ProcessContext& context; + // }; + +public: + MainBuilder(ProcessContext& context, StringPtr version, + StringPtr briefDescription, StringPtr extendedDescription = nullptr); + ~MainBuilder() noexcept(false); + + class OptionName { + public: + OptionName() = default; + inline OptionName(char shortName): isLong(false), shortName(shortName) {} + inline OptionName(const char* longName): isLong(true), longName(longName) {} + + private: + bool isLong; + union { + char shortName; + const char* longName; + }; + friend class MainBuilder; + }; + + class Validity { + public: + inline Validity(bool valid) { + if (!valid) errorMessage = heapString("invalid argument"); + } + inline Validity(const char* errorMessage) + : errorMessage(heapString(errorMessage)) {} + inline Validity(String&& errorMessage) + : errorMessage(kj::mv(errorMessage)) {} + + inline const Maybe& getError() const { return errorMessage; } + inline Maybe releaseError() { return kj::mv(errorMessage); } + + private: + Maybe errorMessage; + friend class MainBuilder; + }; + + MainBuilder& addOption(std::initializer_list names, Function callback, + StringPtr helpText); + // Defines a new option (flag). `names` is a list of characters and strings that can be used to + // specify the option on the command line. Single-character names are used with "-" while string + // names are used with "--". `helpText` is a natural-language description of the flag. + // + // `callback` is called when the option is seen. Its return value indicates whether the option + // was accepted. If not, further option processing stops, and error is written, and the process + // exits. + // + // Example: + // + // builder.addOption({'a', "all"}, KJ_BIND_METHOD(*this, showAll), "Show all files."); + // + // This option could be specified in the following ways: + // + // -a + // --all + // + // Note that single-character option names can be combined into a single argument. For example, + // `-abcd` is equivalent to `-a -b -c -d`. + // + // The help text for this option would look like: + // + // -a, --all + // Show all files. + // + // Note that help text is automatically word-wrapped. + + MainBuilder& addOptionWithArg(std::initializer_list names, + Function callback, + StringPtr argumentTitle, StringPtr helpText); + // Like `addOption()`, but adds an option which accepts an argument. `argumentTitle` is used in + // the help text. The argument text is passed to the callback. + // + // Example: + // + // builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput), + // "", "Output to ."); + // + // This option could be specified with an argument of "foo" in the following ways: + // + // -ofoo + // -o foo + // --output=foo + // --output foo + // + // Note that single-character option names can be combined, but only the last option can have an + // argument, since the characters after the option letter are interpreted as the argument. E.g. + // `-abofoo` would be equivalent to `-a -b -o foo`. + // + // The help text for this option would look like: + // + // -o FILENAME, --output=FILENAME + // Output to FILENAME. + + MainBuilder& addSubCommand(StringPtr name, Function getSubParser, + StringPtr briefHelpText); + // If exactly the given name is seen as an argument, invoke getSubParser() and then pass all + // remaining arguments to the parser it returns. This is useful for implementing commands which + // have lots of sub-commands, like "git" (which has sub-commands "checkout", "branch", "pull", + // etc.). + // + // `getSubParser` is only called if the command is seen. This avoids building main functions + // for commands that aren't used. + // + // `briefHelpText` should be brief enough to show immediately after the command name on a single + // line. It will not be wrapped. Users can use the built-in "help" command to get extended + // help on a particular command. + + MainBuilder& expectArg(StringPtr title, Function callback); + MainBuilder& expectOptionalArg(StringPtr title, Function callback); + MainBuilder& expectZeroOrMoreArgs(StringPtr title, Function callback); + MainBuilder& expectOneOrMoreArgs(StringPtr title, Function callback); + // Set callbacks to handle arguments. `expectArg()` and `expectOptionalArg()` specify positional + // arguments with special handling, while `expect{Zero,One}OrMoreArgs()` specifies a handler for + // an argument list (the handler is called once for each argument in the list). `title` + // specifies how the argument should be represented in the usage text. + // + // All options callbacks are called before argument callbacks, regardless of their ordering on + // the command line. This matches GNU getopt's behavior of permuting non-flag arguments to the + // end of the argument list. Also matching getopt, the special option "--" indicates that the + // rest of the command line is all arguments, not options, even if they start with '-'. + // + // The interpretation of positional arguments is fairly flexible. The non-optional arguments can + // be expected at the beginning, end, or in the middle. If more arguments are specified than + // the number of non-optional args, they are assigned to the optional argument handlers in the + // order of registration. + // + // For example, say you called: + // builder.expectArg("", ...); + // builder.expectOptionalArg("", ...); + // builder.expectArg("", ...); + // builder.expectZeroOrMoreArgs("", ...); + // builder.expectArg("", ...); + // + // This command requires at least three arguments: foo, baz, and corge. If four arguments are + // given, the second is assigned to bar. If five or more arguments are specified, then the + // arguments between the third and last are assigned to qux. Note that it never makes sense + // to call `expect*OrMoreArgs()` more than once since only the first call would ever be used. + // + // In practice, you probably shouldn't create such complicated commands as in the above example. + // But, this flexibility seems necessary to support commands where the first argument is special + // as well as commands (like `cp`) where the last argument is special. + + MainBuilder& callAfterParsing(Function callback); + // Call the given function after all arguments have been parsed. + + MainFunc build(); + // Build the "main" function, which simply parses the arguments. Once this returns, the + // `MainBuilder` is no longer valid. + +private: + struct Impl; + Own impl; + + class MainImpl; +}; + +} // namespace kj + +#endif // KJ_MAIN_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/memory.h --- a/osx/include/kj/memory.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/memory.h Mon May 22 10:01:37 2017 +0100 @@ -1,404 +1,406 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_MEMORY_H_ -#define KJ_MEMORY_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" - -namespace kj { - -// ======================================================================================= -// Disposer -- Implementation details. - -class Disposer { - // Abstract interface for a thing that "disposes" of objects, where "disposing" usually means - // calling the destructor followed by freeing the underlying memory. `Own` encapsulates an - // object pointer with corresponding Disposer. - // - // Few developers will ever touch this interface. It is primarily useful for those implementing - // custom memory allocators. - -protected: - // Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer - // instance. Eww! - - virtual void disposeImpl(void* pointer) const = 0; - // Disposes of the object, given a pointer to the beginning of the object. If the object is - // polymorphic, this pointer is determined by dynamic_cast(). For non-polymorphic types, - // Own does not allow any casting, so the pointer exactly matches the original one given to - // Own. - -public: - - template - void dispose(T* object) const; - // Helper wrapper around disposeImpl(). - // - // If T is polymorphic, calls `disposeImpl(dynamic_cast(object))`, otherwise calls - // `disposeImpl(implicitCast(object))`. - // - // Callers must not call dispose() on the same pointer twice, even if the first call throws - // an exception. - -private: - template - struct Dispose_; -}; - -template -class DestructorOnlyDisposer: public Disposer { - // A disposer that merely calls the type's destructor and nothing else. - -public: - static const DestructorOnlyDisposer instance; - - void disposeImpl(void* pointer) const override { - reinterpret_cast(pointer)->~T(); - } -}; - -template -const DestructorOnlyDisposer DestructorOnlyDisposer::instance = DestructorOnlyDisposer(); - -class NullDisposer: public Disposer { - // A disposer that does nothing. - -public: - static const NullDisposer instance; - - void disposeImpl(void* pointer) const override {} -}; - -// ======================================================================================= -// Own -- An owned pointer. - -template -class Own { - // A transferrable title to a T. When an Own goes out of scope, the object's Disposer is - // called to dispose of it. An Own can be efficiently passed by move, without relocating the - // underlying object; this transfers ownership. - // - // This is much like std::unique_ptr, except: - // - You cannot release(). An owned object is not necessarily allocated with new (see next - // point), so it would be hard to use release() correctly. - // - The deleter is made polymorphic by virtual call rather than by template. This is much - // more powerful -- it allows the use of custom allocators, freelists, etc. This could - // _almost_ be accomplished with unique_ptr by forcing everyone to use something like - // std::unique_ptr, except that things get hairy in the presence of multiple - // inheritance and upcasting, and anyway if you force everyone to use a custom deleter - // then you've lost any benefit to interoperating with the "standard" unique_ptr. - -public: - KJ_DISALLOW_COPY(Own); - inline Own(): disposer(nullptr), ptr(nullptr) {} - inline Own(Own&& other) noexcept - : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } - inline Own(Own>&& other) noexcept - : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } - template ()>> - inline Own(Own&& other) noexcept - : disposer(other.disposer), ptr(other.ptr) { - static_assert(__is_polymorphic(T), - "Casting owned pointers requires that the target type is polymorphic."); - other.ptr = nullptr; - } - inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {} - - ~Own() noexcept(false) { dispose(); } - - inline Own& operator=(Own&& other) { - // Move-assingnment operator. - - // Careful, this might own `other`. Therefore we have to transfer the pointers first, then - // dispose. - const Disposer* disposerCopy = disposer; - T* ptrCopy = ptr; - disposer = other.disposer; - ptr = other.ptr; - other.ptr = nullptr; - if (ptrCopy != nullptr) { - disposerCopy->dispose(const_cast*>(ptrCopy)); - } - return *this; - } - - inline Own& operator=(decltype(nullptr)) { - dispose(); - return *this; - } - - template - Own downcast() { - // Downcast the pointer to Own, destroying the original pointer. If this pointer does not - // actually point at an instance of U, the results are undefined (throws an exception in debug - // mode if RTTI is enabled, otherwise you're on your own). - - Own result; - if (ptr != nullptr) { - result.ptr = &kj::downcast(*ptr); - result.disposer = disposer; - ptr = nullptr; - } - return result; - } - -#define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") - inline T* operator->() { NULLCHECK; return ptr; } - inline const T* operator->() const { NULLCHECK; return ptr; } - inline T& operator*() { NULLCHECK; return *ptr; } - inline const T& operator*() const { NULLCHECK; return *ptr; } -#undef NULLCHECK - inline T* get() { return ptr; } - inline const T* get() const { return ptr; } - inline operator T*() { return ptr; } - inline operator const T*() const { return ptr; } - -private: - const Disposer* disposer; // Only valid if ptr != nullptr. - T* ptr; - - inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {} - - inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } - inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } - // Only called by Maybe>. - - inline void dispose() { - // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly - // dispose again. - T* ptrCopy = ptr; - if (ptrCopy != nullptr) { - ptr = nullptr; - disposer->dispose(const_cast*>(ptrCopy)); - } - } - - template - friend class Own; - friend class Maybe>; -}; - -namespace _ { // private - -template -class OwnOwn { -public: - inline OwnOwn(Own&& value) noexcept: value(kj::mv(value)) {} - - inline Own& operator*() & { return value; } - inline const Own& operator*() const & { return value; } - inline Own&& operator*() && { return kj::mv(value); } - inline const Own&& operator*() const && { return kj::mv(value); } - inline Own* operator->() { return &value; } - inline const Own* operator->() const { return &value; } - inline operator Own*() { return value ? &value : nullptr; } - inline operator const Own*() const { return value ? &value : nullptr; } - -private: - Own value; -}; - -template -OwnOwn readMaybe(Maybe>&& maybe) { return OwnOwn(kj::mv(maybe.ptr)); } -template -Own* readMaybe(Maybe>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } -template -const Own* readMaybe(const Maybe>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } - -} // namespace _ (private) - -template -class Maybe> { -public: - inline Maybe(): ptr(nullptr) {} - inline Maybe(Own&& t) noexcept: ptr(kj::mv(t)) {} - inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {} - - template - inline Maybe(Maybe>&& other): ptr(mv(other.ptr)) {} - - inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} - - inline operator Maybe() { return ptr.get(); } - inline operator Maybe() const { return ptr.get(); } - - inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } - - inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } - inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } - - Own& orDefault(Own& defaultValue) { - if (ptr == nullptr) { - return defaultValue; - } else { - return ptr; - } - } - const Own& orDefault(const Own& defaultValue) const { - if (ptr == nullptr) { - return defaultValue; - } else { - return ptr; - } - } - - template - auto map(Func&& f) & -> Maybe&>()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(ptr); - } - } - - template - auto map(Func&& f) const & -> Maybe&>()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(ptr); - } - } - - template - auto map(Func&& f) && -> Maybe&&>()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(kj::mv(ptr)); - } - } - - template - auto map(Func&& f) const && -> Maybe&&>()))> { - if (ptr == nullptr) { - return nullptr; - } else { - return f(kj::mv(ptr)); - } - } - -private: - Own ptr; - - template - friend class Maybe; - template - friend _::OwnOwn _::readMaybe(Maybe>&& maybe); - template - friend Own* _::readMaybe(Maybe>& maybe); - template - friend const Own* _::readMaybe(const Maybe>& maybe); -}; - -namespace _ { // private - -template -class HeapDisposer final: public Disposer { -public: - virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast(pointer); } - - static const HeapDisposer instance; -}; - -template -const HeapDisposer HeapDisposer::instance = HeapDisposer(); - -} // namespace _ (private) - -template -Own heap(Params&&... params) { - // heap(...) allocates a T on the heap, forwarding the parameters to its constructor. The - // exact heap implementation is unspecified -- for now it is operator new, but you should not - // assume this. (Since we know the object size at delete time, we could actually implement an - // allocator that is more efficient than operator new.) - - return Own(new T(kj::fwd(params)...), _::HeapDisposer::instance); -} - -template -Own> heap(T&& orig) { - // Allocate a copy (or move) of the argument on the heap. - // - // The purpose of this overload is to allow you to omit the template parameter as there is only - // one argument and the purpose is to copy it. - - typedef Decay T2; - return Own(new T2(kj::fwd(orig)), _::HeapDisposer::instance); -} - -// ======================================================================================= -// SpaceFor -- assists in manual allocation - -template -class SpaceFor { - // A class which has the same size and alignment as T but does not call its constructor or - // destructor automatically. Instead, call construct() to construct a T in the space, which - // returns an Own which will take care of calling T's destructor later. - -public: - inline SpaceFor() {} - inline ~SpaceFor() {} - - template - Own construct(Params&&... params) { - ctor(value, kj::fwd(params)...); - return Own(&value, DestructorOnlyDisposer::instance); - } - -private: - union { - T value; - }; -}; - -// ======================================================================================= -// Inline implementation details - -template -struct Disposer::Dispose_ { - static void dispose(T* object, const Disposer& disposer) { - // Note that dynamic_cast does not require RTTI to be enabled, because the offset to - // the top of the object is in the vtable -- as it obviously needs to be to correctly implement - // operator delete. - disposer.disposeImpl(dynamic_cast(object)); - } -}; -template -struct Disposer::Dispose_ { - static void dispose(T* object, const Disposer& disposer) { - disposer.disposeImpl(static_cast(object)); - } -}; - -template -void Disposer::dispose(T* object) const { - Dispose_::dispose(object, *this); -} - -} // namespace kj - -#endif // KJ_MEMORY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_MEMORY_H_ +#define KJ_MEMORY_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" + +namespace kj { + +// ======================================================================================= +// Disposer -- Implementation details. + +class Disposer { + // Abstract interface for a thing that "disposes" of objects, where "disposing" usually means + // calling the destructor followed by freeing the underlying memory. `Own` encapsulates an + // object pointer with corresponding Disposer. + // + // Few developers will ever touch this interface. It is primarily useful for those implementing + // custom memory allocators. + +protected: + // Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer + // instance. Eww! + + virtual void disposeImpl(void* pointer) const = 0; + // Disposes of the object, given a pointer to the beginning of the object. If the object is + // polymorphic, this pointer is determined by dynamic_cast(). For non-polymorphic types, + // Own does not allow any casting, so the pointer exactly matches the original one given to + // Own. + +public: + + template + void dispose(T* object) const; + // Helper wrapper around disposeImpl(). + // + // If T is polymorphic, calls `disposeImpl(dynamic_cast(object))`, otherwise calls + // `disposeImpl(implicitCast(object))`. + // + // Callers must not call dispose() on the same pointer twice, even if the first call throws + // an exception. + +private: + template + struct Dispose_; +}; + +template +class DestructorOnlyDisposer: public Disposer { + // A disposer that merely calls the type's destructor and nothing else. + +public: + static const DestructorOnlyDisposer instance; + + void disposeImpl(void* pointer) const override { + reinterpret_cast(pointer)->~T(); + } +}; + +template +const DestructorOnlyDisposer DestructorOnlyDisposer::instance = DestructorOnlyDisposer(); + +class NullDisposer: public Disposer { + // A disposer that does nothing. + +public: + static const NullDisposer instance; + + void disposeImpl(void* pointer) const override {} +}; + +// ======================================================================================= +// Own -- An owned pointer. + +template +class Own { + // A transferrable title to a T. When an Own goes out of scope, the object's Disposer is + // called to dispose of it. An Own can be efficiently passed by move, without relocating the + // underlying object; this transfers ownership. + // + // This is much like std::unique_ptr, except: + // - You cannot release(). An owned object is not necessarily allocated with new (see next + // point), so it would be hard to use release() correctly. + // - The deleter is made polymorphic by virtual call rather than by template. This is much + // more powerful -- it allows the use of custom allocators, freelists, etc. This could + // _almost_ be accomplished with unique_ptr by forcing everyone to use something like + // std::unique_ptr, except that things get hairy in the presence of multiple + // inheritance and upcasting, and anyway if you force everyone to use a custom deleter + // then you've lost any benefit to interoperating with the "standard" unique_ptr. + +public: + KJ_DISALLOW_COPY(Own); + inline Own(): disposer(nullptr), ptr(nullptr) {} + inline Own(Own&& other) noexcept + : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } + inline Own(Own>&& other) noexcept + : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } + template ()>> + inline Own(Own&& other) noexcept + : disposer(other.disposer), ptr(other.ptr) { + static_assert(__is_polymorphic(T), + "Casting owned pointers requires that the target type is polymorphic."); + other.ptr = nullptr; + } + inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {} + + ~Own() noexcept(false) { dispose(); } + + inline Own& operator=(Own&& other) { + // Move-assingnment operator. + + // Careful, this might own `other`. Therefore we have to transfer the pointers first, then + // dispose. + const Disposer* disposerCopy = disposer; + T* ptrCopy = ptr; + disposer = other.disposer; + ptr = other.ptr; + other.ptr = nullptr; + if (ptrCopy != nullptr) { + disposerCopy->dispose(const_cast*>(ptrCopy)); + } + return *this; + } + + inline Own& operator=(decltype(nullptr)) { + dispose(); + return *this; + } + + template + Own downcast() { + // Downcast the pointer to Own, destroying the original pointer. If this pointer does not + // actually point at an instance of U, the results are undefined (throws an exception in debug + // mode if RTTI is enabled, otherwise you're on your own). + + Own result; + if (ptr != nullptr) { + result.ptr = &kj::downcast(*ptr); + result.disposer = disposer; + ptr = nullptr; + } + return result; + } + +#define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") + inline T* operator->() { NULLCHECK; return ptr; } + inline const T* operator->() const { NULLCHECK; return ptr; } + inline T& operator*() { NULLCHECK; return *ptr; } + inline const T& operator*() const { NULLCHECK; return *ptr; } +#undef NULLCHECK + inline T* get() { return ptr; } + inline const T* get() const { return ptr; } + inline operator T*() { return ptr; } + inline operator const T*() const { return ptr; } + +private: + const Disposer* disposer; // Only valid if ptr != nullptr. + T* ptr; + + inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {} + + inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } + // Only called by Maybe>. + + inline void dispose() { + // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly + // dispose again. + T* ptrCopy = ptr; + if (ptrCopy != nullptr) { + ptr = nullptr; + disposer->dispose(const_cast*>(ptrCopy)); + } + } + + template + friend class Own; + friend class Maybe>; +}; + +namespace _ { // private + +template +class OwnOwn { +public: + inline OwnOwn(Own&& value) noexcept: value(kj::mv(value)) {} + + inline Own& operator*() & { return value; } + inline const Own& operator*() const & { return value; } + inline Own&& operator*() && { return kj::mv(value); } + inline const Own&& operator*() const && { return kj::mv(value); } + inline Own* operator->() { return &value; } + inline const Own* operator->() const { return &value; } + inline operator Own*() { return value ? &value : nullptr; } + inline operator const Own*() const { return value ? &value : nullptr; } + +private: + Own value; +}; + +template +OwnOwn readMaybe(Maybe>&& maybe) { return OwnOwn(kj::mv(maybe.ptr)); } +template +Own* readMaybe(Maybe>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } +template +const Own* readMaybe(const Maybe>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } + +} // namespace _ (private) + +template +class Maybe> { +public: + inline Maybe(): ptr(nullptr) {} + inline Maybe(Own&& t) noexcept: ptr(kj::mv(t)) {} + inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {} + + template + inline Maybe(Maybe>&& other): ptr(mv(other.ptr)) {} + template + inline Maybe(Own&& other): ptr(mv(other)) {} + + inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} + + inline operator Maybe() { return ptr.get(); } + inline operator Maybe() const { return ptr.get(); } + + inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } + + inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + Own& orDefault(Own& defaultValue) { + if (ptr == nullptr) { + return defaultValue; + } else { + return ptr; + } + } + const Own& orDefault(const Own& defaultValue) const { + if (ptr == nullptr) { + return defaultValue; + } else { + return ptr; + } + } + + template + auto map(Func&& f) & -> Maybe&>()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(ptr); + } + } + + template + auto map(Func&& f) const & -> Maybe&>()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(ptr); + } + } + + template + auto map(Func&& f) && -> Maybe&&>()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(ptr)); + } + } + + template + auto map(Func&& f) const && -> Maybe&&>()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(ptr)); + } + } + +private: + Own ptr; + + template + friend class Maybe; + template + friend _::OwnOwn _::readMaybe(Maybe>&& maybe); + template + friend Own* _::readMaybe(Maybe>& maybe); + template + friend const Own* _::readMaybe(const Maybe>& maybe); +}; + +namespace _ { // private + +template +class HeapDisposer final: public Disposer { +public: + virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast(pointer); } + + static const HeapDisposer instance; +}; + +template +const HeapDisposer HeapDisposer::instance = HeapDisposer(); + +} // namespace _ (private) + +template +Own heap(Params&&... params) { + // heap(...) allocates a T on the heap, forwarding the parameters to its constructor. The + // exact heap implementation is unspecified -- for now it is operator new, but you should not + // assume this. (Since we know the object size at delete time, we could actually implement an + // allocator that is more efficient than operator new.) + + return Own(new T(kj::fwd(params)...), _::HeapDisposer::instance); +} + +template +Own> heap(T&& orig) { + // Allocate a copy (or move) of the argument on the heap. + // + // The purpose of this overload is to allow you to omit the template parameter as there is only + // one argument and the purpose is to copy it. + + typedef Decay T2; + return Own(new T2(kj::fwd(orig)), _::HeapDisposer::instance); +} + +// ======================================================================================= +// SpaceFor -- assists in manual allocation + +template +class SpaceFor { + // A class which has the same size and alignment as T but does not call its constructor or + // destructor automatically. Instead, call construct() to construct a T in the space, which + // returns an Own which will take care of calling T's destructor later. + +public: + inline SpaceFor() {} + inline ~SpaceFor() {} + + template + Own construct(Params&&... params) { + ctor(value, kj::fwd(params)...); + return Own(&value, DestructorOnlyDisposer::instance); + } + +private: + union { + T value; + }; +}; + +// ======================================================================================= +// Inline implementation details + +template +struct Disposer::Dispose_ { + static void dispose(T* object, const Disposer& disposer) { + // Note that dynamic_cast does not require RTTI to be enabled, because the offset to + // the top of the object is in the vtable -- as it obviously needs to be to correctly implement + // operator delete. + disposer.disposeImpl(dynamic_cast(object)); + } +}; +template +struct Disposer::Dispose_ { + static void dispose(T* object, const Disposer& disposer) { + disposer.disposeImpl(static_cast(object)); + } +}; + +template +void Disposer::dispose(T* object) const { + Dispose_::dispose(object, *this); +} + +} // namespace kj + +#endif // KJ_MEMORY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/miniposix.h --- a/osx/include/kj/miniposix.h Mon Mar 06 13:29:58 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_MINIPOSIX_H_ -#define KJ_MINIPOSIX_H_ - -// This header provides a small subset of the POSIX API which also happens to be available on -// Windows under slightly-different names. - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#if _WIN32 -#include -#include -#include // _O_BINARY -#else -#include -#include -#endif - -#if !_WIN32 || __MINGW32__ -#include -#include -#include -#endif - -#if !_WIN32 -#include -#endif - -namespace kj { -namespace miniposix { - -#if _WIN32 && !__MINGW32__ -// We're on Windows and not MinGW. So, we need to define wrappers for the POSIX API. - -typedef int ssize_t; - -inline ssize_t read(int fd, void* buffer, size_t size) { - return ::_read(fd, buffer, size); -} -inline ssize_t write(int fd, const void* buffer, size_t size) { - return ::_write(fd, buffer, size); -} -inline int close(int fd) { - return ::_close(fd); -} - -#ifndef F_OK -#define F_OK 0 // access() existence test -#endif - -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) // stat() regular file test -#endif -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) // stat() directory test -#endif - -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif - -#else -// We're on a POSIX system or MinGW which already defines the wrappers for us. - -using ::ssize_t; -using ::read; -using ::write; -using ::close; - -#endif - -#if _WIN32 -// We're on Windows, including MinGW. pipe() and mkdir() are non-standard even on MinGW. - -inline int pipe(int fds[2]) { - return ::_pipe(fds, 8192, _O_BINARY); -} -inline int mkdir(const char* path, int mode) { - return ::_mkdir(path); -} - -#else -// We're on real POSIX. - -using ::pipe; -using ::mkdir; - -inline size_t iovMax(size_t count) { - // Apparently, there is a maximum number of iovecs allowed per call. I don't understand why. - // Most platforms define IOV_MAX but Linux defines only UIO_MAXIOV and others, like Hurd, - // define neither. - // - // On platforms where both IOV_MAX and UIO_MAXIOV are undefined, we poke sysconf(_SC_IOV_MAX), - // then try to fall back to the POSIX-mandated minimum of _XOPEN_IOV_MAX if that fails. - // - // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html#tag_13_23_03_01 - -#if defined(IOV_MAX) - // Solaris (and others?) - return IOV_MAX; -#elif defined(UIO_MAXIOV) - // Linux - return UIO_MAXIOV; -#else - // POSIX mystery meat - - long iovmax; - - errno = 0; - if ((iovmax = sysconf(_SC_IOV_MAX)) == -1) { - // assume iovmax == -1 && errno == 0 means "unbounded" - return errno ? _XOPEN_IOV_MAX : count; - } else { - return (size_t) iovmax; - } -#endif -} - -#endif - -} // namespace miniposix -} // namespace kj - -#endif // KJ_MINIPOSIX_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/mutex.h --- a/osx/include/kj/mutex.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/mutex.h Mon May 22 10:01:37 2017 +0100 @@ -1,369 +1,369 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_MUTEX_H_ -#define KJ_MUTEX_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "memory.h" -#include - -#if __linux__ && !defined(KJ_USE_FUTEX) -#define KJ_USE_FUTEX 1 -#endif - -#if !KJ_USE_FUTEX && !_WIN32 -// On Linux we use futex. On other platforms we wrap pthreads. -// TODO(someday): Write efficient low-level locking primitives for other platforms. -#include -#endif - -namespace kj { - -// ======================================================================================= -// Private details -- public interfaces follow below. - -namespace _ { // private - -class Mutex { - // Internal implementation details. See `MutexGuarded`. - -public: - Mutex(); - ~Mutex(); - KJ_DISALLOW_COPY(Mutex); - - enum Exclusivity { - EXCLUSIVE, - SHARED - }; - - void lock(Exclusivity exclusivity); - void unlock(Exclusivity exclusivity); - - void assertLockedByCaller(Exclusivity exclusivity); - // In debug mode, assert that the mutex is locked by the calling thread, or if that is - // non-trivial, assert that the mutex is locked (which should be good enough to catch problems - // in unit tests). In non-debug builds, do nothing. - -private: -#if KJ_USE_FUTEX - uint futex; - // bit 31 (msb) = set if exclusive lock held - // bit 30 (msb) = set if threads are waiting for exclusive lock - // bits 0-29 = count of readers; If an exclusive lock is held, this is the count of threads - // waiting for a read lock, otherwise it is the count of threads that currently hold a read - // lock. - - static constexpr uint EXCLUSIVE_HELD = 1u << 31; - static constexpr uint EXCLUSIVE_REQUESTED = 1u << 30; - static constexpr uint SHARED_COUNT_MASK = EXCLUSIVE_REQUESTED - 1; - -#elif _WIN32 - uintptr_t srwLock; // Actually an SRWLOCK, but don't want to #include in header. - -#else - mutable pthread_rwlock_t mutex; -#endif -}; - -class Once { - // Internal implementation details. See `Lazy`. - -public: -#if KJ_USE_FUTEX - inline Once(bool startInitialized = false) - : futex(startInitialized ? INITIALIZED : UNINITIALIZED) {} -#else - Once(bool startInitialized = false); - ~Once(); -#endif - KJ_DISALLOW_COPY(Once); - - class Initializer { - public: - virtual void run() = 0; - }; - - void runOnce(Initializer& init); - -#if _WIN32 // TODO(perf): Can we make this inline on win32 somehow? - bool isInitialized() noexcept; - -#else - inline bool isInitialized() noexcept { - // Fast path check to see if runOnce() would simply return immediately. -#if KJ_USE_FUTEX - return __atomic_load_n(&futex, __ATOMIC_ACQUIRE) == INITIALIZED; -#else - return __atomic_load_n(&state, __ATOMIC_ACQUIRE) == INITIALIZED; -#endif - } -#endif - - void reset(); - // Returns the state from initialized to uninitialized. It is an error to call this when - // not already initialized, or when runOnce() or isInitialized() might be called concurrently in - // another thread. - -private: -#if KJ_USE_FUTEX - uint futex; - - enum State { - UNINITIALIZED, - INITIALIZING, - INITIALIZING_WITH_WAITERS, - INITIALIZED - }; - -#elif _WIN32 - uintptr_t initOnce; // Actually an INIT_ONCE, but don't want to #include in header. - -#else - enum State { - UNINITIALIZED, - INITIALIZED - }; - State state; - pthread_mutex_t mutex; -#endif -}; - -} // namespace _ (private) - -// ======================================================================================= -// Public interface - -template -class Locked { - // Return type for `MutexGuarded::lock()`. `Locked` provides access to the guarded object - // and unlocks the mutex when it goes out of scope. - -public: - KJ_DISALLOW_COPY(Locked); - inline Locked(): mutex(nullptr), ptr(nullptr) {} - inline Locked(Locked&& other): mutex(other.mutex), ptr(other.ptr) { - other.mutex = nullptr; - other.ptr = nullptr; - } - inline ~Locked() { - if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); - } - - inline Locked& operator=(Locked&& other) { - if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); - mutex = other.mutex; - ptr = other.ptr; - other.mutex = nullptr; - other.ptr = nullptr; - return *this; - } - - inline void release() { - if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); - mutex = nullptr; - ptr = nullptr; - } - - inline T* operator->() { return ptr; } - inline const T* operator->() const { return ptr; } - inline T& operator*() { return *ptr; } - inline const T& operator*() const { return *ptr; } - inline T* get() { return ptr; } - inline const T* get() const { return ptr; } - inline operator T*() { return ptr; } - inline operator const T*() const { return ptr; } - -private: - _::Mutex* mutex; - T* ptr; - - inline Locked(_::Mutex& mutex, T& value): mutex(&mutex), ptr(&value) {} - - template - friend class MutexGuarded; -}; - -template -class MutexGuarded { - // An object of type T, guarded by a mutex. In order to access the object, you must lock it. - // - // Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock - // will deadlock. Recursive write locks are usually a sign of bad design. - // - // Unfortunately, **READ LOCKS ARE NOT RECURSIVE** either. Common sense says they should be. - // But on many operating systems (BSD, OSX), recursively read-locking a pthread_rwlock is - // actually unsafe. The problem is that writers are "prioritized" over readers, so a read lock - // request will block if any write lock requests are outstanding. So, if thread A takes a read - // lock, thread B requests a write lock (and starts waiting), and then thread A tries to take - // another read lock recursively, the result is deadlock. - -public: - template - explicit MutexGuarded(Params&&... params); - // Initialize the mutex-guarded object by passing the given parameters to its constructor. - - Locked lockExclusive() const; - // Exclusively locks the object and returns it. The returned `Locked` can be passed by - // move, similar to `Own`. - // - // This method is declared `const` in accordance with KJ style rules which say that constness - // should be used to indicate thread-safety. It is safe to share a const pointer between threads, - // but it is not safe to share a mutable pointer. Since the whole point of MutexGuarded is to - // be shared between threads, its methods should be const, even though locking it produces a - // non-const pointer to the contained object. - - Locked lockShared() const; - // Lock the value for shared access. Multiple shared locks can be taken concurrently, but cannot - // be held at the same time as a non-shared lock. - - inline const T& getWithoutLock() const { return value; } - inline T& getWithoutLock() { return value; } - // Escape hatch for cases where some external factor guarantees that it's safe to get the - // value. You should treat these like const_cast -- be highly suspicious of any use. - - inline const T& getAlreadyLockedShared() const; - inline T& getAlreadyLockedShared(); - inline T& getAlreadyLockedExclusive() const; - // Like `getWithoutLock()`, but asserts that the lock is already held by the calling thread. - -private: - mutable _::Mutex mutex; - mutable T value; -}; - -template -class MutexGuarded { - // MutexGuarded cannot guard a const type. This would be pointless anyway, and would complicate - // the implementation of Locked, which uses constness to decide what kind of lock it holds. - static_assert(sizeof(T) < 0, "MutexGuarded's type cannot be const."); -}; - -template -class Lazy { - // A lazily-initialized value. - -public: - template - T& get(Func&& init); - template - const T& get(Func&& init) const; - // The first thread to call get() will invoke the given init function to construct the value. - // Other threads will block until construction completes, then return the same value. - // - // `init` is a functor(typically a lambda) which takes `SpaceFor&` as its parameter and returns - // `Own`. If `init` throws an exception, the exception is propagated out of that thread's - // call to `get()`, and subsequent calls behave as if `get()` hadn't been called at all yet -- - // in other words, subsequent calls retry initialization until it succeeds. - -private: - mutable _::Once once; - mutable SpaceFor space; - mutable Own value; - - template - class InitImpl; -}; - -// ======================================================================================= -// Inline implementation details - -template -template -inline MutexGuarded::MutexGuarded(Params&&... params) - : value(kj::fwd(params)...) {} - -template -inline Locked MutexGuarded::lockExclusive() const { - mutex.lock(_::Mutex::EXCLUSIVE); - return Locked(mutex, value); -} - -template -inline Locked MutexGuarded::lockShared() const { - mutex.lock(_::Mutex::SHARED); - return Locked(mutex, value); -} - -template -inline const T& MutexGuarded::getAlreadyLockedShared() const { -#ifdef KJ_DEBUG - mutex.assertLockedByCaller(_::Mutex::SHARED); -#endif - return value; -} -template -inline T& MutexGuarded::getAlreadyLockedShared() { -#ifdef KJ_DEBUG - mutex.assertLockedByCaller(_::Mutex::SHARED); -#endif - return value; -} -template -inline T& MutexGuarded::getAlreadyLockedExclusive() const { -#ifdef KJ_DEBUG - mutex.assertLockedByCaller(_::Mutex::EXCLUSIVE); -#endif - return const_cast(value); -} - -template -template -class Lazy::InitImpl: public _::Once::Initializer { -public: - inline InitImpl(const Lazy& lazy, Func&& func): lazy(lazy), func(kj::fwd(func)) {} - - void run() override { - lazy.value = func(lazy.space); - } - -private: - const Lazy& lazy; - Func func; -}; - -template -template -inline T& Lazy::get(Func&& init) { - if (!once.isInitialized()) { - InitImpl initImpl(*this, kj::fwd(init)); - once.runOnce(initImpl); - } - return *value; -} - -template -template -inline const T& Lazy::get(Func&& init) const { - if (!once.isInitialized()) { - InitImpl initImpl(*this, kj::fwd(init)); - once.runOnce(initImpl); - } - return *value; -} - -} // namespace kj - -#endif // KJ_MUTEX_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_MUTEX_H_ +#define KJ_MUTEX_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" +#include + +#if __linux__ && !defined(KJ_USE_FUTEX) +#define KJ_USE_FUTEX 1 +#endif + +#if !KJ_USE_FUTEX && !_WIN32 +// On Linux we use futex. On other platforms we wrap pthreads. +// TODO(someday): Write efficient low-level locking primitives for other platforms. +#include +#endif + +namespace kj { + +// ======================================================================================= +// Private details -- public interfaces follow below. + +namespace _ { // private + +class Mutex { + // Internal implementation details. See `MutexGuarded`. + +public: + Mutex(); + ~Mutex(); + KJ_DISALLOW_COPY(Mutex); + + enum Exclusivity { + EXCLUSIVE, + SHARED + }; + + void lock(Exclusivity exclusivity); + void unlock(Exclusivity exclusivity); + + void assertLockedByCaller(Exclusivity exclusivity); + // In debug mode, assert that the mutex is locked by the calling thread, or if that is + // non-trivial, assert that the mutex is locked (which should be good enough to catch problems + // in unit tests). In non-debug builds, do nothing. + +private: +#if KJ_USE_FUTEX + uint futex; + // bit 31 (msb) = set if exclusive lock held + // bit 30 (msb) = set if threads are waiting for exclusive lock + // bits 0-29 = count of readers; If an exclusive lock is held, this is the count of threads + // waiting for a read lock, otherwise it is the count of threads that currently hold a read + // lock. + + static constexpr uint EXCLUSIVE_HELD = 1u << 31; + static constexpr uint EXCLUSIVE_REQUESTED = 1u << 30; + static constexpr uint SHARED_COUNT_MASK = EXCLUSIVE_REQUESTED - 1; + +#elif _WIN32 + uintptr_t srwLock; // Actually an SRWLOCK, but don't want to #include in header. + +#else + mutable pthread_rwlock_t mutex; +#endif +}; + +class Once { + // Internal implementation details. See `Lazy`. + +public: +#if KJ_USE_FUTEX + inline Once(bool startInitialized = false) + : futex(startInitialized ? INITIALIZED : UNINITIALIZED) {} +#else + Once(bool startInitialized = false); + ~Once(); +#endif + KJ_DISALLOW_COPY(Once); + + class Initializer { + public: + virtual void run() = 0; + }; + + void runOnce(Initializer& init); + +#if _WIN32 // TODO(perf): Can we make this inline on win32 somehow? + bool isInitialized() noexcept; + +#else + inline bool isInitialized() noexcept { + // Fast path check to see if runOnce() would simply return immediately. +#if KJ_USE_FUTEX + return __atomic_load_n(&futex, __ATOMIC_ACQUIRE) == INITIALIZED; +#else + return __atomic_load_n(&state, __ATOMIC_ACQUIRE) == INITIALIZED; +#endif + } +#endif + + void reset(); + // Returns the state from initialized to uninitialized. It is an error to call this when + // not already initialized, or when runOnce() or isInitialized() might be called concurrently in + // another thread. + +private: +#if KJ_USE_FUTEX + uint futex; + + enum State { + UNINITIALIZED, + INITIALIZING, + INITIALIZING_WITH_WAITERS, + INITIALIZED + }; + +#elif _WIN32 + uintptr_t initOnce; // Actually an INIT_ONCE, but don't want to #include in header. + +#else + enum State { + UNINITIALIZED, + INITIALIZED + }; + State state; + pthread_mutex_t mutex; +#endif +}; + +} // namespace _ (private) + +// ======================================================================================= +// Public interface + +template +class Locked { + // Return type for `MutexGuarded::lock()`. `Locked` provides access to the bounded object + // and unlocks the mutex when it goes out of scope. + +public: + KJ_DISALLOW_COPY(Locked); + inline Locked(): mutex(nullptr), ptr(nullptr) {} + inline Locked(Locked&& other): mutex(other.mutex), ptr(other.ptr) { + other.mutex = nullptr; + other.ptr = nullptr; + } + inline ~Locked() { + if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); + } + + inline Locked& operator=(Locked&& other) { + if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); + mutex = other.mutex; + ptr = other.ptr; + other.mutex = nullptr; + other.ptr = nullptr; + return *this; + } + + inline void release() { + if (mutex != nullptr) mutex->unlock(isConst() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE); + mutex = nullptr; + ptr = nullptr; + } + + inline T* operator->() { return ptr; } + inline const T* operator->() const { return ptr; } + inline T& operator*() { return *ptr; } + inline const T& operator*() const { return *ptr; } + inline T* get() { return ptr; } + inline const T* get() const { return ptr; } + inline operator T*() { return ptr; } + inline operator const T*() const { return ptr; } + +private: + _::Mutex* mutex; + T* ptr; + + inline Locked(_::Mutex& mutex, T& value): mutex(&mutex), ptr(&value) {} + + template + friend class MutexGuarded; +}; + +template +class MutexGuarded { + // An object of type T, bounded by a mutex. In order to access the object, you must lock it. + // + // Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock + // will deadlock. Recursive write locks are usually a sign of bad design. + // + // Unfortunately, **READ LOCKS ARE NOT RECURSIVE** either. Common sense says they should be. + // But on many operating systems (BSD, OSX), recursively read-locking a pthread_rwlock is + // actually unsafe. The problem is that writers are "prioritized" over readers, so a read lock + // request will block if any write lock requests are outstanding. So, if thread A takes a read + // lock, thread B requests a write lock (and starts waiting), and then thread A tries to take + // another read lock recursively, the result is deadlock. + +public: + template + explicit MutexGuarded(Params&&... params); + // Initialize the mutex-bounded object by passing the given parameters to its constructor. + + Locked lockExclusive() const; + // Exclusively locks the object and returns it. The returned `Locked` can be passed by + // move, similar to `Own`. + // + // This method is declared `const` in accordance with KJ style rules which say that constness + // should be used to indicate thread-safety. It is safe to share a const pointer between threads, + // but it is not safe to share a mutable pointer. Since the whole point of MutexGuarded is to + // be shared between threads, its methods should be const, even though locking it produces a + // non-const pointer to the contained object. + + Locked lockShared() const; + // Lock the value for shared access. Multiple shared locks can be taken concurrently, but cannot + // be held at the same time as a non-shared lock. + + inline const T& getWithoutLock() const { return value; } + inline T& getWithoutLock() { return value; } + // Escape hatch for cases where some external factor guarantees that it's safe to get the + // value. You should treat these like const_cast -- be highly suspicious of any use. + + inline const T& getAlreadyLockedShared() const; + inline T& getAlreadyLockedShared(); + inline T& getAlreadyLockedExclusive() const; + // Like `getWithoutLock()`, but asserts that the lock is already held by the calling thread. + +private: + mutable _::Mutex mutex; + mutable T value; +}; + +template +class MutexGuarded { + // MutexGuarded cannot guard a const type. This would be pointless anyway, and would complicate + // the implementation of Locked, which uses constness to decide what kind of lock it holds. + static_assert(sizeof(T) < 0, "MutexGuarded's type cannot be const."); +}; + +template +class Lazy { + // A lazily-initialized value. + +public: + template + T& get(Func&& init); + template + const T& get(Func&& init) const; + // The first thread to call get() will invoke the given init function to construct the value. + // Other threads will block until construction completes, then return the same value. + // + // `init` is a functor(typically a lambda) which takes `SpaceFor&` as its parameter and returns + // `Own`. If `init` throws an exception, the exception is propagated out of that thread's + // call to `get()`, and subsequent calls behave as if `get()` hadn't been called at all yet -- + // in other words, subsequent calls retry initialization until it succeeds. + +private: + mutable _::Once once; + mutable SpaceFor space; + mutable Own value; + + template + class InitImpl; +}; + +// ======================================================================================= +// Inline implementation details + +template +template +inline MutexGuarded::MutexGuarded(Params&&... params) + : value(kj::fwd(params)...) {} + +template +inline Locked MutexGuarded::lockExclusive() const { + mutex.lock(_::Mutex::EXCLUSIVE); + return Locked(mutex, value); +} + +template +inline Locked MutexGuarded::lockShared() const { + mutex.lock(_::Mutex::SHARED); + return Locked(mutex, value); +} + +template +inline const T& MutexGuarded::getAlreadyLockedShared() const { +#ifdef KJ_DEBUG + mutex.assertLockedByCaller(_::Mutex::SHARED); +#endif + return value; +} +template +inline T& MutexGuarded::getAlreadyLockedShared() { +#ifdef KJ_DEBUG + mutex.assertLockedByCaller(_::Mutex::SHARED); +#endif + return value; +} +template +inline T& MutexGuarded::getAlreadyLockedExclusive() const { +#ifdef KJ_DEBUG + mutex.assertLockedByCaller(_::Mutex::EXCLUSIVE); +#endif + return const_cast(value); +} + +template +template +class Lazy::InitImpl: public _::Once::Initializer { +public: + inline InitImpl(const Lazy& lazy, Func&& func): lazy(lazy), func(kj::fwd(func)) {} + + void run() override { + lazy.value = func(lazy.space); + } + +private: + const Lazy& lazy; + Func func; +}; + +template +template +inline T& Lazy::get(Func&& init) { + if (!once.isInitialized()) { + InitImpl initImpl(*this, kj::fwd(init)); + once.runOnce(initImpl); + } + return *value; +} + +template +template +inline const T& Lazy::get(Func&& init) const { + if (!once.isInitialized()) { + InitImpl initImpl(*this, kj::fwd(init)); + once.runOnce(initImpl); + } + return *value; +} + +} // namespace kj + +#endif // KJ_MUTEX_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/one-of.h --- a/osx/include/kj/one-of.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/one-of.h Mon May 22 10:01:37 2017 +0100 @@ -1,150 +1,155 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_ONE_OF_H_ -#define KJ_ONE_OF_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" - -namespace kj { - -namespace _ { // private - -template -struct TypeIndex_ { static constexpr uint value = TypeIndex_::value; }; -template -struct TypeIndex_ { static constexpr uint value = i; }; - -} // namespace _ (private) - -template -class OneOf { - template - static inline constexpr uint typeIndex() { return _::TypeIndex_<1, Key, Variants...>::value; } - // Get the 1-based index of Key within the type list Types. - -public: - inline OneOf(): tag(0) {} - OneOf(const OneOf& other) { copyFrom(other); } - OneOf(OneOf&& other) { moveFrom(other); } - ~OneOf() { destroy(); } - - OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; } - OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; } - - inline bool operator==(decltype(nullptr)) const { return tag == 0; } - inline bool operator!=(decltype(nullptr)) const { return tag != 0; } - - template - bool is() const { - return tag == typeIndex(); - } - - template - T& get() { - KJ_IREQUIRE(is(), "Must check OneOf::is() before calling get()."); - return *reinterpret_cast(space); - } - template - const T& get() const { - KJ_IREQUIRE(is(), "Must check OneOf::is() before calling get()."); - return *reinterpret_cast(space); - } - - template - void init(Params&&... params) { - if (tag != 0) destroy(); - ctor(*reinterpret_cast(space), kj::fwd(params)...); - tag = typeIndex(); - } - -private: - uint tag; - - static inline constexpr size_t maxSize(size_t a) { - return a; - } - template - static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) { - return maxSize(kj::max(a, b), rest...); - } - // Returns the maximum of all the parameters. - // TODO(someday): Generalize the above template and make it common. I tried, but C++ decided to - // be difficult so I cut my losses. - - union { - byte space[maxSize(sizeof(Variants)...)]; - - void* forceAligned; - // TODO(someday): Use C++11 alignas() once we require GCC 4.8 / Clang 3.3. - }; - - template - inline void doAll(T... t) {} - - template - inline bool destroyVariant() { - if (tag == typeIndex()) { - tag = 0; - dtor(*reinterpret_cast(space)); - } - return false; - } - void destroy() { - doAll(destroyVariant()...); - } - - template - inline bool copyVariantFrom(const OneOf& other) { - if (other.is()) { - ctor(*reinterpret_cast(space), other.get()); - } - return false; - } - void copyFrom(const OneOf& other) { - // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag - // is invalid. - tag = other.tag; - doAll(copyVariantFrom(other)...); - } - - template - inline bool moveVariantFrom(OneOf& other) { - if (other.is()) { - ctor(*reinterpret_cast(space), kj::mv(other.get())); - } - return false; - } - void moveFrom(OneOf& other) { - // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag - // is invalid. - tag = other.tag; - doAll(moveVariantFrom(other)...); - } -}; - -} // namespace kj - -#endif // KJ_ONE_OF_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ONE_OF_H_ +#define KJ_ONE_OF_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" + +namespace kj { + +namespace _ { // private + +template +struct TypeIndex_ { static constexpr uint value = TypeIndex_::value; }; +template +struct TypeIndex_ { static constexpr uint value = i; }; + +} // namespace _ (private) + +template +class OneOf { + template + static inline constexpr uint typeIndex() { return _::TypeIndex_<1, Key, Variants...>::value; } + // Get the 1-based index of Key within the type list Types. + +public: + inline OneOf(): tag(0) {} + OneOf(const OneOf& other) { copyFrom(other); } + OneOf(OneOf&& other) { moveFrom(other); } + ~OneOf() { destroy(); } + + OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; } + OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; } + + inline bool operator==(decltype(nullptr)) const { return tag == 0; } + inline bool operator!=(decltype(nullptr)) const { return tag != 0; } + + template + bool is() const { + return tag == typeIndex(); + } + + template + T& get() { + KJ_IREQUIRE(is(), "Must check OneOf::is() before calling get()."); + return *reinterpret_cast(space); + } + template + const T& get() const { + KJ_IREQUIRE(is(), "Must check OneOf::is() before calling get()."); + return *reinterpret_cast(space); + } + + template + T& init(Params&&... params) { + if (tag != 0) destroy(); + ctor(*reinterpret_cast(space), kj::fwd(params)...); + tag = typeIndex(); + return *reinterpret_cast(space); + } + +private: + uint tag; + + static inline constexpr size_t maxSize(size_t a) { + return a; + } + template + static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) { + return maxSize(kj::max(a, b), rest...); + } + // Returns the maximum of all the parameters. + // TODO(someday): Generalize the above template and make it common. I tried, but C++ decided to + // be difficult so I cut my losses. + + static constexpr auto spaceSize = maxSize(sizeof(Variants)...); + // TODO(msvc): This constant could just as well go directly inside space's bracket's, where it's + // used, but MSVC suffers a parse error on `...`. + + union { + byte space[spaceSize]; + + void* forceAligned; + // TODO(someday): Use C++11 alignas() once we require GCC 4.8 / Clang 3.3. + }; + + template + inline void doAll(T... t) {} + + template + inline bool destroyVariant() { + if (tag == typeIndex()) { + tag = 0; + dtor(*reinterpret_cast(space)); + } + return false; + } + void destroy() { + doAll(destroyVariant()...); + } + + template + inline bool copyVariantFrom(const OneOf& other) { + if (other.is()) { + ctor(*reinterpret_cast(space), other.get()); + } + return false; + } + void copyFrom(const OneOf& other) { + // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag + // is invalid. + tag = other.tag; + doAll(copyVariantFrom(other)...); + } + + template + inline bool moveVariantFrom(OneOf& other) { + if (other.is()) { + ctor(*reinterpret_cast(space), kj::mv(other.get())); + } + return false; + } + void moveFrom(OneOf& other) { + // Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag + // is invalid. + tag = other.tag; + doAll(moveVariantFrom(other)...); + } +}; + +} // namespace kj + +#endif // KJ_ONE_OF_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/parse/char.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/parse/char.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,361 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains parsers useful for character stream inputs, including parsers to parse +// common kinds of tokens like identifiers, numbers, and quoted strings. + +#ifndef KJ_PARSE_CHAR_H_ +#define KJ_PARSE_CHAR_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" +#include "../string.h" +#include + +namespace kj { +namespace parse { + +// ======================================================================================= +// Exact char/string. + +class ExactString_ { +public: + constexpr inline ExactString_(const char* str): str(str) {} + + template + Maybe> operator()(Input& input) const { + const char* ptr = str; + + while (*ptr != '\0') { + if (input.atEnd() || input.current() != *ptr) return nullptr; + input.next(); + ++ptr; + } + + return Tuple<>(); + } + +private: + const char* str; +}; + +constexpr inline ExactString_ exactString(const char* str) { + return ExactString_(str); +} + +template +constexpr ExactlyConst_ exactChar() { + // Returns a parser that matches exactly the character given by the template argument (returning + // no result). + return ExactlyConst_(); +} + +// ======================================================================================= +// Char ranges / sets + +class CharGroup_ { +public: + constexpr inline CharGroup_(): bits{0, 0, 0, 0} {} + + constexpr inline CharGroup_ orRange(unsigned char first, unsigned char last) const { + return CharGroup_(bits[0] | (oneBits(last + 1) & ~oneBits(first )), + bits[1] | (oneBits(last - 63) & ~oneBits(first - 64)), + bits[2] | (oneBits(last - 127) & ~oneBits(first - 128)), + bits[3] | (oneBits(last - 191) & ~oneBits(first - 192))); + } + + constexpr inline CharGroup_ orAny(const char* chars) const { + return *chars == 0 ? *this : orChar(*chars).orAny(chars + 1); + } + + constexpr inline CharGroup_ orChar(unsigned char c) const { + return CharGroup_(bits[0] | bit(c), + bits[1] | bit(c - 64), + bits[2] | bit(c - 128), + bits[3] | bit(c - 256)); + } + + constexpr inline CharGroup_ orGroup(CharGroup_ other) const { + return CharGroup_(bits[0] | other.bits[0], + bits[1] | other.bits[1], + bits[2] | other.bits[2], + bits[3] | other.bits[3]); + } + + constexpr inline CharGroup_ invert() const { + return CharGroup_(~bits[0], ~bits[1], ~bits[2], ~bits[3]); + } + + constexpr inline bool contains(unsigned char c) const { + return (bits[c / 64] & (1ll << (c % 64))) != 0; + } + + template + Maybe operator()(Input& input) const { + if (input.atEnd()) return nullptr; + unsigned char c = input.current(); + if (contains(c)) { + input.next(); + return c; + } else { + return nullptr; + } + } + +private: + typedef unsigned long long Bits64; + + constexpr inline CharGroup_(Bits64 a, Bits64 b, Bits64 c, Bits64 d): bits{a, b, c, d} {} + Bits64 bits[4]; + + static constexpr inline Bits64 oneBits(int count) { + return count <= 0 ? 0ll : count >= 64 ? -1ll : ((1ll << count) - 1); + } + static constexpr inline Bits64 bit(int index) { + return index < 0 ? 0 : index >= 64 ? 0 : (1ll << index); + } +}; + +constexpr inline CharGroup_ charRange(char first, char last) { + // Create a parser which accepts any character in the range from `first` to `last`, inclusive. + // For example: `charRange('a', 'z')` matches all lower-case letters. The parser's result is the + // character matched. + // + // The returned object has methods which can be used to match more characters. The following + // produces a parser which accepts any letter as well as '_', '+', '-', and '.'. + // + // charRange('a', 'z').orRange('A', 'Z').orChar('_').orAny("+-.") + // + // You can also use `.invert()` to match the opposite set of characters. + + return CharGroup_().orRange(first, last); +} + +#if _MSC_VER +#define anyOfChars(chars) CharGroup_().orAny(chars) +// TODO(msvc): MSVC ICEs on the proper definition of `anyOfChars()`, which in turn prevents us from +// building the compiler or schema parser. We don't know why this happens, but Harris found that +// this horrible, horrible hack makes things work. This is awful, but it's better than nothing. +// Hopefully, MSVC will get fixed soon and we'll be able to remove this. +#else +constexpr inline CharGroup_ anyOfChars(const char* chars) { + // Returns a parser that accepts any of the characters in the given string (which should usually + // be a literal). The returned parser is of the same type as returned by `charRange()` -- see + // that function for more info. + + return CharGroup_().orAny(chars); +} +#endif + +// ======================================================================================= + +namespace _ { // private + +struct ArrayToString { + inline String operator()(const Array& arr) const { + return heapString(arr); + } +}; + +} // namespace _ (private) + +template +constexpr inline auto charsToString(SubParser&& subParser) + -> decltype(transform(kj::fwd(subParser), _::ArrayToString())) { + // Wraps a parser that returns Array such that it returns String instead. + return parse::transform(kj::fwd(subParser), _::ArrayToString()); +} + +// ======================================================================================= +// Basic character classes. + +constexpr auto alpha = charRange('a', 'z').orRange('A', 'Z'); +constexpr auto digit = charRange('0', '9'); +constexpr auto alphaNumeric = alpha.orGroup(digit); +constexpr auto nameStart = alpha.orChar('_'); +constexpr auto nameChar = alphaNumeric.orChar('_'); +constexpr auto hexDigit = charRange('0', '9').orRange('a', 'f').orRange('A', 'F'); +constexpr auto octDigit = charRange('0', '7'); +constexpr auto whitespaceChar = anyOfChars(" \f\n\r\t\v"); +constexpr auto controlChar = charRange(0, 0x1f).invert().orGroup(whitespaceChar).invert(); + +constexpr auto whitespace = many(anyOfChars(" \f\n\r\t\v")); + +constexpr auto discardWhitespace = discard(many(discard(anyOfChars(" \f\n\r\t\v")))); +// Like discard(whitespace) but avoids some memory allocation. + +// ======================================================================================= +// Identifiers + +namespace _ { // private + +struct IdentifierToString { + inline String operator()(char first, const Array& rest) const { + String result = heapString(rest.size() + 1); + result[0] = first; + memcpy(result.begin() + 1, rest.begin(), rest.size()); + return result; + } +}; + +} // namespace _ (private) + +constexpr auto identifier = transform(sequence(nameStart, many(nameChar)), _::IdentifierToString()); +// Parses an identifier (e.g. a C variable name). + +// ======================================================================================= +// Integers + +namespace _ { // private + +inline char parseDigit(char c) { + if (c < 'A') return c - '0'; + if (c < 'a') return c - 'A' + 10; + return c - 'a' + 10; +} + +template +struct ParseInteger { + inline uint64_t operator()(const Array& digits) const { + return operator()('0', digits); + } + uint64_t operator()(char first, const Array& digits) const { + uint64_t result = parseDigit(first); + for (char digit: digits) { + result = result * base + parseDigit(digit); + } + return result; + } +}; + + +} // namespace _ (private) + +constexpr auto integer = sequence( + oneOf( + transform(sequence(exactChar<'0'>(), exactChar<'x'>(), oneOrMore(hexDigit)), _::ParseInteger<16>()), + transform(sequence(exactChar<'0'>(), many(octDigit)), _::ParseInteger<8>()), + transform(sequence(charRange('1', '9'), many(digit)), _::ParseInteger<10>())), + notLookingAt(alpha.orAny("_."))); + +// ======================================================================================= +// Numbers (i.e. floats) + +namespace _ { // private + +struct ParseFloat { + double operator()(const Array& digits, + const Maybe>& fraction, + const Maybe, Array>>& exponent) const; +}; + +} // namespace _ (private) + +constexpr auto number = transform( + sequence( + oneOrMore(digit), + optional(sequence(exactChar<'.'>(), many(digit))), + optional(sequence(discard(anyOfChars("eE")), optional(anyOfChars("+-")), many(digit))), + notLookingAt(alpha.orAny("_."))), + _::ParseFloat()); + +// ======================================================================================= +// Quoted strings + +namespace _ { // private + +struct InterpretEscape { + char operator()(char c) const { + switch (c) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + default: return c; + } + } +}; + +struct ParseHexEscape { + inline char operator()(char first, char second) const { + return (parseDigit(first) << 4) | parseDigit(second); + } +}; + +struct ParseHexByte { + inline byte operator()(char first, char second) const { + return (parseDigit(first) << 4) | parseDigit(second); + } +}; + +struct ParseOctEscape { + inline char operator()(char first, Maybe second, Maybe third) const { + char result = first - '0'; + KJ_IF_MAYBE(digit1, second) { + result = (result << 3) | (*digit1 - '0'); + KJ_IF_MAYBE(digit2, third) { + result = (result << 3) | (*digit2 - '0'); + } + } + return result; + } +}; + +} // namespace _ (private) + +constexpr auto escapeSequence = + sequence(exactChar<'\\'>(), oneOf( + transform(anyOfChars("abfnrtv'\"\\\?"), _::InterpretEscape()), + transform(sequence(exactChar<'x'>(), hexDigit, hexDigit), _::ParseHexEscape()), + transform(sequence(octDigit, optional(octDigit), optional(octDigit)), + _::ParseOctEscape()))); +// A parser that parses a C-string-style escape sequence (starting with a backslash). Returns +// a char. + +constexpr auto doubleQuotedString = charsToString(sequence( + exactChar<'\"'>(), + many(oneOf(anyOfChars("\\\n\"").invert(), escapeSequence)), + exactChar<'\"'>())); +// Parses a C-style double-quoted string. + +constexpr auto singleQuotedString = charsToString(sequence( + exactChar<'\''>(), + many(oneOf(anyOfChars("\\\n\'").invert(), escapeSequence)), + exactChar<'\''>())); +// Parses a C-style single-quoted string. + +constexpr auto doubleQuotedHexBinary = sequence( + exactChar<'0'>(), exactChar<'x'>(), exactChar<'\"'>(), + oneOrMore(transform(sequence(discardWhitespace, hexDigit, hexDigit), _::ParseHexByte())), + discardWhitespace, + exactChar<'\"'>()); +// Parses a double-quoted hex binary literal. Returns Array. + +} // namespace parse +} // namespace kj + +#endif // KJ_PARSE_CHAR_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/parse/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/parse/common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,824 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Parser combinator framework! +// +// This file declares several functions which construct parsers, usually taking other parsers as +// input, thus making them parser combinators. +// +// A valid parser is any functor which takes a reference to an input cursor (defined below) as its +// input and returns a Maybe. The parser returns null on parse failure, or returns the parsed +// result on success. +// +// An "input cursor" is any type which implements the same interface as IteratorInput, below. Such +// a type acts as a pointer to the current input location. When a parser returns successfully, it +// will have updated the input cursor to point to the position just past the end of what was parsed. +// On failure, the cursor position is unspecified. + +#ifndef KJ_PARSE_COMMON_H_ +#define KJ_PARSE_COMMON_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "../common.h" +#include "../memory.h" +#include "../array.h" +#include "../tuple.h" +#include "../vector.h" +#if _MSC_VER +#include // result_of_t +#endif + +namespace kj { +namespace parse { + +template +class IteratorInput { + // A parser input implementation based on an iterator range. + +public: + IteratorInput(Iterator begin, Iterator end) + : parent(nullptr), pos(begin), end(end), best(begin) {} + explicit IteratorInput(IteratorInput& parent) + : parent(&parent), pos(parent.pos), end(parent.end), best(parent.pos) {} + ~IteratorInput() { + if (parent != nullptr) { + parent->best = kj::max(kj::max(pos, best), parent->best); + } + } + KJ_DISALLOW_COPY(IteratorInput); + + void advanceParent() { + parent->pos = pos; + } + void forgetParent() { + parent = nullptr; + } + + bool atEnd() { return pos == end; } + auto current() -> decltype(*instance()) { + KJ_IREQUIRE(!atEnd()); + return *pos; + } + auto consume() -> decltype(*instance()) { + KJ_IREQUIRE(!atEnd()); + return *pos++; + } + void next() { + KJ_IREQUIRE(!atEnd()); + ++pos; + } + + Iterator getBest() { return kj::max(pos, best); } + + Iterator getPosition() { return pos; } + +private: + IteratorInput* parent; + Iterator pos; + Iterator end; + Iterator best; // furthest we got with any sub-input +}; + +template struct OutputType_; +template struct OutputType_> { typedef T Type; }; +template +using OutputType = typename OutputType_< +#if _MSC_VER + std::result_of_t + // The instance() based version below results in: + // C2064: term does not evaluate to a function taking 1 arguments +#else + decltype(instance()(instance())) +#endif + >::Type; +// Synonym for the output type of a parser, given the parser type and the input type. + +// ======================================================================================= + +template +class ParserRef { + // Acts as a reference to some other parser, with simplified type. The referenced parser + // is polymorphic by virtual call rather than templates. For grammars of non-trivial size, + // it is important to inject refs into the grammar here and there to prevent the parser types + // from becoming ridiculous. Using too many of them can hurt performance, though. + +public: + ParserRef(): parser(nullptr), wrapper(nullptr) {} + ParserRef(const ParserRef&) = default; + ParserRef(ParserRef&&) = default; + ParserRef& operator=(const ParserRef& other) = default; + ParserRef& operator=(ParserRef&& other) = default; + + template + constexpr ParserRef(Other&& other) + : parser(&other), wrapper(&WrapperImplInstance>::instance) { + static_assert(kj::isReference(), "ParserRef should not be assigned to a temporary."); + } + + template + inline ParserRef& operator=(Other&& other) { + static_assert(kj::isReference(), "ParserRef should not be assigned to a temporary."); + parser = &other; + wrapper = &WrapperImplInstance>::instance; + return *this; + } + + KJ_ALWAYS_INLINE(Maybe operator()(Input& input) const) { + // Always inline in the hopes that this allows branch prediction to kick in so the virtual call + // doesn't hurt so much. + return wrapper->parse(parser, input); + } + +private: + struct Wrapper { + virtual Maybe parse(const void* parser, Input& input) const = 0; + }; + template + struct WrapperImpl: public Wrapper { + Maybe parse(const void* parser, Input& input) const override { + return (*reinterpret_cast(parser))(input); + } + }; + template + struct WrapperImplInstance { +#if _MSC_VER + // TODO(msvc): MSVC currently fails to initialize vtable pointers for constexpr values so + // we have to make this just const instead. + static const WrapperImpl instance; +#else + static constexpr WrapperImpl instance = WrapperImpl(); +#endif + }; + + const void* parser; + const Wrapper* wrapper; +}; + +template +template +#if _MSC_VER +const typename ParserRef::template WrapperImpl +ParserRef::WrapperImplInstance::instance = WrapperImpl(); +#else +constexpr typename ParserRef::template WrapperImpl +ParserRef::WrapperImplInstance::instance; +#endif + +template +constexpr ParserRef> ref(ParserImpl& impl) { + // Constructs a ParserRef. You must specify the input type explicitly, e.g. + // `ref(myParser)`. + + return ParserRef>(impl); +} + +// ------------------------------------------------------------------- +// any +// Output = one token + +class Any_ { +public: + template + Maybe().consume())>> operator()(Input& input) const { + if (input.atEnd()) { + return nullptr; + } else { + return input.consume(); + } + } +}; + +constexpr Any_ any = Any_(); +// A parser which matches any token and simply returns it. + +// ------------------------------------------------------------------- +// exactly() +// Output = Tuple<> + +template +class Exactly_ { +public: + explicit constexpr Exactly_(T&& expected): expected(expected) {} + + template + Maybe> operator()(Input& input) const { + if (input.atEnd() || input.current() != expected) { + return nullptr; + } else { + input.next(); + return Tuple<>(); + } + } + +private: + T expected; +}; + +template +constexpr Exactly_ exactly(T&& expected) { + // Constructs a parser which succeeds when the input is exactly the token specified. The + // result is always the empty tuple. + + return Exactly_(kj::fwd(expected)); +} + +// ------------------------------------------------------------------- +// exactlyConst() +// Output = Tuple<> + +template +class ExactlyConst_ { +public: + explicit constexpr ExactlyConst_() {} + + template + Maybe> operator()(Input& input) const { + if (input.atEnd() || input.current() != expected) { + return nullptr; + } else { + input.next(); + return Tuple<>(); + } + } +}; + +template +constexpr ExactlyConst_ exactlyConst() { + // Constructs a parser which succeeds when the input is exactly the token specified. The + // result is always the empty tuple. This parser is templated on the token value which may cause + // it to perform better -- or worse. Be sure to measure. + + return ExactlyConst_(); +} + +// ------------------------------------------------------------------- +// constResult() + +template +class ConstResult_ { +public: + explicit constexpr ConstResult_(SubParser&& subParser, Result&& result) + : subParser(kj::fwd(subParser)), result(kj::fwd(result)) {} + + template + Maybe operator()(Input& input) const { + if (subParser(input) == nullptr) { + return nullptr; + } else { + return result; + } + } + +private: + SubParser subParser; + Result result; +}; + +template +constexpr ConstResult_ constResult(SubParser&& subParser, Result&& result) { + // Constructs a parser which returns exactly `result` if `subParser` is successful. + return ConstResult_(kj::fwd(subParser), kj::fwd(result)); +} + +template +constexpr ConstResult_> discard(SubParser&& subParser) { + // Constructs a parser which wraps `subParser` but discards the result. + return constResult(kj::fwd(subParser), Tuple<>()); +} + +// ------------------------------------------------------------------- +// sequence() +// Output = Flattened Tuple of outputs of sub-parsers. + +template class Sequence_; + +template +class Sequence_ { +public: + template + explicit constexpr Sequence_(T&& firstSubParser, U&&... rest) + : first(kj::fwd(firstSubParser)), rest(kj::fwd(rest)...) {} + + // TODO(msvc): The trailing return types on `operator()` and `parseNext()` expose at least two + // bugs in MSVC: + // + // 1. An ICE. + // 2. 'error C2672: 'operator __surrogate_func': no matching overloaded function found)', + // which crops up in numerous places when trying to build the capnp command line tools. + // + // The only workaround I found for both bugs is to omit the trailing return types and instead + // rely on C++14's return type deduction. + + template + auto operator()(Input& input) const +#ifndef _MSC_VER + -> Maybe>(), + instance>()...))> +#endif + { + return parseNext(input); + } + + template + auto parseNext(Input& input, InitialParams&&... initialParams) const +#ifndef _MSC_VER + -> Maybe(initialParams)..., + instance>(), + instance>()...))> +#endif + { + KJ_IF_MAYBE(firstResult, first(input)) { + return rest.parseNext(input, kj::fwd(initialParams)..., + kj::mv(*firstResult)); + } else { + // TODO(msvc): MSVC depends on return type deduction to compile this function, so we need to + // help it deduce the right type on this code path. + return Maybe(initialParams)..., + instance>(), + instance>()...))>{nullptr}; + } + } + +private: + FirstSubParser first; + Sequence_ rest; +}; + +template <> +class Sequence_<> { +public: + template + Maybe> operator()(Input& input) const { + return parseNext(input); + } + + template + auto parseNext(Input& input, Params&&... params) const -> + Maybe(params)...))> { + return tuple(kj::fwd(params)...); + } +}; + +template +constexpr Sequence_ sequence(SubParsers&&... subParsers) { + // Constructs a parser that executes each of the parameter parsers in sequence and returns a + // tuple of their results. + + return Sequence_(kj::fwd(subParsers)...); +} + +// ------------------------------------------------------------------- +// many() +// Output = Array of output of sub-parser, or just a uint count if the sub-parser returns Tuple<>. + +template +class Many_ { + template > + struct Impl; +public: + explicit constexpr Many_(SubParser&& subParser) + : subParser(kj::fwd(subParser)) {} + + template + auto operator()(Input& input) const + -> decltype(Impl::apply(instance(), input)); + +private: + SubParser subParser; +}; + +template +template +struct Many_::Impl { + static Maybe> apply(const SubParser& subParser, Input& input) { + typedef Vector> Results; + Results results; + + while (!input.atEnd()) { + Input subInput(input); + + KJ_IF_MAYBE(subResult, subParser(subInput)) { + subInput.advanceParent(); + results.add(kj::mv(*subResult)); + } else { + break; + } + } + + if (atLeastOne && results.empty()) { + return nullptr; + } + + return results.releaseAsArray(); + } +}; + +template +template +struct Many_::Impl> { + // If the sub-parser output is Tuple<>, just return a count. + + static Maybe apply(const SubParser& subParser, Input& input) { + uint count = 0; + + while (!input.atEnd()) { + Input subInput(input); + + KJ_IF_MAYBE(subResult, subParser(subInput)) { + subInput.advanceParent(); + ++count; + } else { + break; + } + } + + if (atLeastOne && count == 0) { + return nullptr; + } + + return count; + } +}; + +template +template +auto Many_::operator()(Input& input) const + -> decltype(Impl::apply(instance(), input)) { + return Impl>::apply(subParser, input); +} + +template +constexpr Many_ many(SubParser&& subParser) { + // Constructs a parser that repeatedly executes the given parser until it fails, returning an + // Array of the results (or a uint count if `subParser` returns an empty tuple). + return Many_(kj::fwd(subParser)); +} + +template +constexpr Many_ oneOrMore(SubParser&& subParser) { + // Like `many()` but the parser must parse at least one item to be successful. + return Many_(kj::fwd(subParser)); +} + +// ------------------------------------------------------------------- +// times() +// Output = Array of output of sub-parser, or Tuple<> if sub-parser returns Tuple<>. + +template +class Times_ { + template > + struct Impl; +public: + explicit constexpr Times_(SubParser&& subParser, uint count) + : subParser(kj::fwd(subParser)), count(count) {} + + template + auto operator()(Input& input) const + -> decltype(Impl::apply(instance(), instance(), input)); + +private: + SubParser subParser; + uint count; +}; + +template +template +struct Times_::Impl { + static Maybe> apply(const SubParser& subParser, uint count, Input& input) { + auto results = heapArrayBuilder>(count); + + while (results.size() < count) { + if (input.atEnd()) { + return nullptr; + } else KJ_IF_MAYBE(subResult, subParser(input)) { + results.add(kj::mv(*subResult)); + } else { + return nullptr; + } + } + + return results.finish(); + } +}; + +template +template +struct Times_::Impl> { + // If the sub-parser output is Tuple<>, just return a count. + + static Maybe> apply(const SubParser& subParser, uint count, Input& input) { + uint actualCount = 0; + + while (actualCount < count) { + if (input.atEnd()) { + return nullptr; + } else KJ_IF_MAYBE(subResult, subParser(input)) { + ++actualCount; + } else { + return nullptr; + } + } + + return tuple(); + } +}; + +template +template +auto Times_::operator()(Input& input) const + -> decltype(Impl::apply(instance(), instance(), input)) { + return Impl>::apply(subParser, count, input); +} + +template +constexpr Times_ times(SubParser&& subParser, uint count) { + // Constructs a parser that repeats the subParser exactly `count` times. + return Times_(kj::fwd(subParser), count); +} + +// ------------------------------------------------------------------- +// optional() +// Output = Maybe + +template +class Optional_ { +public: + explicit constexpr Optional_(SubParser&& subParser) + : subParser(kj::fwd(subParser)) {} + + template + Maybe>> operator()(Input& input) const { + typedef Maybe> Result; + + Input subInput(input); + KJ_IF_MAYBE(subResult, subParser(subInput)) { + subInput.advanceParent(); + return Result(kj::mv(*subResult)); + } else { + return Result(nullptr); + } + } + +private: + SubParser subParser; +}; + +template +constexpr Optional_ optional(SubParser&& subParser) { + // Constructs a parser that accepts zero or one of the given sub-parser, returning a Maybe + // of the sub-parser's result. + return Optional_(kj::fwd(subParser)); +} + +// ------------------------------------------------------------------- +// oneOf() +// All SubParsers must have same output type, which becomes the output type of the +// OneOfParser. + +template +class OneOf_; + +template +class OneOf_ { +public: + explicit constexpr OneOf_(FirstSubParser&& firstSubParser, SubParsers&&... rest) + : first(kj::fwd(firstSubParser)), rest(kj::fwd(rest)...) {} + + template + Maybe> operator()(Input& input) const { + { + Input subInput(input); + Maybe> firstResult = first(subInput); + + if (firstResult != nullptr) { + subInput.advanceParent(); + return kj::mv(firstResult); + } + } + + // Hoping for some tail recursion here... + return rest(input); + } + +private: + FirstSubParser first; + OneOf_ rest; +}; + +template <> +class OneOf_<> { +public: + template + decltype(nullptr) operator()(Input& input) const { + return nullptr; + } +}; + +template +constexpr OneOf_ oneOf(SubParsers&&... parsers) { + // Constructs a parser that accepts one of a set of options. The parser behaves as the first + // sub-parser in the list which returns successfully. All of the sub-parsers must return the + // same type. + return OneOf_(kj::fwd(parsers)...); +} + +// ------------------------------------------------------------------- +// transform() +// Output = Result of applying transform functor to input value. If input is a tuple, it is +// unpacked to form the transformation parameters. + +template +struct Span { +public: + inline const Position& begin() const { return begin_; } + inline const Position& end() const { return end_; } + + Span() = default; + inline constexpr Span(Position&& begin, Position&& end): begin_(mv(begin)), end_(mv(end)) {} + +private: + Position begin_; + Position end_; +}; + +template +constexpr Span> span(Position&& start, Position&& end) { + return Span>(kj::fwd(start), kj::fwd(end)); +} + +template +class Transform_ { +public: + explicit constexpr Transform_(SubParser&& subParser, TransformFunc&& transform) + : subParser(kj::fwd(subParser)), transform(kj::fwd(transform)) {} + + template + Maybe(), + instance&&>()))> + operator()(Input& input) const { + KJ_IF_MAYBE(subResult, subParser(input)) { + return kj::apply(transform, kj::mv(*subResult)); + } else { + return nullptr; + } + } + +private: + SubParser subParser; + TransformFunc transform; +}; + +template +class TransformOrReject_ { +public: + explicit constexpr TransformOrReject_(SubParser&& subParser, TransformFunc&& transform) + : subParser(kj::fwd(subParser)), transform(kj::fwd(transform)) {} + + template + decltype(kj::apply(instance(), instance&&>())) + operator()(Input& input) const { + KJ_IF_MAYBE(subResult, subParser(input)) { + return kj::apply(transform, kj::mv(*subResult)); + } else { + return nullptr; + } + } + +private: + SubParser subParser; + TransformFunc transform; +}; + +template +class TransformWithLocation_ { +public: + explicit constexpr TransformWithLocation_(SubParser&& subParser, TransformFunc&& transform) + : subParser(kj::fwd(subParser)), transform(kj::fwd(transform)) {} + + template + Maybe(), + instance().getPosition())>>>(), + instance&&>()))> + operator()(Input& input) const { + auto start = input.getPosition(); + KJ_IF_MAYBE(subResult, subParser(input)) { + return kj::apply(transform, Span(kj::mv(start), input.getPosition()), + kj::mv(*subResult)); + } else { + return nullptr; + } + } + +private: + SubParser subParser; + TransformFunc transform; +}; + +template +constexpr Transform_ transform( + SubParser&& subParser, TransformFunc&& functor) { + // Constructs a parser which executes some other parser and then transforms the result by invoking + // `functor` on it. Typically `functor` is a lambda. It is invoked using `kj::apply`, + // meaning tuples will be unpacked as arguments. + return Transform_( + kj::fwd(subParser), kj::fwd(functor)); +} + +template +constexpr TransformOrReject_ transformOrReject( + SubParser&& subParser, TransformFunc&& functor) { + // Like `transform()` except that `functor` returns a `Maybe`. If it returns null, parsing fails, + // otherwise the parser's result is the content of the `Maybe`. + return TransformOrReject_( + kj::fwd(subParser), kj::fwd(functor)); +} + +template +constexpr TransformWithLocation_ transformWithLocation( + SubParser&& subParser, TransformFunc&& functor) { + // Like `transform` except that `functor` also takes a `Span` as its first parameter specifying + // the location of the parsed content. The span's position type is whatever the parser input's + // getPosition() returns. + return TransformWithLocation_( + kj::fwd(subParser), kj::fwd(functor)); +} + +// ------------------------------------------------------------------- +// notLookingAt() +// Fails if the given parser succeeds at the current location. + +template +class NotLookingAt_ { +public: + explicit constexpr NotLookingAt_(SubParser&& subParser) + : subParser(kj::fwd(subParser)) {} + + template + Maybe> operator()(Input& input) const { + Input subInput(input); + subInput.forgetParent(); + if (subParser(subInput) == nullptr) { + return Tuple<>(); + } else { + return nullptr; + } + } + +private: + SubParser subParser; +}; + +template +constexpr NotLookingAt_ notLookingAt(SubParser&& subParser) { + // Constructs a parser which fails at any position where the given parser succeeds. Otherwise, + // it succeeds without consuming any input and returns an empty tuple. + return NotLookingAt_(kj::fwd(subParser)); +} + +// ------------------------------------------------------------------- +// endOfInput() +// Output = Tuple<>, only succeeds if at end-of-input + +class EndOfInput_ { +public: + template + Maybe> operator()(Input& input) const { + if (input.atEnd()) { + return Tuple<>(); + } else { + return nullptr; + } + } +}; + +constexpr EndOfInput_ endOfInput = EndOfInput_(); +// A parser that succeeds only if it is called with no input. + +} // namespace parse +} // namespace kj + +#endif // KJ_PARSE_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/refcount.h --- a/osx/include/kj/refcount.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/refcount.h Mon May 22 10:01:37 2017 +0100 @@ -1,107 +1,107 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "memory.h" - -#ifndef KJ_REFCOUNT_H_ -#define KJ_REFCOUNT_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -namespace kj { - -class Refcounted: private Disposer { - // Subclass this to create a class that contains a reference count. Then, use - // `kj::refcounted()` to allocate a new refcounted pointer. - // - // Do NOT use this lightly. Refcounting is a crutch. Good designs should strive to make object - // ownership clear, so that refcounting is not necessary. All that said, reference counting can - // sometimes simplify code that would otherwise become convoluted with explicit ownership, even - // when ownership relationships are clear at an abstract level. - // - // NOT THREADSAFE: This refcounting implementation assumes that an object's references are - // manipulated only in one thread, because atomic (thread-safe) refcounting is surprisingly slow. - // - // In general, abstract classes should _not_ subclass this. The concrete class at the bottom - // of the hierarchy should be the one to decide how it implements refcounting. Interfaces should - // expose only an `addRef()` method that returns `Own`. There are two reasons for - // this rule: - // 1. Interfaces would need to virtually inherit Refcounted, otherwise two refcounted interfaces - // could not be inherited by the same subclass. Virtual inheritance is awkward and - // inefficient. - // 2. An implementation may decide that it would rather return a copy than a refcount, or use - // some other strategy. - // - // TODO(cleanup): Rethink above. Virtual inheritance is not necessarily that bad. OTOH, a - // virtual function call for every refcount is sad in its own way. A Ref type to replace - // Own could also be nice. - -public: - virtual ~Refcounted() noexcept(false); - - inline bool isShared() const { return refcount > 1; } - // Check if there are multiple references to this object. This is sometimes useful for deciding - // whether it's safe to modify the object vs. make a copy. - -private: - mutable uint refcount = 0; - // "mutable" because disposeImpl() is const. Bleh. - - void disposeImpl(void* pointer) const override; - template - static Own addRefInternal(T* object); - - template - friend Own addRef(T& object); - template - friend Own refcounted(Params&&... params); -}; - -template -inline Own refcounted(Params&&... params) { - // Allocate a new refcounted instance of T, passing `params` to its constructor. Returns an - // initial reference to the object. More references can be created with `kj::addRef()`. - - return Refcounted::addRefInternal(new T(kj::fwd(params)...)); -} - -template -Own addRef(T& object) { - // Return a new reference to `object`, which must subclass Refcounted and have been allocated - // using `kj::refcounted<>()`. It is suggested that subclasses implement a non-static addRef() - // method which wraps this and returns the appropriate type. - - KJ_IREQUIRE(object.Refcounted::refcount > 0, "Object not allocated with kj::refcounted()."); - return Refcounted::addRefInternal(&object); -} - -template -Own Refcounted::addRefInternal(T* object) { - Refcounted* refcounted = object; - ++refcounted->refcount; - return Own(object, *refcounted); -} - -} // namespace kj - -#endif // KJ_REFCOUNT_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "memory.h" + +#ifndef KJ_REFCOUNT_H_ +#define KJ_REFCOUNT_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +namespace kj { + +class Refcounted: private Disposer { + // Subclass this to create a class that contains a reference count. Then, use + // `kj::refcounted()` to allocate a new refcounted pointer. + // + // Do NOT use this lightly. Refcounting is a crutch. Good designs should strive to make object + // ownership clear, so that refcounting is not necessary. All that said, reference counting can + // sometimes simplify code that would otherwise become convoluted with explicit ownership, even + // when ownership relationships are clear at an abstract level. + // + // NOT THREADSAFE: This refcounting implementation assumes that an object's references are + // manipulated only in one thread, because atomic (thread-safe) refcounting is surprisingly slow. + // + // In general, abstract classes should _not_ subclass this. The concrete class at the bottom + // of the hierarchy should be the one to decide how it implements refcounting. Interfaces should + // expose only an `addRef()` method that returns `Own`. There are two reasons for + // this rule: + // 1. Interfaces would need to virtually inherit Refcounted, otherwise two refcounted interfaces + // could not be inherited by the same subclass. Virtual inheritance is awkward and + // inefficient. + // 2. An implementation may decide that it would rather return a copy than a refcount, or use + // some other strategy. + // + // TODO(cleanup): Rethink above. Virtual inheritance is not necessarily that bad. OTOH, a + // virtual function call for every refcount is sad in its own way. A Ref type to replace + // Own could also be nice. + +public: + virtual ~Refcounted() noexcept(false); + + inline bool isShared() const { return refcount > 1; } + // Check if there are multiple references to this object. This is sometimes useful for deciding + // whether it's safe to modify the object vs. make a copy. + +private: + mutable uint refcount = 0; + // "mutable" because disposeImpl() is const. Bleh. + + void disposeImpl(void* pointer) const override; + template + static Own addRefInternal(T* object); + + template + friend Own addRef(T& object); + template + friend Own refcounted(Params&&... params); +}; + +template +inline Own refcounted(Params&&... params) { + // Allocate a new refcounted instance of T, passing `params` to its constructor. Returns an + // initial reference to the object. More references can be created with `kj::addRef()`. + + return Refcounted::addRefInternal(new T(kj::fwd(params)...)); +} + +template +Own addRef(T& object) { + // Return a new reference to `object`, which must subclass Refcounted and have been allocated + // using `kj::refcounted<>()`. It is suggested that subclasses implement a non-static addRef() + // method which wraps this and returns the appropriate type. + + KJ_IREQUIRE(object.Refcounted::refcount > 0, "Object not allocated with kj::refcounted()."); + return Refcounted::addRefInternal(&object); +} + +template +Own Refcounted::addRefInternal(T* object) { + Refcounted* refcounted = object; + ++refcounted->refcount; + return Own(object, *refcounted); +} + +} // namespace kj + +#endif // KJ_REFCOUNT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/std/iostream.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx/include/kj/std/iostream.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,88 @@ +// Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * Compatibility layer for stdlib iostream + */ + +#ifndef KJ_STD_IOSTREAM_H_ +#define KJ_STD_IOSTREAM_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "../io.h" +#include + +namespace kj { +namespace std { + +class StdOutputStream: public kj::OutputStream { + +public: + explicit StdOutputStream(::std::ostream& stream) : stream_(stream) {} + ~StdOutputStream() noexcept(false) {} + + virtual void write(const void* src, size_t size) override { + // Always writes the full size. + + stream_.write((char*)src, size); + } + + virtual void write(ArrayPtr> pieces) override { + // Equivalent to write()ing each byte array in sequence, which is what the + // default implementation does. Override if you can do something better, + // e.g. use writev() to do the write in a single syscall. + + for (auto piece : pieces) { + write(piece.begin(), piece.size()); + } + } + +private: + ::std::ostream& stream_; + +}; + +class StdInputStream: public kj::InputStream { + +public: + explicit StdInputStream(::std::istream& stream) : stream_(stream) {} + ~StdInputStream() noexcept(false) {} + + virtual size_t tryRead( + void* buffer, size_t minBytes, size_t maxBytes) override { + // Like read(), but may return fewer than minBytes on EOF. + + stream_.read((char*)buffer, maxBytes); + return stream_.gcount(); + } + +private: + ::std::istream& stream_; + +}; + +} // namespace std +} // namespace kj + +#endif // KJ_STD_IOSTREAM_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/string-tree.h --- a/osx/include/kj/string-tree.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/string-tree.h Mon May 22 10:01:37 2017 +0100 @@ -1,212 +1,212 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_STRING_TREE_H_ -#define KJ_STRING_TREE_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "string.h" - -namespace kj { - -class StringTree { - // A long string, represented internally as a tree of strings. This data structure is like a - // String, but optimized for concatenation and iteration at the expense of seek time. The - // structure is intended to be used for building large text blobs from many small pieces, where - // repeatedly concatenating smaller strings into larger ones would waste copies. This structure - // is NOT intended for use cases requiring random access or computing substrings. For those, - // you should use a Rope, which is a much more complicated data structure. - // - // The proper way to construct a StringTree is via kj::strTree(...), which works just like - // kj::str(...) but returns a StringTree rather than a String. - // - // KJ_STRINGIFY() functions that construct large strings from many smaller strings are encouraged - // to return StringTree rather than a flat char container. - -public: - inline StringTree(): size_(0) {} - inline StringTree(String&& text): size_(text.size()), text(kj::mv(text)) {} - - StringTree(Array&& pieces, StringPtr delim); - // Build a StringTree by concatenating the given pieces, delimited by the given delimiter - // (e.g. ", "). - - inline size_t size() const { return size_; } - - template - void visit(Func&& func) const; - - String flatten() const; - // Return the contents as a string. - - // TODO(someday): flatten() when *this is an rvalue and when branches.size() == 0 could simply - // return `kj::mv(text)`. Requires reference qualifiers (Clang 3.3 / GCC 4.8). - - void flattenTo(char* __restrict__ target) const; - // Copy the contents to the given character array. Does not add a NUL terminator. - -private: - size_t size_; - String text; - - struct Branch; - Array branches; // In order. - - inline void fill(char* pos, size_t branchIndex); - template - void fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest); - template - void fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest); - template - void fill(char* pos, size_t branchIndex, Array&& first, Rest&&... rest); - template - void fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest); - - template - static StringTree concat(Params&&... params); - static StringTree&& concat(StringTree&& param) { return kj::mv(param); } - - template - static inline size_t flatSize(const T& t) { return t.size(); } - static inline size_t flatSize(String&& s) { return 0; } - static inline size_t flatSize(StringTree&& s) { return 0; } - - template - static inline size_t branchCount(const T& t) { return 0; } - static inline size_t branchCount(String&& s) { return 1; } - static inline size_t branchCount(StringTree&& s) { return 1; } - - template - friend StringTree strTree(Params&&... params); -}; - -inline StringTree&& KJ_STRINGIFY(StringTree&& tree) { return kj::mv(tree); } -inline const StringTree& KJ_STRINGIFY(const StringTree& tree) { return tree; } - -inline StringTree KJ_STRINGIFY(Array&& trees) { return StringTree(kj::mv(trees), ""); } - -template -StringTree strTree(Params&&... params); -// Build a StringTree by stringifying the given parameters and concatenating the results. -// If any of the parameters stringify to StringTree rvalues, they will be incorporated as -// branches to avoid a copy. - -// ======================================================================================= -// Inline implementation details - -namespace _ { // private - -template -char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest) { - // Make str() work with stringifiers that return StringTree by patching fill(). - - first.flattenTo(target); - return fill(target + first.size(), kj::fwd(rest)...); -} - -template constexpr bool isStringTree() { return false; } -template <> constexpr bool isStringTree() { return true; } - -inline StringTree&& toStringTreeOrCharSequence(StringTree&& tree) { return kj::mv(tree); } -inline StringTree toStringTreeOrCharSequence(String&& str) { return StringTree(kj::mv(str)); } - -template -inline auto toStringTreeOrCharSequence(T&& value) - -> decltype(toCharSequence(kj::fwd(value))) { - static_assert(!isStringTree>(), - "When passing a StringTree into kj::strTree(), either pass it by rvalue " - "(use kj::mv(value)) or explicitly call value.flatten() to make a copy."); - - return toCharSequence(kj::fwd(value)); -} - -} // namespace _ (private) - -struct StringTree::Branch { - size_t index; - // Index in `text` where this branch should be inserted. - - StringTree content; -}; - -template -void StringTree::visit(Func&& func) const { - size_t pos = 0; - for (auto& branch: branches) { - if (branch.index > pos) { - func(text.slice(pos, branch.index)); - pos = branch.index; - } - branch.content.visit(func); - } - if (text.size() > pos) { - func(text.slice(pos, text.size())); - } -} - -inline void StringTree::fill(char* pos, size_t branchIndex) { - KJ_IREQUIRE(pos == text.end() && branchIndex == branches.size(), - kj::str(text.end() - pos, ' ', branches.size() - branchIndex).cStr()); -} - -template -void StringTree::fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest) { - pos = _::fill(pos, kj::fwd(first)); - fill(pos, branchIndex, kj::fwd(rest)...); -} - -template -void StringTree::fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest) { - branches[branchIndex].index = pos - text.begin(); - branches[branchIndex].content = kj::mv(first); - fill(pos, branchIndex + 1, kj::fwd(rest)...); -} - -template -void StringTree::fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest) { - branches[branchIndex].index = pos - text.begin(); - branches[branchIndex].content = StringTree(kj::mv(first)); - fill(pos, branchIndex + 1, kj::fwd(rest)...); -} - -template -StringTree StringTree::concat(Params&&... params) { - StringTree result; - result.size_ = _::sum({params.size()...}); - result.text = heapString( - _::sum({StringTree::flatSize(kj::fwd(params))...})); - result.branches = heapArray( - _::sum({StringTree::branchCount(kj::fwd(params))...})); - result.fill(result.text.begin(), 0, kj::fwd(params)...); - return result; -} - -template -StringTree strTree(Params&&... params) { - return StringTree::concat(_::toStringTreeOrCharSequence(kj::fwd(params))...); -} - -} // namespace kj - -#endif // KJ_STRING_TREE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_STRING_TREE_H_ +#define KJ_STRING_TREE_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "string.h" + +namespace kj { + +class StringTree { + // A long string, represented internally as a tree of strings. This data structure is like a + // String, but optimized for concatenation and iteration at the expense of seek time. The + // structure is intended to be used for building large text blobs from many small pieces, where + // repeatedly concatenating smaller strings into larger ones would waste copies. This structure + // is NOT intended for use cases requiring random access or computing substrings. For those, + // you should use a Rope, which is a much more complicated data structure. + // + // The proper way to construct a StringTree is via kj::strTree(...), which works just like + // kj::str(...) but returns a StringTree rather than a String. + // + // KJ_STRINGIFY() functions that construct large strings from many smaller strings are encouraged + // to return StringTree rather than a flat char container. + +public: + inline StringTree(): size_(0) {} + inline StringTree(String&& text): size_(text.size()), text(kj::mv(text)) {} + + StringTree(Array&& pieces, StringPtr delim); + // Build a StringTree by concatenating the given pieces, delimited by the given delimiter + // (e.g. ", "). + + inline size_t size() const { return size_; } + + template + void visit(Func&& func) const; + + String flatten() const; + // Return the contents as a string. + + // TODO(someday): flatten() when *this is an rvalue and when branches.size() == 0 could simply + // return `kj::mv(text)`. Requires reference qualifiers (Clang 3.3 / GCC 4.8). + + void flattenTo(char* __restrict__ target) const; + // Copy the contents to the given character array. Does not add a NUL terminator. + +private: + size_t size_; + String text; + + struct Branch; + Array branches; // In order. + + inline void fill(char* pos, size_t branchIndex); + template + void fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest); + template + void fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest); + template + void fill(char* pos, size_t branchIndex, Array&& first, Rest&&... rest); + template + void fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest); + + template + static StringTree concat(Params&&... params); + static StringTree&& concat(StringTree&& param) { return kj::mv(param); } + + template + static inline size_t flatSize(const T& t) { return t.size(); } + static inline size_t flatSize(String&& s) { return 0; } + static inline size_t flatSize(StringTree&& s) { return 0; } + + template + static inline size_t branchCount(const T& t) { return 0; } + static inline size_t branchCount(String&& s) { return 1; } + static inline size_t branchCount(StringTree&& s) { return 1; } + + template + friend StringTree strTree(Params&&... params); +}; + +inline StringTree&& KJ_STRINGIFY(StringTree&& tree) { return kj::mv(tree); } +inline const StringTree& KJ_STRINGIFY(const StringTree& tree) { return tree; } + +inline StringTree KJ_STRINGIFY(Array&& trees) { return StringTree(kj::mv(trees), ""); } + +template +StringTree strTree(Params&&... params); +// Build a StringTree by stringifying the given parameters and concatenating the results. +// If any of the parameters stringify to StringTree rvalues, they will be incorporated as +// branches to avoid a copy. + +// ======================================================================================= +// Inline implementation details + +namespace _ { // private + +template +char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest) { + // Make str() work with stringifiers that return StringTree by patching fill(). + + first.flattenTo(target); + return fill(target + first.size(), kj::fwd(rest)...); +} + +template constexpr bool isStringTree() { return false; } +template <> constexpr bool isStringTree() { return true; } + +inline StringTree&& toStringTreeOrCharSequence(StringTree&& tree) { return kj::mv(tree); } +inline StringTree toStringTreeOrCharSequence(String&& str) { return StringTree(kj::mv(str)); } + +template +inline auto toStringTreeOrCharSequence(T&& value) + -> decltype(toCharSequence(kj::fwd(value))) { + static_assert(!isStringTree>(), + "When passing a StringTree into kj::strTree(), either pass it by rvalue " + "(use kj::mv(value)) or explicitly call value.flatten() to make a copy."); + + return toCharSequence(kj::fwd(value)); +} + +} // namespace _ (private) + +struct StringTree::Branch { + size_t index; + // Index in `text` where this branch should be inserted. + + StringTree content; +}; + +template +void StringTree::visit(Func&& func) const { + size_t pos = 0; + for (auto& branch: branches) { + if (branch.index > pos) { + func(text.slice(pos, branch.index)); + pos = branch.index; + } + branch.content.visit(func); + } + if (text.size() > pos) { + func(text.slice(pos, text.size())); + } +} + +inline void StringTree::fill(char* pos, size_t branchIndex) { + KJ_IREQUIRE(pos == text.end() && branchIndex == branches.size(), + kj::str(text.end() - pos, ' ', branches.size() - branchIndex).cStr()); +} + +template +void StringTree::fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest) { + pos = _::fill(pos, kj::fwd(first)); + fill(pos, branchIndex, kj::fwd(rest)...); +} + +template +void StringTree::fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest) { + branches[branchIndex].index = pos - text.begin(); + branches[branchIndex].content = kj::mv(first); + fill(pos, branchIndex + 1, kj::fwd(rest)...); +} + +template +void StringTree::fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest) { + branches[branchIndex].index = pos - text.begin(); + branches[branchIndex].content = StringTree(kj::mv(first)); + fill(pos, branchIndex + 1, kj::fwd(rest)...); +} + +template +StringTree StringTree::concat(Params&&... params) { + StringTree result; + result.size_ = _::sum({params.size()...}); + result.text = heapString( + _::sum({StringTree::flatSize(kj::fwd(params))...})); + result.branches = heapArray( + _::sum({StringTree::branchCount(kj::fwd(params))...})); + result.fill(result.text.begin(), 0, kj::fwd(params)...); + return result; +} + +template +StringTree strTree(Params&&... params) { + return StringTree::concat(_::toStringTreeOrCharSequence(kj::fwd(params))...); +} + +} // namespace kj + +#endif // KJ_STRING_TREE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/string.h --- a/osx/include/kj/string.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/string.h Mon May 22 10:01:37 2017 +0100 @@ -1,530 +1,534 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_STRING_H_ -#define KJ_STRING_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include -#include "array.h" -#include - -namespace kj { - -class StringPtr; -class String; - -class StringTree; // string-tree.h - -// Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so -// we'll just preprocess it out if not supported. -#if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || _MSC_VER -#define KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 1 -#endif - -// ======================================================================================= -// StringPtr -- A NUL-terminated ArrayPtr containing UTF-8 text. -// -// NUL bytes are allowed to appear before the end of the string. The only requirement is that -// a NUL byte appear immediately after the last byte of the content. This terminator byte is not -// counted in the string's size. - -class StringPtr { -public: - inline StringPtr(): content("", 1) {} - inline StringPtr(decltype(nullptr)): content("", 1) {} - inline StringPtr(const char* value): content(value, strlen(value) + 1) {} - inline StringPtr(const char* value, size_t size): content(value, size + 1) { - KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); - } - inline StringPtr(const char* begin, const char* end): StringPtr(begin, end - begin) {} - inline StringPtr(const String& value); - -#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP - template ().c_str())> - inline StringPtr(const T& t): StringPtr(t.c_str()) {} - // Allow implicit conversion from any class that has a c_str() method (namely, std::string). - // We use a template trick to detect std::string in order to avoid including the header for - // those who don't want it. - - template ().c_str())> - inline operator T() const { return cStr(); } - // Allow implicit conversion to any class that has a c_str() method (namely, std::string). - // We use a template trick to detect std::string in order to avoid including the header for - // those who don't want it. -#endif - - inline operator ArrayPtr() const; - inline ArrayPtr asArray() const; - inline ArrayPtr asBytes() const { return asArray().asBytes(); } - // Result does not include NUL terminator. - - inline const char* cStr() const { return content.begin(); } - // Returns NUL-terminated string. - - inline size_t size() const { return content.size() - 1; } - // Result does not include NUL terminator. - - inline char operator[](size_t index) const { return content[index]; } - - inline const char* begin() const { return content.begin(); } - inline const char* end() const { return content.end() - 1; } - - inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } - inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } - - inline bool operator==(const StringPtr& other) const; - inline bool operator!=(const StringPtr& other) const { return !(*this == other); } - inline bool operator< (const StringPtr& other) const; - inline bool operator> (const StringPtr& other) const { return other < *this; } - inline bool operator<=(const StringPtr& other) const { return !(other < *this); } - inline bool operator>=(const StringPtr& other) const { return !(*this < other); } - - inline StringPtr slice(size_t start) const; - inline ArrayPtr slice(size_t start, size_t end) const; - // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter - // version that assumes end = size(). - - inline bool startsWith(const StringPtr& other) const; - inline bool endsWith(const StringPtr& other) const; - - inline Maybe findFirst(char c) const; - inline Maybe findLast(char c) const; - - template - T parseAs() const; - // Parse string as template number type. - // Integer numbers prefixed by "0x" and "0X" are parsed in base 16 (like strtoi with base 0). - // Integer numbers prefixed by "0" are parsed in base 10 (unlike strtoi with base 0). - // Overflowed integer numbers throw exception. - // Overflowed floating numbers return inf. - -private: - inline StringPtr(ArrayPtr content): content(content) {} - - ArrayPtr content; -}; - -inline bool operator==(const char* a, const StringPtr& b) { return b == a; } -inline bool operator!=(const char* a, const StringPtr& b) { return b != a; } - -template <> char StringPtr::parseAs() const; -template <> signed char StringPtr::parseAs() const; -template <> unsigned char StringPtr::parseAs() const; -template <> short StringPtr::parseAs() const; -template <> unsigned short StringPtr::parseAs() const; -template <> int StringPtr::parseAs() const; -template <> unsigned StringPtr::parseAs() const; -template <> long StringPtr::parseAs() const; -template <> unsigned long StringPtr::parseAs() const; -template <> long long StringPtr::parseAs() const; -template <> unsigned long long StringPtr::parseAs() const; -template <> float StringPtr::parseAs() const; -template <> double StringPtr::parseAs() const; - -// ======================================================================================= -// String -- A NUL-terminated Array containing UTF-8 text. -// -// NUL bytes are allowed to appear before the end of the string. The only requirement is that -// a NUL byte appear immediately after the last byte of the content. This terminator byte is not -// counted in the string's size. -// -// To allocate a String, you must call kj::heapString(). We do not implement implicit copying to -// the heap because this hides potential inefficiency from the developer. - -class String { -public: - String() = default; - inline String(decltype(nullptr)): content(nullptr) {} - inline String(char* value, size_t size, const ArrayDisposer& disposer); - // Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated. - inline explicit String(Array buffer); - // Does not copy. Requires `buffer` ends with `\0`. - - inline operator ArrayPtr(); - inline operator ArrayPtr() const; - inline ArrayPtr asArray(); - inline ArrayPtr asArray() const; - inline ArrayPtr asBytes() { return asArray().asBytes(); } - inline ArrayPtr asBytes() const { return asArray().asBytes(); } - // Result does not include NUL terminator. - - inline const char* cStr() const; - - inline size_t size() const; - // Result does not include NUL terminator. - - inline char operator[](size_t index) const; - inline char& operator[](size_t index); - - inline char* begin(); - inline char* end(); - inline const char* begin() const; - inline const char* end() const; - - inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } - inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } - - inline bool operator==(const StringPtr& other) const { return StringPtr(*this) == other; } - inline bool operator!=(const StringPtr& other) const { return StringPtr(*this) != other; } - inline bool operator< (const StringPtr& other) const { return StringPtr(*this) < other; } - inline bool operator> (const StringPtr& other) const { return StringPtr(*this) > other; } - inline bool operator<=(const StringPtr& other) const { return StringPtr(*this) <= other; } - inline bool operator>=(const StringPtr& other) const { return StringPtr(*this) >= other; } - - inline bool startsWith(const StringPtr& other) const { return StringPtr(*this).startsWith(other);} - inline bool endsWith(const StringPtr& other) const { return StringPtr(*this).endsWith(other); } - - inline StringPtr slice(size_t start) const { return StringPtr(*this).slice(start); } - inline ArrayPtr slice(size_t start, size_t end) const { - return StringPtr(*this).slice(start, end); - } - - inline Maybe findFirst(char c) const { return StringPtr(*this).findFirst(c); } - inline Maybe findLast(char c) const { return StringPtr(*this).findLast(c); } - - template - T parseAs() const { return StringPtr(*this).parseAs(); } - // Parse as number - -private: - Array content; -}; - -inline bool operator==(const char* a, const String& b) { return b == a; } -inline bool operator!=(const char* a, const String& b) { return b != a; } - -String heapString(size_t size); -// Allocate a String of the given size on the heap, not including NUL terminator. The NUL -// terminator will be initialized automatically but the rest of the content is not initialized. - -String heapString(const char* value); -String heapString(const char* value, size_t size); -String heapString(StringPtr value); -String heapString(const String& value); -String heapString(ArrayPtr value); -// Allocates a copy of the given value on the heap. - -// ======================================================================================= -// Magic str() function which transforms parameters to text and concatenates them into one big -// String. - -namespace _ { // private - -inline size_t sum(std::initializer_list nums) { - size_t result = 0; - for (auto num: nums) { - result += num; - } - return result; -} - -inline char* fill(char* ptr) { return ptr; } - -template -char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest); -// Make str() work with stringifiers that return StringTree by patching fill(). -// -// Defined in string-tree.h. - -template -char* fill(char* __restrict__ target, const First& first, Rest&&... rest) { - auto i = first.begin(); - auto end = first.end(); - while (i != end) { - *target++ = *i++; - } - return fill(target, kj::fwd(rest)...); -} - -template -String concat(Params&&... params) { - // Concatenate a bunch of containers into a single Array. The containers can be anything that - // is iterable and whose elements can be converted to `char`. - - String result = heapString(sum({params.size()...})); - fill(result.begin(), kj::fwd(params)...); - return result; -} - -inline String concat(String&& arr) { - return kj::mv(arr); -} - -struct Stringifier { - // This is a dummy type with only one instance: STR (below). To make an arbitrary type - // stringifiable, define `operator*(Stringifier, T)` to return an iterable container of `char`. - // The container type must have a `size()` method. Be sure to declare the operator in the same - // namespace as `T` **or** in the global scope. - // - // A more usual way to accomplish what we're doing here would be to require that you define - // a function like `toString(T)` and then rely on argument-dependent lookup. However, this has - // the problem that it pollutes other people's namespaces and even the global namespace. For - // example, some other project may already have functions called `toString` which do something - // different. Declaring `operator*` with `Stringifier` as the left operand cannot conflict with - // anything. - - inline ArrayPtr operator*(ArrayPtr s) const { return s; } - inline ArrayPtr operator*(ArrayPtr s) const { return s; } - inline ArrayPtr operator*(const Array& s) const { return s; } - inline ArrayPtr operator*(const Array& s) const { return s; } - template - inline ArrayPtr operator*(const CappedArray& s) const { return s; } - template - inline ArrayPtr operator*(const FixedArray& s) const { return s; } - inline ArrayPtr operator*(const char* s) const { return arrayPtr(s, strlen(s)); } - inline ArrayPtr operator*(const String& s) const { return s.asArray(); } - inline ArrayPtr operator*(const StringPtr& s) const { return s.asArray(); } - - inline Range operator*(const Range& r) const { return r; } - inline Repeat operator*(const Repeat& r) const { return r; } - - inline FixedArray operator*(char c) const { - FixedArray result; - result[0] = c; - return result; - } - - StringPtr operator*(decltype(nullptr)) const; - StringPtr operator*(bool b) const; - - CappedArray operator*(signed char i) const; - CappedArray operator*(unsigned char i) const; - CappedArray operator*(short i) const; - CappedArray operator*(unsigned short i) const; - CappedArray operator*(int i) const; - CappedArray operator*(unsigned int i) const; - CappedArray operator*(long i) const; - CappedArray operator*(unsigned long i) const; - CappedArray operator*(long long i) const; - CappedArray operator*(unsigned long long i) const; - CappedArray operator*(float f) const; - CappedArray operator*(double f) const; - CappedArray operator*(const void* s) const; - - template - String operator*(ArrayPtr arr) const; - template - String operator*(const Array& arr) const; - -#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP // supports expression SFINAE? - template ().toString())> - inline Result operator*(T&& value) const { return kj::fwd(value).toString(); } -#endif -}; -static KJ_CONSTEXPR(const) Stringifier STR = Stringifier(); - -} // namespace _ (private) - -template -auto toCharSequence(T&& value) -> decltype(_::STR * kj::fwd(value)) { - // Returns an iterable of chars that represent a textual representation of the value, suitable - // for debugging. - // - // Most users should use str() instead, but toCharSequence() may occasionally be useful to avoid - // heap allocation overhead that str() implies. - // - // To specialize this function for your type, see KJ_STRINGIFY. - - return _::STR * kj::fwd(value); -} - -CappedArray hex(unsigned char i); -CappedArray hex(unsigned short i); -CappedArray hex(unsigned int i); -CappedArray hex(unsigned long i); -CappedArray hex(unsigned long long i); - -template -String str(Params&&... params) { - // Magic function which builds a string from a bunch of arbitrary values. Example: - // str(1, " / ", 2, " = ", 0.5) - // returns: - // "1 / 2 = 0.5" - // To teach `str` how to stringify a type, see `Stringifier`. - - return _::concat(toCharSequence(kj::fwd(params))...); -} - -inline String str(String&& s) { return mv(s); } -// Overload to prevent redundant allocation. - -template -String strArray(T&& arr, const char* delim) { - size_t delimLen = strlen(delim); - KJ_STACK_ARRAY(decltype(_::STR * arr[0]), pieces, kj::size(arr), 8, 32); - size_t size = 0; - for (size_t i = 0; i < kj::size(arr); i++) { - if (i > 0) size += delimLen; - pieces[i] = _::STR * arr[i]; - size += pieces[i].size(); - } - - String result = heapString(size); - char* pos = result.begin(); - for (size_t i = 0; i < kj::size(arr); i++) { - if (i > 0) { - memcpy(pos, delim, delimLen); - pos += delimLen; - } - pos = _::fill(pos, pieces[i]); - } - return result; -} - -namespace _ { // private - -template -inline String Stringifier::operator*(ArrayPtr arr) const { - return strArray(arr, ", "); -} - -template -inline String Stringifier::operator*(const Array& arr) const { - return strArray(arr, ", "); -} - -} // namespace _ (private) - -#define KJ_STRINGIFY(...) operator*(::kj::_::Stringifier, __VA_ARGS__) -// Defines a stringifier for a custom type. Example: -// -// class Foo {...}; -// inline StringPtr KJ_STRINGIFY(const Foo& foo) { return foo.name(); } -// -// This allows Foo to be passed to str(). -// -// The function should be declared either in the same namespace as the target type or in the global -// namespace. It can return any type which is an iterable container of chars. - -// ======================================================================================= -// Inline implementation details. - -inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {} - -inline StringPtr::operator ArrayPtr() const { - return content.slice(0, content.size() - 1); -} - -inline ArrayPtr StringPtr::asArray() const { - return content.slice(0, content.size() - 1); -} - -inline bool StringPtr::operator==(const StringPtr& other) const { - return content.size() == other.content.size() && - memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0; -} - -inline bool StringPtr::operator<(const StringPtr& other) const { - bool shorter = content.size() < other.content.size(); - int cmp = memcmp(content.begin(), other.content.begin(), - shorter ? content.size() : other.content.size()); - return cmp < 0 || (cmp == 0 && shorter); -} - -inline StringPtr StringPtr::slice(size_t start) const { - return StringPtr(content.slice(start, content.size())); -} -inline ArrayPtr StringPtr::slice(size_t start, size_t end) const { - return content.slice(start, end); -} - -inline bool StringPtr::startsWith(const StringPtr& other) const { - return other.content.size() <= content.size() && - memcmp(content.begin(), other.content.begin(), other.size()) == 0; -} -inline bool StringPtr::endsWith(const StringPtr& other) const { - return other.content.size() <= content.size() && - memcmp(end() - other.size(), other.content.begin(), other.size()) == 0; -} - -inline Maybe StringPtr::findFirst(char c) const { - const char* pos = reinterpret_cast(memchr(content.begin(), c, size())); - if (pos == nullptr) { - return nullptr; - } else { - return pos - content.begin(); - } -} - -inline Maybe StringPtr::findLast(char c) const { - for (size_t i = size(); i > 0; --i) { - if (content[i-1] == c) { - return i-1; - } - } - return nullptr; -} - -inline String::operator ArrayPtr() { - return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); -} -inline String::operator ArrayPtr() const { - return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); -} - -inline ArrayPtr String::asArray() { - return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); -} -inline ArrayPtr String::asArray() const { - return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); -} - -inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); } - -inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; } - -inline char String::operator[](size_t index) const { return content[index]; } -inline char& String::operator[](size_t index) { return content[index]; } - -inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); } -inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; } -inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); } -inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; } - -inline String::String(char* value, size_t size, const ArrayDisposer& disposer) - : content(value, size + 1, disposer) { - KJ_IREQUIRE(value[size] == '\0', "String must be NUL-terminated."); -} - -inline String::String(Array buffer): content(kj::mv(buffer)) { - KJ_IREQUIRE(content.size() > 0 && content.back() == '\0', "String must be NUL-terminated."); -} - -inline String heapString(const char* value) { - return heapString(value, strlen(value)); -} -inline String heapString(StringPtr value) { - return heapString(value.begin(), value.size()); -} -inline String heapString(const String& value) { - return heapString(value.begin(), value.size()); -} -inline String heapString(ArrayPtr value) { - return heapString(value.begin(), value.size()); -} - -} // namespace kj - -#endif // KJ_STRING_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_STRING_H_ +#define KJ_STRING_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include +#include "array.h" +#include + +namespace kj { + +class StringPtr; +class String; + +class StringTree; // string-tree.h + +// Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so +// we'll just preprocess it out if not supported. +#if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || _MSC_VER +#define KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 1 +#endif + +// ======================================================================================= +// StringPtr -- A NUL-terminated ArrayPtr containing UTF-8 text. +// +// NUL bytes are allowed to appear before the end of the string. The only requirement is that +// a NUL byte appear immediately after the last byte of the content. This terminator byte is not +// counted in the string's size. + +class StringPtr { +public: + inline StringPtr(): content("", 1) {} + inline StringPtr(decltype(nullptr)): content("", 1) {} + inline StringPtr(const char* value): content(value, strlen(value) + 1) {} + inline StringPtr(const char* value, size_t size): content(value, size + 1) { + KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); + } + inline StringPtr(const char* begin, const char* end): StringPtr(begin, end - begin) {} + inline StringPtr(const String& value); + +#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP + template ().c_str())> + inline StringPtr(const T& t): StringPtr(t.c_str()) {} + // Allow implicit conversion from any class that has a c_str() method (namely, std::string). + // We use a template trick to detect std::string in order to avoid including the header for + // those who don't want it. + + template ().c_str())> + inline operator T() const { return cStr(); } + // Allow implicit conversion to any class that has a c_str() method (namely, std::string). + // We use a template trick to detect std::string in order to avoid including the header for + // those who don't want it. +#endif + + inline operator ArrayPtr() const; + inline ArrayPtr asArray() const; + inline ArrayPtr asBytes() const { return asArray().asBytes(); } + // Result does not include NUL terminator. + + inline const char* cStr() const { return content.begin(); } + // Returns NUL-terminated string. + + inline size_t size() const { return content.size() - 1; } + // Result does not include NUL terminator. + + inline char operator[](size_t index) const { return content[index]; } + + inline const char* begin() const { return content.begin(); } + inline const char* end() const { return content.end() - 1; } + + inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } + inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } + + inline bool operator==(const StringPtr& other) const; + inline bool operator!=(const StringPtr& other) const { return !(*this == other); } + inline bool operator< (const StringPtr& other) const; + inline bool operator> (const StringPtr& other) const { return other < *this; } + inline bool operator<=(const StringPtr& other) const { return !(other < *this); } + inline bool operator>=(const StringPtr& other) const { return !(*this < other); } + + inline StringPtr slice(size_t start) const; + inline ArrayPtr slice(size_t start, size_t end) const; + // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter + // version that assumes end = size(). + + inline bool startsWith(const StringPtr& other) const; + inline bool endsWith(const StringPtr& other) const; + + inline Maybe findFirst(char c) const; + inline Maybe findLast(char c) const; + + template + T parseAs() const; + // Parse string as template number type. + // Integer numbers prefixed by "0x" and "0X" are parsed in base 16 (like strtoi with base 0). + // Integer numbers prefixed by "0" are parsed in base 10 (unlike strtoi with base 0). + // Overflowed integer numbers throw exception. + // Overflowed floating numbers return inf. + +private: + inline StringPtr(ArrayPtr content): content(content) {} + + ArrayPtr content; +}; + +inline bool operator==(const char* a, const StringPtr& b) { return b == a; } +inline bool operator!=(const char* a, const StringPtr& b) { return b != a; } + +template <> char StringPtr::parseAs() const; +template <> signed char StringPtr::parseAs() const; +template <> unsigned char StringPtr::parseAs() const; +template <> short StringPtr::parseAs() const; +template <> unsigned short StringPtr::parseAs() const; +template <> int StringPtr::parseAs() const; +template <> unsigned StringPtr::parseAs() const; +template <> long StringPtr::parseAs() const; +template <> unsigned long StringPtr::parseAs() const; +template <> long long StringPtr::parseAs() const; +template <> unsigned long long StringPtr::parseAs() const; +template <> float StringPtr::parseAs() const; +template <> double StringPtr::parseAs() const; + +// ======================================================================================= +// String -- A NUL-terminated Array containing UTF-8 text. +// +// NUL bytes are allowed to appear before the end of the string. The only requirement is that +// a NUL byte appear immediately after the last byte of the content. This terminator byte is not +// counted in the string's size. +// +// To allocate a String, you must call kj::heapString(). We do not implement implicit copying to +// the heap because this hides potential inefficiency from the developer. + +class String { +public: + String() = default; + inline String(decltype(nullptr)): content(nullptr) {} + inline String(char* value, size_t size, const ArrayDisposer& disposer); + // Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated. + inline explicit String(Array buffer); + // Does not copy. Requires `buffer` ends with `\0`. + + inline operator ArrayPtr(); + inline operator ArrayPtr() const; + inline ArrayPtr asArray(); + inline ArrayPtr asArray() const; + inline ArrayPtr asBytes() { return asArray().asBytes(); } + inline ArrayPtr asBytes() const { return asArray().asBytes(); } + // Result does not include NUL terminator. + + inline Array releaseArray() { return kj::mv(content); } + // Disowns the backing array (which includes the NUL terminator) and returns it. The String value + // is clobbered (as if moved away). + + inline const char* cStr() const; + + inline size_t size() const; + // Result does not include NUL terminator. + + inline char operator[](size_t index) const; + inline char& operator[](size_t index); + + inline char* begin(); + inline char* end(); + inline const char* begin() const; + inline const char* end() const; + + inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } + inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } + + inline bool operator==(const StringPtr& other) const { return StringPtr(*this) == other; } + inline bool operator!=(const StringPtr& other) const { return StringPtr(*this) != other; } + inline bool operator< (const StringPtr& other) const { return StringPtr(*this) < other; } + inline bool operator> (const StringPtr& other) const { return StringPtr(*this) > other; } + inline bool operator<=(const StringPtr& other) const { return StringPtr(*this) <= other; } + inline bool operator>=(const StringPtr& other) const { return StringPtr(*this) >= other; } + + inline bool startsWith(const StringPtr& other) const { return StringPtr(*this).startsWith(other);} + inline bool endsWith(const StringPtr& other) const { return StringPtr(*this).endsWith(other); } + + inline StringPtr slice(size_t start) const { return StringPtr(*this).slice(start); } + inline ArrayPtr slice(size_t start, size_t end) const { + return StringPtr(*this).slice(start, end); + } + + inline Maybe findFirst(char c) const { return StringPtr(*this).findFirst(c); } + inline Maybe findLast(char c) const { return StringPtr(*this).findLast(c); } + + template + T parseAs() const { return StringPtr(*this).parseAs(); } + // Parse as number + +private: + Array content; +}; + +inline bool operator==(const char* a, const String& b) { return b == a; } +inline bool operator!=(const char* a, const String& b) { return b != a; } + +String heapString(size_t size); +// Allocate a String of the given size on the heap, not including NUL terminator. The NUL +// terminator will be initialized automatically but the rest of the content is not initialized. + +String heapString(const char* value); +String heapString(const char* value, size_t size); +String heapString(StringPtr value); +String heapString(const String& value); +String heapString(ArrayPtr value); +// Allocates a copy of the given value on the heap. + +// ======================================================================================= +// Magic str() function which transforms parameters to text and concatenates them into one big +// String. + +namespace _ { // private + +inline size_t sum(std::initializer_list nums) { + size_t result = 0; + for (auto num: nums) { + result += num; + } + return result; +} + +inline char* fill(char* ptr) { return ptr; } + +template +char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest); +// Make str() work with stringifiers that return StringTree by patching fill(). +// +// Defined in string-tree.h. + +template +char* fill(char* __restrict__ target, const First& first, Rest&&... rest) { + auto i = first.begin(); + auto end = first.end(); + while (i != end) { + *target++ = *i++; + } + return fill(target, kj::fwd(rest)...); +} + +template +String concat(Params&&... params) { + // Concatenate a bunch of containers into a single Array. The containers can be anything that + // is iterable and whose elements can be converted to `char`. + + String result = heapString(sum({params.size()...})); + fill(result.begin(), kj::fwd(params)...); + return result; +} + +inline String concat(String&& arr) { + return kj::mv(arr); +} + +struct Stringifier { + // This is a dummy type with only one instance: STR (below). To make an arbitrary type + // stringifiable, define `operator*(Stringifier, T)` to return an iterable container of `char`. + // The container type must have a `size()` method. Be sure to declare the operator in the same + // namespace as `T` **or** in the global scope. + // + // A more usual way to accomplish what we're doing here would be to require that you define + // a function like `toString(T)` and then rely on argument-dependent lookup. However, this has + // the problem that it pollutes other people's namespaces and even the global namespace. For + // example, some other project may already have functions called `toString` which do something + // different. Declaring `operator*` with `Stringifier` as the left operand cannot conflict with + // anything. + + inline ArrayPtr operator*(ArrayPtr s) const { return s; } + inline ArrayPtr operator*(ArrayPtr s) const { return s; } + inline ArrayPtr operator*(const Array& s) const { return s; } + inline ArrayPtr operator*(const Array& s) const { return s; } + template + inline ArrayPtr operator*(const CappedArray& s) const { return s; } + template + inline ArrayPtr operator*(const FixedArray& s) const { return s; } + inline ArrayPtr operator*(const char* s) const { return arrayPtr(s, strlen(s)); } + inline ArrayPtr operator*(const String& s) const { return s.asArray(); } + inline ArrayPtr operator*(const StringPtr& s) const { return s.asArray(); } + + inline Range operator*(const Range& r) const { return r; } + inline Repeat operator*(const Repeat& r) const { return r; } + + inline FixedArray operator*(char c) const { + FixedArray result; + result[0] = c; + return result; + } + + StringPtr operator*(decltype(nullptr)) const; + StringPtr operator*(bool b) const; + + CappedArray operator*(signed char i) const; + CappedArray operator*(unsigned char i) const; + CappedArray operator*(short i) const; + CappedArray operator*(unsigned short i) const; + CappedArray operator*(int i) const; + CappedArray operator*(unsigned int i) const; + CappedArray operator*(long i) const; + CappedArray operator*(unsigned long i) const; + CappedArray operator*(long long i) const; + CappedArray operator*(unsigned long long i) const; + CappedArray operator*(float f) const; + CappedArray operator*(double f) const; + CappedArray operator*(const void* s) const; + + template + String operator*(ArrayPtr arr) const; + template + String operator*(const Array& arr) const; + +#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP // supports expression SFINAE? + template ().toString())> + inline Result operator*(T&& value) const { return kj::fwd(value).toString(); } +#endif +}; +static KJ_CONSTEXPR(const) Stringifier STR = Stringifier(); + +} // namespace _ (private) + +template +auto toCharSequence(T&& value) -> decltype(_::STR * kj::fwd(value)) { + // Returns an iterable of chars that represent a textual representation of the value, suitable + // for debugging. + // + // Most users should use str() instead, but toCharSequence() may occasionally be useful to avoid + // heap allocation overhead that str() implies. + // + // To specialize this function for your type, see KJ_STRINGIFY. + + return _::STR * kj::fwd(value); +} + +CappedArray hex(unsigned char i); +CappedArray hex(unsigned short i); +CappedArray hex(unsigned int i); +CappedArray hex(unsigned long i); +CappedArray hex(unsigned long long i); + +template +String str(Params&&... params) { + // Magic function which builds a string from a bunch of arbitrary values. Example: + // str(1, " / ", 2, " = ", 0.5) + // returns: + // "1 / 2 = 0.5" + // To teach `str` how to stringify a type, see `Stringifier`. + + return _::concat(toCharSequence(kj::fwd(params))...); +} + +inline String str(String&& s) { return mv(s); } +// Overload to prevent redundant allocation. + +template +String strArray(T&& arr, const char* delim) { + size_t delimLen = strlen(delim); + KJ_STACK_ARRAY(decltype(_::STR * arr[0]), pieces, kj::size(arr), 8, 32); + size_t size = 0; + for (size_t i = 0; i < kj::size(arr); i++) { + if (i > 0) size += delimLen; + pieces[i] = _::STR * arr[i]; + size += pieces[i].size(); + } + + String result = heapString(size); + char* pos = result.begin(); + for (size_t i = 0; i < kj::size(arr); i++) { + if (i > 0) { + memcpy(pos, delim, delimLen); + pos += delimLen; + } + pos = _::fill(pos, pieces[i]); + } + return result; +} + +namespace _ { // private + +template +inline String Stringifier::operator*(ArrayPtr arr) const { + return strArray(arr, ", "); +} + +template +inline String Stringifier::operator*(const Array& arr) const { + return strArray(arr, ", "); +} + +} // namespace _ (private) + +#define KJ_STRINGIFY(...) operator*(::kj::_::Stringifier, __VA_ARGS__) +// Defines a stringifier for a custom type. Example: +// +// class Foo {...}; +// inline StringPtr KJ_STRINGIFY(const Foo& foo) { return foo.name(); } +// +// This allows Foo to be passed to str(). +// +// The function should be declared either in the same namespace as the target type or in the global +// namespace. It can return any type which is an iterable container of chars. + +// ======================================================================================= +// Inline implementation details. + +inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {} + +inline StringPtr::operator ArrayPtr() const { + return content.slice(0, content.size() - 1); +} + +inline ArrayPtr StringPtr::asArray() const { + return content.slice(0, content.size() - 1); +} + +inline bool StringPtr::operator==(const StringPtr& other) const { + return content.size() == other.content.size() && + memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0; +} + +inline bool StringPtr::operator<(const StringPtr& other) const { + bool shorter = content.size() < other.content.size(); + int cmp = memcmp(content.begin(), other.content.begin(), + shorter ? content.size() : other.content.size()); + return cmp < 0 || (cmp == 0 && shorter); +} + +inline StringPtr StringPtr::slice(size_t start) const { + return StringPtr(content.slice(start, content.size())); +} +inline ArrayPtr StringPtr::slice(size_t start, size_t end) const { + return content.slice(start, end); +} + +inline bool StringPtr::startsWith(const StringPtr& other) const { + return other.content.size() <= content.size() && + memcmp(content.begin(), other.content.begin(), other.size()) == 0; +} +inline bool StringPtr::endsWith(const StringPtr& other) const { + return other.content.size() <= content.size() && + memcmp(end() - other.size(), other.content.begin(), other.size()) == 0; +} + +inline Maybe StringPtr::findFirst(char c) const { + const char* pos = reinterpret_cast(memchr(content.begin(), c, size())); + if (pos == nullptr) { + return nullptr; + } else { + return pos - content.begin(); + } +} + +inline Maybe StringPtr::findLast(char c) const { + for (size_t i = size(); i > 0; --i) { + if (content[i-1] == c) { + return i-1; + } + } + return nullptr; +} + +inline String::operator ArrayPtr() { + return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); +} +inline String::operator ArrayPtr() const { + return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); +} + +inline ArrayPtr String::asArray() { + return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); +} +inline ArrayPtr String::asArray() const { + return content == nullptr ? ArrayPtr(nullptr) : content.slice(0, content.size() - 1); +} + +inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); } + +inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; } + +inline char String::operator[](size_t index) const { return content[index]; } +inline char& String::operator[](size_t index) { return content[index]; } + +inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); } +inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; } +inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); } +inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; } + +inline String::String(char* value, size_t size, const ArrayDisposer& disposer) + : content(value, size + 1, disposer) { + KJ_IREQUIRE(value[size] == '\0', "String must be NUL-terminated."); +} + +inline String::String(Array buffer): content(kj::mv(buffer)) { + KJ_IREQUIRE(content.size() > 0 && content.back() == '\0', "String must be NUL-terminated."); +} + +inline String heapString(const char* value) { + return heapString(value, strlen(value)); +} +inline String heapString(StringPtr value) { + return heapString(value.begin(), value.size()); +} +inline String heapString(const String& value) { + return heapString(value.begin(), value.size()); +} +inline String heapString(ArrayPtr value) { + return heapString(value.begin(), value.size()); +} + +} // namespace kj + +#endif // KJ_STRING_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/test.h --- a/osx/include/kj/test.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/test.h Mon May 22 10:01:37 2017 +0100 @@ -1,144 +1,167 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_TEST_H_ -#define KJ_TEST_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "debug.h" -#include "vector.h" - -namespace kj { - -class TestRunner; - -class TestCase { -public: - TestCase(const char* file, uint line, const char* description); - ~TestCase(); - - virtual void run() = 0; - -private: - const char* file; - uint line; - const char* description; - TestCase* next; - TestCase** prev; - bool matchedFilter; - - friend class TestRunner; -}; - -#define KJ_TEST(description) \ - /* Make sure the linker fails if tests are not in anonymous namespaces. */ \ - extern int KJ_CONCAT(YouMustWrapTestsInAnonymousNamespace, __COUNTER__) KJ_UNUSED; \ - class KJ_UNIQUE_NAME(TestCase): public ::kj::TestCase { \ - public: \ - KJ_UNIQUE_NAME(TestCase)(): ::kj::TestCase(__FILE__, __LINE__, description) {} \ - void run() override; \ - } KJ_UNIQUE_NAME(testCase); \ - void KJ_UNIQUE_NAME(TestCase)::run() - -#if _MSC_VER -#define KJ_INDIRECT_EXPAND(m, vargs) m vargs -#define KJ_FAIL_EXPECT(...) \ - KJ_INDIRECT_EXPAND(KJ_LOG, (ERROR , __VA_ARGS__)); -#define KJ_EXPECT(cond, ...) \ - if (cond); else KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("failed: expected " #cond , __VA_ARGS__)) -#else -#define KJ_FAIL_EXPECT(...) \ - KJ_LOG(ERROR, ##__VA_ARGS__); -#define KJ_EXPECT(cond, ...) \ - if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__) -#endif - -#define KJ_EXPECT_THROW(type, code) \ - do { \ - KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ - KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \ - "code threw wrong exception type: " #code, e->getType()); \ - } else { \ - KJ_FAIL_EXPECT("code did not throw: " #code); \ - } \ - } while (false) - -#define KJ_EXPECT_THROW_MESSAGE(message, code) \ - do { \ - KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ - KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \ - "exception description didn't contain expected substring", e->getDescription()); \ - } else { \ - KJ_FAIL_EXPECT("code did not throw: " #code); \ - } \ - } while (false) - -#define KJ_EXPECT_LOG(level, substring) \ - ::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring) -// Expects that a log message with the given level and substring text will be printed within -// the current scope. This message will not cause the test to fail, even if it is an error. - -// ======================================================================================= - -namespace _ { // private - -bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle); - -class LogExpectation: public ExceptionCallback { -public: - LogExpectation(LogSeverity severity, StringPtr substring); - ~LogExpectation(); - - void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, - String&& text) override; - -private: - LogSeverity severity; - StringPtr substring; - bool seen; - UnwindDetector unwindDetector; -}; - -class GlobFilter { - // Implements glob filters for the --filter flag. - // - // Exposed in header only for testing. - -public: - explicit GlobFilter(const char* pattern); - explicit GlobFilter(ArrayPtr pattern); - - bool matches(StringPtr name); - -private: - String pattern; - Vector states; - - void applyState(char c, int state); -}; - -} // namespace _ (private) -} // namespace kj - -#endif // KJ_TEST_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_TEST_H_ +#define KJ_TEST_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "debug.h" +#include "vector.h" +#include "function.h" + +namespace kj { + +class TestRunner; + +class TestCase { +public: + TestCase(const char* file, uint line, const char* description); + ~TestCase(); + + virtual void run() = 0; + +private: + const char* file; + uint line; + const char* description; + TestCase* next; + TestCase** prev; + bool matchedFilter; + + friend class TestRunner; +}; + +#define KJ_TEST(description) \ + /* Make sure the linker fails if tests are not in anonymous namespaces. */ \ + extern int KJ_CONCAT(YouMustWrapTestsInAnonymousNamespace, __COUNTER__) KJ_UNUSED; \ + class KJ_UNIQUE_NAME(TestCase): public ::kj::TestCase { \ + public: \ + KJ_UNIQUE_NAME(TestCase)(): ::kj::TestCase(__FILE__, __LINE__, description) {} \ + void run() override; \ + } KJ_UNIQUE_NAME(testCase); \ + void KJ_UNIQUE_NAME(TestCase)::run() + +#if _MSC_VER +#define KJ_INDIRECT_EXPAND(m, vargs) m vargs +#define KJ_FAIL_EXPECT(...) \ + KJ_INDIRECT_EXPAND(KJ_LOG, (ERROR , __VA_ARGS__)); +#define KJ_EXPECT(cond, ...) \ + if (cond); else KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("failed: expected " #cond , __VA_ARGS__)) +#else +#define KJ_FAIL_EXPECT(...) \ + KJ_LOG(ERROR, ##__VA_ARGS__); +#define KJ_EXPECT(cond, ...) \ + if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__) +#endif + +#define KJ_EXPECT_THROW_RECOVERABLE(type, code) \ + do { \ + KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ + KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \ + "code threw wrong exception type: " #code, e->getType()); \ + } else { \ + KJ_FAIL_EXPECT("code did not throw: " #code); \ + } \ + } while (false) + +#define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code) \ + do { \ + KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \ + KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \ + "exception description didn't contain expected substring", e->getDescription()); \ + } else { \ + KJ_FAIL_EXPECT("code did not throw: " #code); \ + } \ + } while (false) + +#if KJ_NO_EXCEPTIONS +#define KJ_EXPECT_THROW(type, code) \ + do { \ + KJ_EXPECT(::kj::_::expectFatalThrow(type, nullptr, [&]() { code; })); \ + } while (false) +#define KJ_EXPECT_THROW_MESSAGE(message, code) \ + do { \ + KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, kj::StringPtr(message), [&]() { code; })); \ + } while (false) +#else +#define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE +#define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE +#endif + +#define KJ_EXPECT_LOG(level, substring) \ + ::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring) +// Expects that a log message with the given level and substring text will be printed within +// the current scope. This message will not cause the test to fail, even if it is an error. + +// ======================================================================================= + +namespace _ { // private + +bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle); + +#if KJ_NO_EXCEPTIONS +bool expectFatalThrow(Maybe type, Maybe message, + Function code); +// Expects that the given code will throw a fatal exception matching the given type and/or message. +// Since exceptions are disabled, the test will fork() and run in a subprocess. On Windows, where +// fork() is not available, this always returns true. +#endif + +class LogExpectation: public ExceptionCallback { +public: + LogExpectation(LogSeverity severity, StringPtr substring); + ~LogExpectation(); + + void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) override; + +private: + LogSeverity severity; + StringPtr substring; + bool seen; + UnwindDetector unwindDetector; +}; + +class GlobFilter { + // Implements glob filters for the --filter flag. + // + // Exposed in header only for testing. + +public: + explicit GlobFilter(const char* pattern); + explicit GlobFilter(ArrayPtr pattern); + + bool matches(StringPtr name); + +private: + String pattern; + Vector states; + + void applyState(char c, int state); +}; + +} // namespace _ (private) +} // namespace kj + +#endif // KJ_TEST_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/thread.h --- a/osx/include/kj/thread.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/thread.h Mon May 22 10:01:37 2017 +0100 @@ -1,85 +1,82 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_THREAD_H_ -#define KJ_THREAD_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" -#include "function.h" -#include "exception.h" - -namespace kj { - -class Thread { - // A thread! Pass a lambda to the constructor, and it runs in the thread. The destructor joins - // the thread. If the function throws an exception, it is rethrown from the thread's destructor - // (if not unwinding from another exception). - -public: - explicit Thread(Function func); - KJ_DISALLOW_COPY(Thread); - - ~Thread() noexcept(false); - -#if !_WIN32 - void sendSignal(int signo); - // Send a Unix signal to the given thread, using pthread_kill or an equivalent. -#endif - - void detach(); - // Don't join the thread in ~Thread(). - // - // TODO(soon): Currently broken: the thread uses the Thread objects during its execution; instead - // the Thread object and the thread itself will need to share a refcounted object. - -private: - struct ThreadState { - Function func; - kj::Maybe exception; - - unsigned int refcount; - // Owned by the parent thread and the child thread. - - void unref(); - }; - ThreadState* state; - -#if _WIN32 - void* threadHandle; -#else - unsigned long long threadId; // actually pthread_t -#endif - bool detached = false; - -#if _WIN32 - static unsigned long __stdcall runThread(void* ptr); -#else - static void* runThread(void* ptr); -#endif -}; - -} // namespace kj - -#endif // KJ_THREAD_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_THREAD_H_ +#define KJ_THREAD_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" +#include "function.h" +#include "exception.h" + +namespace kj { + +class Thread { + // A thread! Pass a lambda to the constructor, and it runs in the thread. The destructor joins + // the thread. If the function throws an exception, it is rethrown from the thread's destructor + // (if not unwinding from another exception). + +public: + explicit Thread(Function func); + KJ_DISALLOW_COPY(Thread); + + ~Thread() noexcept(false); + +#if !_WIN32 + void sendSignal(int signo); + // Send a Unix signal to the given thread, using pthread_kill or an equivalent. +#endif + + void detach(); + // Don't join the thread in ~Thread(). + +private: + struct ThreadState { + Function func; + kj::Maybe exception; + + unsigned int refcount; + // Owned by the parent thread and the child thread. + + void unref(); + }; + ThreadState* state; + +#if _WIN32 + void* threadHandle; +#else + unsigned long long threadId; // actually pthread_t +#endif + bool detached = false; + +#if _WIN32 + static unsigned long __stdcall runThread(void* ptr); +#else + static void* runThread(void* ptr); +#endif +}; + +} // namespace kj + +#endif // KJ_THREAD_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/threadlocal.h --- a/osx/include/kj/threadlocal.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/threadlocal.h Mon May 22 10:01:37 2017 +0100 @@ -1,136 +1,136 @@ -// Copyright (c) 2014, Jason Choy -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_THREADLOCAL_H_ -#define KJ_THREADLOCAL_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif -// This file declares a macro `KJ_THREADLOCAL_PTR` for declaring thread-local pointer-typed -// variables. Use like: -// KJ_THREADLOCAL_PTR(MyType) foo = nullptr; -// This is equivalent to: -// thread_local MyType* foo = nullptr; -// This can only be used at the global scope. -// -// AVOID USING THIS. Use of thread-locals is discouraged because they often have many of the same -// properties as singletons: http://www.object-oriented-security.org/lets-argue/singletons -// -// Also, thread-locals tend to be hostile to event-driven code, which can be particularly -// surprising when using fibers (all fibers in the same thread will share the same threadlocals, -// even though they do not share a stack). -// -// That said, thread-locals are sometimes needed for runtime logistics in the KJ framework. For -// example, the current exception callback and current EventLoop are stored as thread-local -// pointers. Since KJ only ever needs to store pointers, not values, we avoid the question of -// whether these values' destructors need to be run, and we avoid the need for heap allocation. - -#include "common.h" - -#if !defined(KJ_USE_PTHREAD_THREADLOCAL) && defined(__APPLE__) -#include "TargetConditionals.h" -#if TARGET_OS_IPHONE -// iOS apparently does not support __thread (nor C++11 thread_local). -#define KJ_USE_PTHREAD_TLS 1 -#endif -#endif - -#if KJ_USE_PTHREAD_TLS -#include -#endif - -namespace kj { - -#if KJ_USE_PTHREAD_TLS -// If __thread is unavailable, we'll fall back to pthreads. - -#define KJ_THREADLOCAL_PTR(type) \ - namespace { struct KJ_UNIQUE_NAME(_kj_TlpTag); } \ - static ::kj::_::ThreadLocalPtr< type, KJ_UNIQUE_NAME(_kj_TlpTag)> -// Hack: In order to ensure each thread-local results in a unique template instance, we declare -// a one-off dummy type to use as the second type parameter. - -namespace _ { // private - -template -class ThreadLocalPtr { - // Hacky type to emulate __thread T*. We need a separate instance of the ThreadLocalPtr template - // for every thread-local variable, because we don't want to require a global constructor, and in - // order to initialize the TLS on first use we need to use a local static variable (in getKey()). - // Each template instance will get a separate such local static variable, fulfilling our need. - -public: - ThreadLocalPtr() = default; - constexpr ThreadLocalPtr(decltype(nullptr)) {} - // Allow initialization to nullptr without a global constructor. - - inline ThreadLocalPtr& operator=(T* val) { - pthread_setspecific(getKey(), val); - return *this; - } - - inline operator T*() const { - return get(); - } - - inline T& operator*() const { - return *get(); - } - - inline T* operator->() const { - return get(); - } - -private: - inline T* get() const { - return reinterpret_cast(pthread_getspecific(getKey())); - } - - inline static pthread_key_t getKey() { - static pthread_key_t key = createKey(); - return key; - } - - static pthread_key_t createKey() { - pthread_key_t key; - pthread_key_create(&key, 0); - return key; - } -}; - -} // namespace _ (private) - -#elif __GNUC__ - -#define KJ_THREADLOCAL_PTR(type) static __thread type* -// GCC's __thread is lighter-weight than thread_local and is good enough for our purposes. - -#else - -#define KJ_THREADLOCAL_PTR(type) static thread_local type* - -#endif // KJ_USE_PTHREAD_TLS - -} // namespace kj - -#endif // KJ_THREADLOCAL_H_ +// Copyright (c) 2014, Jason Choy +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_THREADLOCAL_H_ +#define KJ_THREADLOCAL_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif +// This file declares a macro `KJ_THREADLOCAL_PTR` for declaring thread-local pointer-typed +// variables. Use like: +// KJ_THREADLOCAL_PTR(MyType) foo = nullptr; +// This is equivalent to: +// thread_local MyType* foo = nullptr; +// This can only be used at the global scope. +// +// AVOID USING THIS. Use of thread-locals is discouraged because they often have many of the same +// properties as singletons: http://www.object-oriented-security.org/lets-argue/singletons +// +// Also, thread-locals tend to be hostile to event-driven code, which can be particularly +// surprising when using fibers (all fibers in the same thread will share the same threadlocals, +// even though they do not share a stack). +// +// That said, thread-locals are sometimes needed for runtime logistics in the KJ framework. For +// example, the current exception callback and current EventLoop are stored as thread-local +// pointers. Since KJ only ever needs to store pointers, not values, we avoid the question of +// whether these values' destructors need to be run, and we avoid the need for heap allocation. + +#include "common.h" + +#if !defined(KJ_USE_PTHREAD_THREADLOCAL) && defined(__APPLE__) +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE +// iOS apparently does not support __thread (nor C++11 thread_local). +#define KJ_USE_PTHREAD_TLS 1 +#endif +#endif + +#if KJ_USE_PTHREAD_TLS +#include +#endif + +namespace kj { + +#if KJ_USE_PTHREAD_TLS +// If __thread is unavailable, we'll fall back to pthreads. + +#define KJ_THREADLOCAL_PTR(type) \ + namespace { struct KJ_UNIQUE_NAME(_kj_TlpTag); } \ + static ::kj::_::ThreadLocalPtr< type, KJ_UNIQUE_NAME(_kj_TlpTag)> +// Hack: In order to ensure each thread-local results in a unique template instance, we declare +// a one-off dummy type to use as the second type parameter. + +namespace _ { // private + +template +class ThreadLocalPtr { + // Hacky type to emulate __thread T*. We need a separate instance of the ThreadLocalPtr template + // for every thread-local variable, because we don't want to require a global constructor, and in + // order to initialize the TLS on first use we need to use a local static variable (in getKey()). + // Each template instance will get a separate such local static variable, fulfilling our need. + +public: + ThreadLocalPtr() = default; + constexpr ThreadLocalPtr(decltype(nullptr)) {} + // Allow initialization to nullptr without a global constructor. + + inline ThreadLocalPtr& operator=(T* val) { + pthread_setspecific(getKey(), val); + return *this; + } + + inline operator T*() const { + return get(); + } + + inline T& operator*() const { + return *get(); + } + + inline T* operator->() const { + return get(); + } + +private: + inline T* get() const { + return reinterpret_cast(pthread_getspecific(getKey())); + } + + inline static pthread_key_t getKey() { + static pthread_key_t key = createKey(); + return key; + } + + static pthread_key_t createKey() { + pthread_key_t key; + pthread_key_create(&key, 0); + return key; + } +}; + +} // namespace _ (private) + +#elif __GNUC__ + +#define KJ_THREADLOCAL_PTR(type) static __thread type* +// GCC's __thread is lighter-weight than thread_local and is good enough for our purposes. + +#else + +#define KJ_THREADLOCAL_PTR(type) static thread_local type* + +#endif // KJ_USE_PTHREAD_TLS + +} // namespace kj + +#endif // KJ_THREADLOCAL_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/time.h --- a/osx/include/kj/time.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/time.h Mon May 22 10:01:37 2017 +0100 @@ -1,119 +1,174 @@ -// Copyright (c) 2014 Google Inc. (contributed by Remy Blank ) -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_TIME_H_ -#define KJ_TIME_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "async.h" -#include "units.h" -#include - -namespace kj { -namespace _ { // private - -class NanosecondLabel; -class TimeLabel; -class DateLabel; - -} // namespace _ (private) - -using Duration = Quantity; -// A time value, in microseconds. - -constexpr Duration NANOSECONDS = unit(); -constexpr Duration MICROSECONDS = 1000 * NANOSECONDS; -constexpr Duration MILLISECONDS = 1000 * MICROSECONDS; -constexpr Duration SECONDS = 1000 * MILLISECONDS; -constexpr Duration MINUTES = 60 * SECONDS; -constexpr Duration HOURS = 60 * MINUTES; -constexpr Duration DAYS = 24 * HOURS; - -using TimePoint = Absolute; -// An absolute time measured by some particular instance of `Timer`. `Time`s from two different -// `Timer`s may be measured from different origins and so are not necessarily compatible. - -using Date = Absolute; -// A point in real-world time, measured relative to the Unix epoch (Jan 1, 1970 00:00:00 UTC). - -constexpr Date UNIX_EPOCH = origin(); -// The `Date` representing Jan 1, 1970 00:00:00 UTC. - -class Timer { - // Interface to time and timer functionality. - // - // Each `Timer` may have a different origin, and some `Timer`s may in fact tick at a different - // rate than real time (e.g. a `Timer` could represent CPU time consumed by a thread). However, - // all `Timer`s are monotonic: time will never appear to move backwards, even if the calendar - // date as tracked by the system is manually modified. - -public: - virtual TimePoint now() = 0; - // Returns the current value of a clock that moves steadily forward, independent of any - // changes in the wall clock. The value is updated every time the event loop waits, - // and is constant in-between waits. - - virtual Promise atTime(TimePoint time) = 0; - // Returns a promise that returns as soon as now() >= time. - - virtual Promise afterDelay(Duration delay) = 0; - // Equivalent to atTime(now() + delay). - - template - Promise timeoutAt(TimePoint time, Promise&& promise) KJ_WARN_UNUSED_RESULT; - // Return a promise equivalent to `promise` but which throws an exception (and cancels the - // original promise) if it hasn't completed by `time`. The thrown exception is of type - // "OVERLOADED". - - template - Promise timeoutAfter(Duration delay, Promise&& promise) KJ_WARN_UNUSED_RESULT; - // Return a promise equivalent to `promise` but which throws an exception (and cancels the - // original promise) if it hasn't completed after `delay` from now. The thrown exception is of - // type "OVERLOADED". - -private: - static kj::Exception makeTimeoutException(); -}; - -// ======================================================================================= -// inline implementation details - -template -Promise Timer::timeoutAt(TimePoint time, Promise&& promise) { - return promise.exclusiveJoin(atTime(time).then([]() -> kj::Promise { - return makeTimeoutException(); - })); -} - -template -Promise Timer::timeoutAfter(Duration delay, Promise&& promise) { - return promise.exclusiveJoin(afterDelay(delay).then([]() -> kj::Promise { - return makeTimeoutException(); - })); -} - -} // namespace kj - -#endif // KJ_TIME_H_ +// Copyright (c) 2014 Google Inc. (contributed by Remy Blank ) +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_TIME_H_ +#define KJ_TIME_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async.h" +#include "units.h" +#include + +namespace kj { +namespace _ { // private + +class NanosecondLabel; +class TimeLabel; +class DateLabel; + +} // namespace _ (private) + +using Duration = Quantity; +// A time value, in nanoseconds. + +constexpr Duration NANOSECONDS = unit(); +constexpr Duration MICROSECONDS = 1000 * NANOSECONDS; +constexpr Duration MILLISECONDS = 1000 * MICROSECONDS; +constexpr Duration SECONDS = 1000 * MILLISECONDS; +constexpr Duration MINUTES = 60 * SECONDS; +constexpr Duration HOURS = 60 * MINUTES; +constexpr Duration DAYS = 24 * HOURS; + +using TimePoint = Absolute; +// An absolute time measured by some particular instance of `Timer`. `Time`s from two different +// `Timer`s may be measured from different origins and so are not necessarily compatible. + +using Date = Absolute; +// A point in real-world time, measured relative to the Unix epoch (Jan 1, 1970 00:00:00 UTC). + +constexpr Date UNIX_EPOCH = origin(); +// The `Date` representing Jan 1, 1970 00:00:00 UTC. + +class Clock { + // Interface to read the current date and time. +public: + virtual Date now() = 0; +}; + +Clock& nullClock(); +// A clock which always returns UNIX_EPOCH as the current time. Useful when you don't care about +// time. + +class Timer { + // Interface to time and timer functionality. + // + // Each `Timer` may have a different origin, and some `Timer`s may in fact tick at a different + // rate than real time (e.g. a `Timer` could represent CPU time consumed by a thread). However, + // all `Timer`s are monotonic: time will never appear to move backwards, even if the calendar + // date as tracked by the system is manually modified. + +public: + virtual TimePoint now() = 0; + // Returns the current value of a clock that moves steadily forward, independent of any + // changes in the wall clock. The value is updated every time the event loop waits, + // and is constant in-between waits. + + virtual Promise atTime(TimePoint time) = 0; + // Returns a promise that returns as soon as now() >= time. + + virtual Promise afterDelay(Duration delay) = 0; + // Equivalent to atTime(now() + delay). + + template + Promise timeoutAt(TimePoint time, Promise&& promise) KJ_WARN_UNUSED_RESULT; + // Return a promise equivalent to `promise` but which throws an exception (and cancels the + // original promise) if it hasn't completed by `time`. The thrown exception is of type + // "OVERLOADED". + + template + Promise timeoutAfter(Duration delay, Promise&& promise) KJ_WARN_UNUSED_RESULT; + // Return a promise equivalent to `promise` but which throws an exception (and cancels the + // original promise) if it hasn't completed after `delay` from now. The thrown exception is of + // type "OVERLOADED". + +private: + static kj::Exception makeTimeoutException(); +}; + +class TimerImpl final: public Timer { + // Implementation of Timer that expects an external caller -- usually, the EventPort + // implementation -- to tell it when time has advanced. + +public: + TimerImpl(TimePoint startTime); + ~TimerImpl() noexcept(false); + + Maybe nextEvent(); + // Returns the time at which the next scheduled timer event will occur, or null if no timer + // events are scheduled. + + Maybe timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max); + // Convenience method which computes a timeout value to pass to an event-waiting system call to + // cause it to time out when the next timer event occurs. + // + // `start` is the time at which the timeout starts counting. This is typically not the same as + // now() since some time may have passed since the last time advanceTo() was called. + // + // `unit` is the time unit in which the timeout is measured. This is often MILLISECONDS. Note + // that this method will fractional values *up*, to guarantee that the returned timeout waits + // until just *after* the time the event is scheduled. + // + // The timeout will be clamped to `max`. Use this to avoid an overflow if e.g. the OS wants a + // 32-bit value or a signed value. + // + // Returns nullptr if there are no future events. + + void advanceTo(TimePoint newTime); + // Set the time to `time` and fire any at() events that have been passed. + + // implements Timer ---------------------------------------------------------- + TimePoint now() override; + Promise atTime(TimePoint time) override; + Promise afterDelay(Duration delay) override; + +private: + struct Impl; + class TimerPromiseAdapter; + TimePoint time; + Own impl; +}; + +// ======================================================================================= +// inline implementation details + +template +Promise Timer::timeoutAt(TimePoint time, Promise&& promise) { + return promise.exclusiveJoin(atTime(time).then([]() -> kj::Promise { + return makeTimeoutException(); + })); +} + +template +Promise Timer::timeoutAfter(Duration delay, Promise&& promise) { + return promise.exclusiveJoin(afterDelay(delay).then([]() -> kj::Promise { + return makeTimeoutException(); + })); +} + +inline TimePoint TimerImpl::now() { return time; } + +} // namespace kj + +#endif // KJ_TIME_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/tuple.h --- a/osx/include/kj/tuple.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/tuple.h Mon May 22 10:01:37 2017 +0100 @@ -1,364 +1,364 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file defines a notion of tuples that is simpler that `std::tuple`. It works as follows: -// - `kj::Tuple is the type of a tuple of an A, a B, and a C. -// - `kj::tuple(a, b, c)` returns a tuple containing a, b, and c. If any of these are themselves -// tuples, they are flattened, so `tuple(a, tuple(b, c), d)` is equivalent to `tuple(a, b, c, d)`. -// - `kj::get(myTuple)` returns the element of `myTuple` at index n. -// - `kj::apply(func, ...)` calls func on the following arguments after first expanding any tuples -// in the argument list. So `kj::apply(foo, a, tuple(b, c), d)` would call `foo(a, b, c, d)`. -// -// Note that: -// - The type `Tuple` is a synonym for T. This is why `get` and `apply` are not members of the -// type. -// - It is illegal for an element of `Tuple` to itself be a tuple, as tuples are meant to be -// flattened. -// - It is illegal for an element of `Tuple` to be a reference, due to problems this would cause -// with type inference and `tuple()`. - -#ifndef KJ_TUPLE_H_ -#define KJ_TUPLE_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" - -namespace kj { -namespace _ { // private - -template -struct TypeByIndex_; -template -struct TypeByIndex_<0, First, Rest...> { - typedef First Type; -}; -template -struct TypeByIndex_ - : public TypeByIndex_ {}; -template -struct TypeByIndex_ { - static_assert(index != index, "Index out-of-range."); -}; -template -using TypeByIndex = typename TypeByIndex_::Type; -// Chose a particular type out of a list of types, by index. - -template -struct Indexes {}; -// Dummy helper type that just encapsulates a sequential list of indexes, so that we can match -// templates against them and unpack them with '...'. - -template -struct MakeIndexes_: public MakeIndexes_ {}; -template -struct MakeIndexes_<0, prefix...> { - typedef Indexes Type; -}; -template -using MakeIndexes = typename MakeIndexes_::Type; -// Equivalent to Indexes<0, 1, 2, ..., end>. - -template -class Tuple; -template -inline TypeByIndex& getImpl(Tuple& tuple); -template -inline TypeByIndex&& getImpl(Tuple&& tuple); -template -inline const TypeByIndex& getImpl(const Tuple& tuple); - -template -struct TupleElement { - // Encapsulates one element of a tuple. The actual tuple implementation multiply-inherits - // from a TupleElement for each element, which is more efficient than a recursive definition. - - T value; - TupleElement() = default; - constexpr inline TupleElement(const T& value): value(value) {} - constexpr inline TupleElement(T&& value): value(kj::mv(value)) {} -}; - -template -struct TupleElement { - // If tuples contained references, one of the following would have to be true: - // - `auto x = tuple(y, z)` would cause x to be a tuple of references to y and z, which is - // probably not what you expected. - // - `Tuple x = tuple(a, b)` would not work, because `tuple()` returned - // Tuple. - static_assert(sizeof(T*) == 0, "Sorry, tuples cannot contain references."); -}; - -template -struct TupleElement> { - static_assert(sizeof(Tuple*) == 0, - "Tuples cannot contain other tuples -- they should be flattened."); -}; - -template -struct TupleImpl; - -template -struct TupleImpl, Types...> - : public TupleElement... { - // Implementation of Tuple. The only reason we need this rather than rolling this into class - // Tuple (below) is so that we can get "indexes" as an unpackable list. - - static_assert(sizeof...(indexes) == sizeof...(Types), "Incorrect use of TupleImpl."); - - template - inline TupleImpl(Params&&... params) - : TupleElement(kj::fwd(params))... { - // Work around Clang 3.2 bug 16303 where this is not detected. (Unfortunately, Clang sometimes - // segfaults instead.) - static_assert(sizeof...(params) == sizeof...(indexes), - "Wrong number of parameters to Tuple constructor."); - } - - template - constexpr inline TupleImpl(Tuple&& other) - : TupleElement(kj::mv(getImpl(other)))... {} - template - constexpr inline TupleImpl(Tuple& other) - : TupleElement(getImpl(other))... {} - template - constexpr inline TupleImpl(const Tuple& other) - : TupleElement(getImpl(other))... {} -}; - -struct MakeTupleFunc; - -template -class Tuple { - // The actual Tuple class (used for tuples of size other than 1). - -public: - template - constexpr inline Tuple(Tuple&& other): impl(kj::mv(other)) {} - template - constexpr inline Tuple(Tuple& other): impl(other) {} - template - constexpr inline Tuple(const Tuple& other): impl(other) {} - -private: - template - constexpr Tuple(Params&&... params): impl(kj::fwd(params)...) {} - - TupleImpl, T...> impl; - - template - friend inline TypeByIndex& getImpl(Tuple& tuple); - template - friend inline TypeByIndex&& getImpl(Tuple&& tuple); - template - friend inline const TypeByIndex& getImpl(const Tuple& tuple); - friend struct MakeTupleFunc; -}; - -template <> -class Tuple<> { - // Simplified zero-member version of Tuple. In particular this is important to make sure that - // Tuple<>() is constexpr. -}; - -template -class Tuple; -// Single-element tuple should never be used. The public API should ensure this. - -template -inline TypeByIndex& getImpl(Tuple& tuple) { - // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. - static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); - return implicitCast>&>(tuple.impl).value; -} -template -inline TypeByIndex&& getImpl(Tuple&& tuple) { - // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. - static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); - return kj::mv(implicitCast>&>(tuple.impl).value); -} -template -inline const TypeByIndex& getImpl(const Tuple& tuple) { - // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. - static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); - return implicitCast>&>(tuple.impl).value; -} -template -inline T&& getImpl(T&& value) { - // Get member of a Tuple by index, e.g. `getImpl<2>(myTuple)`. - - // Non-tuples are equivalent to one-element tuples. - static_assert(index == 0, "Tuple element index out-of-bounds."); - return kj::fwd(value); -} - - -template -struct ExpandAndApplyResult_; -// Template which computes the return type of applying Func to T... after flattening tuples. -// SoFar starts as Tuple<> and accumulates the flattened parameter types -- so after this template -// is recursively expanded, T... is empty and SoFar is a Tuple containing all the parameters. - -template -struct ExpandAndApplyResult_, First, Rest...> - : public ExpandAndApplyResult_, Rest...> {}; -template -struct ExpandAndApplyResult_, Tuple, Rest...> - : public ExpandAndApplyResult_, FirstTypes&&..., Rest...> {}; -template -struct ExpandAndApplyResult_, Tuple&, Rest...> - : public ExpandAndApplyResult_, FirstTypes&..., Rest...> {}; -template -struct ExpandAndApplyResult_, const Tuple&, Rest...> - : public ExpandAndApplyResult_, const FirstTypes&..., Rest...> {}; -template -struct ExpandAndApplyResult_> { - typedef decltype(instance()(instance()...)) Type; -}; -template -using ExpandAndApplyResult = typename ExpandAndApplyResult_, T...>::Type; -// Computes the expected return type of `expandAndApply()`. - -template -inline auto expandAndApply(Func&& func) -> ExpandAndApplyResult { - return func(); -} - -template -struct ExpandAndApplyFunc { - Func&& func; - First&& first; - ExpandAndApplyFunc(Func&& func, First&& first) - : func(kj::fwd(func)), first(kj::fwd(first)) {} - template - auto operator()(T&&... params) - -> decltype(this->func(kj::fwd(first), kj::fwd(params)...)) { - return this->func(kj::fwd(first), kj::fwd(params)...); - } -}; - -template -inline auto expandAndApply(Func&& func, First&& first, Rest&&... rest) - -> ExpandAndApplyResult { - - return expandAndApply( - ExpandAndApplyFunc(kj::fwd(func), kj::fwd(first)), - kj::fwd(rest)...); -} - -template -inline auto expandAndApply(Func&& func, Tuple&& first, Rest&&... rest) - -> ExpandAndApplyResult { - return expandAndApplyWithIndexes(MakeIndexes(), - kj::fwd(func), kj::mv(first), kj::fwd(rest)...); -} - -template -inline auto expandAndApply(Func&& func, Tuple& first, Rest&&... rest) - -> ExpandAndApplyResult { - return expandAndApplyWithIndexes(MakeIndexes(), - kj::fwd(func), first, kj::fwd(rest)...); -} - -template -inline auto expandAndApply(Func&& func, const Tuple& first, Rest&&... rest) - -> ExpandAndApplyResult { - return expandAndApplyWithIndexes(MakeIndexes(), - kj::fwd(func), first, kj::fwd(rest)...); -} - -template -inline auto expandAndApplyWithIndexes( - Indexes, Func&& func, Tuple&& first, Rest&&... rest) - -> ExpandAndApplyResult { - return expandAndApply(kj::fwd(func), kj::mv(getImpl(first))..., - kj::fwd(rest)...); -} - -template -inline auto expandAndApplyWithIndexes( - Indexes, Func&& func, const Tuple& first, Rest&&... rest) - -> ExpandAndApplyResult { - return expandAndApply(kj::fwd(func), getImpl(first)..., - kj::fwd(rest)...); -} - -struct MakeTupleFunc { - template - Tuple...> operator()(Params&&... params) { - return Tuple...>(kj::fwd(params)...); - } - template - Decay operator()(Param&& param) { - return kj::fwd(param); - } -}; - -} // namespace _ (private) - -template struct Tuple_ { typedef _::Tuple Type; }; -template struct Tuple_ { typedef T Type; }; - -template using Tuple = typename Tuple_::Type; -// Tuple type. `Tuple` (i.e. a single-element tuple) is a synonym for `T`. Tuples of size -// other than 1 expand to an internal type. Either way, you can construct a Tuple using -// `kj::tuple(...)`, get an element by index `i` using `kj::get(myTuple)`, and expand the tuple -// as arguments to a function using `kj::apply(func, myTuple)`. -// -// Tuples are always flat -- that is, no element of a Tuple is ever itself a Tuple. If you -// construct a tuple from other tuples, the elements are flattened and concatenated. - -template -inline auto tuple(Params&&... params) - -> decltype(_::expandAndApply(_::MakeTupleFunc(), kj::fwd(params)...)) { - // Construct a new tuple from the given values. Any tuples in the argument list will be - // flattened into the result. - return _::expandAndApply(_::MakeTupleFunc(), kj::fwd(params)...); -} - -template -inline auto get(Tuple&& tuple) -> decltype(_::getImpl(kj::fwd(tuple))) { - // Unpack and return the tuple element at the given index. The index is specified as a template - // parameter, e.g. `kj::get<3>(myTuple)`. - return _::getImpl(kj::fwd(tuple)); -} - -template -inline auto apply(Func&& func, Params&&... params) - -> decltype(_::expandAndApply(kj::fwd(func), kj::fwd(params)...)) { - // Apply a function to some arguments, expanding tuples into separate arguments. - return _::expandAndApply(kj::fwd(func), kj::fwd(params)...); -} - -template struct TupleSize_ { static constexpr size_t size = 1; }; -template struct TupleSize_<_::Tuple> { - static constexpr size_t size = sizeof...(T); -}; - -template -constexpr size_t tupleSize() { return TupleSize_::size; } -// Returns size of the tuple T. - -} // namespace kj - -#endif // KJ_TUPLE_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file defines a notion of tuples that is simpler that `std::tuple`. It works as follows: +// - `kj::Tuple is the type of a tuple of an A, a B, and a C. +// - `kj::tuple(a, b, c)` returns a tuple containing a, b, and c. If any of these are themselves +// tuples, they are flattened, so `tuple(a, tuple(b, c), d)` is equivalent to `tuple(a, b, c, d)`. +// - `kj::get(myTuple)` returns the element of `myTuple` at index n. +// - `kj::apply(func, ...)` calls func on the following arguments after first expanding any tuples +// in the argument list. So `kj::apply(foo, a, tuple(b, c), d)` would call `foo(a, b, c, d)`. +// +// Note that: +// - The type `Tuple` is a synonym for T. This is why `get` and `apply` are not members of the +// type. +// - It is illegal for an element of `Tuple` to itself be a tuple, as tuples are meant to be +// flattened. +// - It is illegal for an element of `Tuple` to be a reference, due to problems this would cause +// with type inference and `tuple()`. + +#ifndef KJ_TUPLE_H_ +#define KJ_TUPLE_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" + +namespace kj { +namespace _ { // private + +template +struct TypeByIndex_; +template +struct TypeByIndex_<0, First, Rest...> { + typedef First Type; +}; +template +struct TypeByIndex_ + : public TypeByIndex_ {}; +template +struct TypeByIndex_ { + static_assert(index != index, "Index out-of-range."); +}; +template +using TypeByIndex = typename TypeByIndex_::Type; +// Chose a particular type out of a list of types, by index. + +template +struct Indexes {}; +// Dummy helper type that just encapsulates a sequential list of indexes, so that we can match +// templates against them and unpack them with '...'. + +template +struct MakeIndexes_: public MakeIndexes_ {}; +template +struct MakeIndexes_<0, prefix...> { + typedef Indexes Type; +}; +template +using MakeIndexes = typename MakeIndexes_::Type; +// Equivalent to Indexes<0, 1, 2, ..., end>. + +template +class Tuple; +template +inline TypeByIndex& getImpl(Tuple& tuple); +template +inline TypeByIndex&& getImpl(Tuple&& tuple); +template +inline const TypeByIndex& getImpl(const Tuple& tuple); + +template +struct TupleElement { + // Encapsulates one element of a tuple. The actual tuple implementation multiply-inherits + // from a TupleElement for each element, which is more efficient than a recursive definition. + + T value; + TupleElement() = default; + constexpr inline TupleElement(const T& value): value(value) {} + constexpr inline TupleElement(T&& value): value(kj::mv(value)) {} +}; + +template +struct TupleElement { + // If tuples contained references, one of the following would have to be true: + // - `auto x = tuple(y, z)` would cause x to be a tuple of references to y and z, which is + // probably not what you expected. + // - `Tuple x = tuple(a, b)` would not work, because `tuple()` returned + // Tuple. + static_assert(sizeof(T*) == 0, "Sorry, tuples cannot contain references."); +}; + +template +struct TupleElement> { + static_assert(sizeof(Tuple*) == 0, + "Tuples cannot contain other tuples -- they should be flattened."); +}; + +template +struct TupleImpl; + +template +struct TupleImpl, Types...> + : public TupleElement... { + // Implementation of Tuple. The only reason we need this rather than rolling this into class + // Tuple (below) is so that we can get "indexes" as an unpackable list. + + static_assert(sizeof...(indexes) == sizeof...(Types), "Incorrect use of TupleImpl."); + + template + inline TupleImpl(Params&&... params) + : TupleElement(kj::fwd(params))... { + // Work around Clang 3.2 bug 16303 where this is not detected. (Unfortunately, Clang sometimes + // segfaults instead.) + static_assert(sizeof...(params) == sizeof...(indexes), + "Wrong number of parameters to Tuple constructor."); + } + + template + constexpr inline TupleImpl(Tuple&& other) + : TupleElement(kj::mv(getImpl(other)))... {} + template + constexpr inline TupleImpl(Tuple& other) + : TupleElement(getImpl(other))... {} + template + constexpr inline TupleImpl(const Tuple& other) + : TupleElement(getImpl(other))... {} +}; + +struct MakeTupleFunc; + +template +class Tuple { + // The actual Tuple class (used for tuples of size other than 1). + +public: + template + constexpr inline Tuple(Tuple&& other): impl(kj::mv(other)) {} + template + constexpr inline Tuple(Tuple& other): impl(other) {} + template + constexpr inline Tuple(const Tuple& other): impl(other) {} + +private: + template + constexpr Tuple(Params&&... params): impl(kj::fwd(params)...) {} + + TupleImpl, T...> impl; + + template + friend inline TypeByIndex& getImpl(Tuple& tuple); + template + friend inline TypeByIndex&& getImpl(Tuple&& tuple); + template + friend inline const TypeByIndex& getImpl(const Tuple& tuple); + friend struct MakeTupleFunc; +}; + +template <> +class Tuple<> { + // Simplified zero-member version of Tuple. In particular this is important to make sure that + // Tuple<>() is constexpr. +}; + +template +class Tuple; +// Single-element tuple should never be used. The public API should ensure this. + +template +inline TypeByIndex& getImpl(Tuple& tuple) { + // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. + static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); + return implicitCast>&>(tuple.impl).value; +} +template +inline TypeByIndex&& getImpl(Tuple&& tuple) { + // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. + static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); + return kj::mv(implicitCast>&>(tuple.impl).value); +} +template +inline const TypeByIndex& getImpl(const Tuple& tuple) { + // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. + static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); + return implicitCast>&>(tuple.impl).value; +} +template +inline T&& getImpl(T&& value) { + // Get member of a Tuple by index, e.g. `getImpl<2>(myTuple)`. + + // Non-tuples are equivalent to one-element tuples. + static_assert(index == 0, "Tuple element index out-of-bounds."); + return kj::fwd(value); +} + + +template +struct ExpandAndApplyResult_; +// Template which computes the return type of applying Func to T... after flattening tuples. +// SoFar starts as Tuple<> and accumulates the flattened parameter types -- so after this template +// is recursively expanded, T... is empty and SoFar is a Tuple containing all the parameters. + +template +struct ExpandAndApplyResult_, First, Rest...> + : public ExpandAndApplyResult_, Rest...> {}; +template +struct ExpandAndApplyResult_, Tuple, Rest...> + : public ExpandAndApplyResult_, FirstTypes&&..., Rest...> {}; +template +struct ExpandAndApplyResult_, Tuple&, Rest...> + : public ExpandAndApplyResult_, FirstTypes&..., Rest...> {}; +template +struct ExpandAndApplyResult_, const Tuple&, Rest...> + : public ExpandAndApplyResult_, const FirstTypes&..., Rest...> {}; +template +struct ExpandAndApplyResult_> { + typedef decltype(instance()(instance()...)) Type; +}; +template +using ExpandAndApplyResult = typename ExpandAndApplyResult_, T...>::Type; +// Computes the expected return type of `expandAndApply()`. + +template +inline auto expandAndApply(Func&& func) -> ExpandAndApplyResult { + return func(); +} + +template +struct ExpandAndApplyFunc { + Func&& func; + First&& first; + ExpandAndApplyFunc(Func&& func, First&& first) + : func(kj::fwd(func)), first(kj::fwd(first)) {} + template + auto operator()(T&&... params) + -> decltype(this->func(kj::fwd(first), kj::fwd(params)...)) { + return this->func(kj::fwd(first), kj::fwd(params)...); + } +}; + +template +inline auto expandAndApply(Func&& func, First&& first, Rest&&... rest) + -> ExpandAndApplyResult { + + return expandAndApply( + ExpandAndApplyFunc(kj::fwd(func), kj::fwd(first)), + kj::fwd(rest)...); +} + +template +inline auto expandAndApply(Func&& func, Tuple&& first, Rest&&... rest) + -> ExpandAndApplyResult { + return expandAndApplyWithIndexes(MakeIndexes(), + kj::fwd(func), kj::mv(first), kj::fwd(rest)...); +} + +template +inline auto expandAndApply(Func&& func, Tuple& first, Rest&&... rest) + -> ExpandAndApplyResult { + return expandAndApplyWithIndexes(MakeIndexes(), + kj::fwd(func), first, kj::fwd(rest)...); +} + +template +inline auto expandAndApply(Func&& func, const Tuple& first, Rest&&... rest) + -> ExpandAndApplyResult { + return expandAndApplyWithIndexes(MakeIndexes(), + kj::fwd(func), first, kj::fwd(rest)...); +} + +template +inline auto expandAndApplyWithIndexes( + Indexes, Func&& func, Tuple&& first, Rest&&... rest) + -> ExpandAndApplyResult { + return expandAndApply(kj::fwd(func), kj::mv(getImpl(first))..., + kj::fwd(rest)...); +} + +template +inline auto expandAndApplyWithIndexes( + Indexes, Func&& func, const Tuple& first, Rest&&... rest) + -> ExpandAndApplyResult { + return expandAndApply(kj::fwd(func), getImpl(first)..., + kj::fwd(rest)...); +} + +struct MakeTupleFunc { + template + Tuple...> operator()(Params&&... params) { + return Tuple...>(kj::fwd(params)...); + } + template + Decay operator()(Param&& param) { + return kj::fwd(param); + } +}; + +} // namespace _ (private) + +template struct Tuple_ { typedef _::Tuple Type; }; +template struct Tuple_ { typedef T Type; }; + +template using Tuple = typename Tuple_::Type; +// Tuple type. `Tuple` (i.e. a single-element tuple) is a synonym for `T`. Tuples of size +// other than 1 expand to an internal type. Either way, you can construct a Tuple using +// `kj::tuple(...)`, get an element by index `i` using `kj::get(myTuple)`, and expand the tuple +// as arguments to a function using `kj::apply(func, myTuple)`. +// +// Tuples are always flat -- that is, no element of a Tuple is ever itself a Tuple. If you +// construct a tuple from other tuples, the elements are flattened and concatenated. + +template +inline auto tuple(Params&&... params) + -> decltype(_::expandAndApply(_::MakeTupleFunc(), kj::fwd(params)...)) { + // Construct a new tuple from the given values. Any tuples in the argument list will be + // flattened into the result. + return _::expandAndApply(_::MakeTupleFunc(), kj::fwd(params)...); +} + +template +inline auto get(Tuple&& tuple) -> decltype(_::getImpl(kj::fwd(tuple))) { + // Unpack and return the tuple element at the given index. The index is specified as a template + // parameter, e.g. `kj::get<3>(myTuple)`. + return _::getImpl(kj::fwd(tuple)); +} + +template +inline auto apply(Func&& func, Params&&... params) + -> decltype(_::expandAndApply(kj::fwd(func), kj::fwd(params)...)) { + // Apply a function to some arguments, expanding tuples into separate arguments. + return _::expandAndApply(kj::fwd(func), kj::fwd(params)...); +} + +template struct TupleSize_ { static constexpr size_t size = 1; }; +template struct TupleSize_<_::Tuple> { + static constexpr size_t size = sizeof...(T); +}; + +template +constexpr size_t tupleSize() { return TupleSize_::size; } +// Returns size of the tuple T. + +} // namespace kj + +#endif // KJ_TUPLE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/units.h --- a/osx/include/kj/units.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/units.h Mon May 22 10:01:37 2017 +0100 @@ -1,433 +1,1172 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// This file contains types which are intended to help detect incorrect usage at compile -// time, but should then be optimized down to basic primitives (usually, integers) by the -// compiler. - -#ifndef KJ_UNITS_H_ -#define KJ_UNITS_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "common.h" - -namespace kj { - -// ======================================================================================= -// IDs - -template -struct Id { - // A type-safe numeric ID. `UnderlyingType` is the underlying integer representation. `Label` - // distinguishes this Id from other Id types. Sample usage: - // - // class Foo; - // typedef Id FooId; - // - // class Bar; - // typedef Id BarId; - // - // You can now use the FooId and BarId types without any possibility of accidentally using a - // FooId when you really wanted a BarId or vice-versa. - - UnderlyingType value; - - inline constexpr Id(): value(0) {} - inline constexpr explicit Id(int value): value(value) {} - - inline constexpr bool operator==(const Id& other) const { return value == other.value; } - inline constexpr bool operator!=(const Id& other) const { return value != other.value; } - inline constexpr bool operator<=(const Id& other) const { return value <= other.value; } - inline constexpr bool operator>=(const Id& other) const { return value >= other.value; } - inline constexpr bool operator< (const Id& other) const { return value < other.value; } - inline constexpr bool operator> (const Id& other) const { return value > other.value; } -}; - -// ======================================================================================= -// Quantity and UnitRatio -- implement unit analysis via the type system - -template constexpr bool isIntegral() { return false; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } -template <> constexpr bool isIntegral() { return true; } - -template -class UnitRatio { - // A multiplier used to convert Quantities of one unit to Quantities of another unit. See - // Quantity, below. - // - // Construct this type by dividing one Quantity by another of a different unit. Use this type - // by multiplying it by a Quantity, or dividing a Quantity by it. - - static_assert(isIntegral(), "Underlying type for UnitRatio must be integer."); - -public: - inline UnitRatio() {} - - constexpr explicit UnitRatio(Number unit1PerUnit2): unit1PerUnit2(unit1PerUnit2) {} - // This constructor was intended to be private, but GCC complains about it being private in a - // bunch of places that don't appear to even call it, so I made it public. Oh well. - - template - inline constexpr UnitRatio(const UnitRatio& other) - : unit1PerUnit2(other.unit1PerUnit2) {} - - template - inline constexpr UnitRatio - operator+(UnitRatio other) const { - return UnitRatio( - unit1PerUnit2 + other.unit1PerUnit2); - } - template - inline constexpr UnitRatio - operator-(UnitRatio other) const { - return UnitRatio( - unit1PerUnit2 - other.unit1PerUnit2); - } - - template - inline constexpr UnitRatio - operator*(UnitRatio other) const { - // U1 / U2 * U3 / U1 = U3 / U2 - return UnitRatio( - unit1PerUnit2 * other.unit1PerUnit2); - } - template - inline constexpr UnitRatio - operator*(UnitRatio other) const { - // U1 / U2 * U2 / U3 = U1 / U3 - return UnitRatio( - unit1PerUnit2 * other.unit1PerUnit2); - } - - template - inline constexpr UnitRatio - operator/(UnitRatio other) const { - // (U1 / U2) / (U1 / U3) = U3 / U2 - return UnitRatio( - unit1PerUnit2 / other.unit1PerUnit2); - } - template - inline constexpr UnitRatio - operator/(UnitRatio other) const { - // (U1 / U2) / (U3 / U2) = U1 / U3 - return UnitRatio( - unit1PerUnit2 / other.unit1PerUnit2); - } - - template - inline decltype(Number(1) / OtherNumber(1)) - operator/(UnitRatio other) const { - return unit1PerUnit2 / other.unit1PerUnit2; - } - - inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } - inline bool operator!=(UnitRatio other) const { return unit1PerUnit2 != other.unit1PerUnit2; } - -private: - Number unit1PerUnit2; - - template - friend class Quantity; - template - friend class UnitRatio; - - template - friend inline constexpr UnitRatio - operator*(N1, UnitRatio); -}; - -template -inline constexpr UnitRatio - operator*(N1 n, UnitRatio r) { - return UnitRatio(n * r.unit1PerUnit2); -} - -template -class Quantity { - // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used - // in arithmetic unless they use the same unit. The `Unit` type parameter is only used to prevent - // accidental mixing of units; this type is never instantiated and can very well be incomplete. - // `Number` is the underlying primitive numeric type. - // - // Quantities support most basic arithmetic operators, intelligently handling units, and - // automatically casting the underlying type in the same way that the compiler would. - // - // To convert a primitive number to a Quantity, multiply it by unit>(). - // To convert a Quantity to a primitive number, divide it by unit>(). - // To convert a Quantity of one unit to another unit, multiply or divide by a UnitRatio. - // - // The Quantity class is not well-suited to hardcore physics as it does not allow multiplying - // one quantity by another. For example, multiplying meters by meters won't get you square - // meters; it will get you a compiler error. It would be interesting to see if template - // metaprogramming could properly deal with such things but this isn't needed for the present - // use case. - // - // Sample usage: - // - // class SecondsLabel; - // typedef Quantity Seconds; - // constexpr Seconds SECONDS = unit(); - // - // class MinutesLabel; - // typedef Quantity Minutes; - // constexpr Minutes MINUTES = unit(); - // - // constexpr UnitRatio SECONDS_PER_MINUTE = - // 60 * SECONDS / MINUTES; - // - // void waitFor(Seconds seconds) { - // sleep(seconds / SECONDS); - // } - // void waitFor(Minutes minutes) { - // waitFor(minutes * SECONDS_PER_MINUTE); - // } - // - // void waitThreeMinutes() { - // waitFor(3 * MINUTES); - // } - - static_assert(isIntegral(), "Underlying type for Quantity must be integer."); - -public: - inline constexpr Quantity() {} - - inline constexpr Quantity(MaxValue_): value(maxValue) {} - inline constexpr Quantity(MinValue_): value(minValue) {} - // Allow initialization from maxValue and minValue. - // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function - // parameters, causing the compiler to complain of a duplicate constructor definition, so we - // specify MaxValue_ and MinValue_ types explicitly. - - inline explicit constexpr Quantity(Number value): value(value) {} - // This constructor was intended to be private, but GCC complains about it being private in a - // bunch of places that don't appear to even call it, so I made it public. Oh well. - - template - inline constexpr Quantity(const Quantity& other) - : value(other.value) {} - - template - inline constexpr Quantity - operator+(const Quantity& other) const { - return Quantity(value + other.value); - } - template - inline constexpr Quantity - operator-(const Quantity& other) const { - return Quantity(value - other.value); - } - template - inline constexpr Quantity - operator*(OtherNumber other) const { - static_assert(isIntegral(), "Multiplied Quantity by non-integer."); - return Quantity(value * other); - } - template - inline constexpr Quantity - operator/(OtherNumber other) const { - static_assert(isIntegral(), "Divided Quantity by non-integer."); - return Quantity(value / other); - } - template - inline constexpr decltype(Number(1) / OtherNumber(1)) - operator/(const Quantity& other) const { - return value / other.value; - } - template - inline constexpr decltype(Number(1) % OtherNumber(1)) - operator%(const Quantity& other) const { - return value % other.value; - } - - template - inline constexpr Quantity - operator*(const UnitRatio& ratio) const { - return Quantity( - value * ratio.unit1PerUnit2); - } - template - inline constexpr Quantity - operator/(const UnitRatio& ratio) const { - return Quantity( - value / ratio.unit1PerUnit2); - } - template - inline constexpr Quantity - operator%(const UnitRatio& ratio) const { - return Quantity( - value % ratio.unit1PerUnit2); - } - template - inline constexpr UnitRatio - operator/(const Quantity& other) const { - return UnitRatio(value / other.value); - } - - template - inline constexpr bool operator==(const Quantity& other) const { - return value == other.value; - } - template - inline constexpr bool operator!=(const Quantity& other) const { - return value != other.value; - } - template - inline constexpr bool operator<=(const Quantity& other) const { - return value <= other.value; - } - template - inline constexpr bool operator>=(const Quantity& other) const { - return value >= other.value; - } - template - inline constexpr bool operator<(const Quantity& other) const { - return value < other.value; - } - template - inline constexpr bool operator>(const Quantity& other) const { - return value > other.value; - } - - template - inline Quantity& operator+=(const Quantity& other) { - value += other.value; - return *this; - } - template - inline Quantity& operator-=(const Quantity& other) { - value -= other.value; - return *this; - } - template - inline Quantity& operator*=(OtherNumber other) { - value *= other; - return *this; - } - template - inline Quantity& operator/=(OtherNumber other) { - value /= other.value; - return *this; - } - -private: - Number value; - - template - friend class Quantity; - - template - friend inline constexpr auto operator*(Number1 a, Quantity b) - -> Quantity; - - template - friend inline constexpr T unit(); -}; - -template -inline constexpr T unit() { return T(1); } -// unit>() returns a Quantity of value 1. It also, intentionally, works on basic -// numeric types. - -template -inline constexpr auto operator*(Number1 a, Quantity b) - -> Quantity { - return Quantity(a * b.value); -} - -template -inline constexpr auto operator*(UnitRatio ratio, - Quantity measure) - -> decltype(measure * ratio) { - return measure * ratio; -} - -// ======================================================================================= -// Absolute measures - -template -class Absolute { - // Wraps some other value -- typically a Quantity -- but represents a value measured based on - // some absolute origin. For example, if `Duration` is a type representing a time duration, - // Absolute might be a calendar date. - // - // Since Absolute represents measurements relative to some arbitrary origin, the only sensible - // arithmetic to perform on them is addition and subtraction. - - // TODO(someday): Do the same automatic expansion of integer width that Quantity does? Doesn't - // matter for our time use case, where we always use 64-bit anyway. Note that fixing this - // would implicitly allow things like multiplying an Absolute by a UnitRatio to change its - // units, which is actually totally logical and kind of neat. - -public: - inline constexpr Absolute operator+(const T& other) const { return Absolute(value + other); } - inline constexpr Absolute operator-(const T& other) const { return Absolute(value - other); } - inline constexpr T operator-(const Absolute& other) const { return value - other.value; } - - inline Absolute& operator+=(const T& other) { value += other; return *this; } - inline Absolute& operator-=(const T& other) { value -= other; return *this; } - - inline constexpr bool operator==(const Absolute& other) const { return value == other.value; } - inline constexpr bool operator!=(const Absolute& other) const { return value != other.value; } - inline constexpr bool operator<=(const Absolute& other) const { return value <= other.value; } - inline constexpr bool operator>=(const Absolute& other) const { return value >= other.value; } - inline constexpr bool operator< (const Absolute& other) const { return value < other.value; } - inline constexpr bool operator> (const Absolute& other) const { return value > other.value; } - -private: - T value; - - explicit constexpr Absolute(T value): value(value) {} - - template - friend inline constexpr U origin(); -}; - -template -inline constexpr Absolute operator+(const T& a, const Absolute& b) { - return b + a; -} - -template struct UnitOf_ { typedef T Type; }; -template struct UnitOf_> { typedef T Type; }; -template -using UnitOf = typename UnitOf_::Type; -// UnitOf> is T. UnitOf is AnythingElse. - -template -inline constexpr T origin() { return T(0 * unit>()); } -// origin>() returns an Absolute of value 0. It also, intentionally, works on basic -// numeric types. - -} // namespace kj - -#endif // KJ_UNITS_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains types which are intended to help detect incorrect usage at compile +// time, but should then be optimized down to basic primitives (usually, integers) by the +// compiler. + +#ifndef KJ_UNITS_H_ +#define KJ_UNITS_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" +#include + +namespace kj { + +// ======================================================================================= +// IDs + +template +struct Id { + // A type-safe numeric ID. `UnderlyingType` is the underlying integer representation. `Label` + // distinguishes this Id from other Id types. Sample usage: + // + // class Foo; + // typedef Id FooId; + // + // class Bar; + // typedef Id BarId; + // + // You can now use the FooId and BarId types without any possibility of accidentally using a + // FooId when you really wanted a BarId or vice-versa. + + UnderlyingType value; + + inline constexpr Id(): value(0) {} + inline constexpr explicit Id(int value): value(value) {} + + inline constexpr bool operator==(const Id& other) const { return value == other.value; } + inline constexpr bool operator!=(const Id& other) const { return value != other.value; } + inline constexpr bool operator<=(const Id& other) const { return value <= other.value; } + inline constexpr bool operator>=(const Id& other) const { return value >= other.value; } + inline constexpr bool operator< (const Id& other) const { return value < other.value; } + inline constexpr bool operator> (const Id& other) const { return value > other.value; } +}; + +// ======================================================================================= +// Quantity and UnitRatio -- implement unit analysis via the type system + +struct Unsafe_ {}; +constexpr Unsafe_ unsafe = Unsafe_(); +// Use as a parameter to constructors that are unsafe to indicate that you really do mean it. + +template +class Bounded; +template +class BoundedConst; + +template constexpr bool isIntegral() { return false; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } +template <> constexpr bool isIntegral() { return true; } + +template +struct IsIntegralOrBounded_ { static constexpr bool value = isIntegral(); }; +template +struct IsIntegralOrBounded_> { static constexpr bool value = true; }; +template +struct IsIntegralOrBounded_> { static constexpr bool value = true; }; + +template +inline constexpr bool isIntegralOrBounded() { return IsIntegralOrBounded_::value; } + +template +class UnitRatio { + // A multiplier used to convert Quantities of one unit to Quantities of another unit. See + // Quantity, below. + // + // Construct this type by dividing one Quantity by another of a different unit. Use this type + // by multiplying it by a Quantity, or dividing a Quantity by it. + + static_assert(isIntegralOrBounded(), + "Underlying type for UnitRatio must be integer."); + +public: + inline UnitRatio() {} + + constexpr UnitRatio(Number unit1PerUnit2, decltype(unsafe)): unit1PerUnit2(unit1PerUnit2) {} + // This constructor was intended to be private, but GCC complains about it being private in a + // bunch of places that don't appear to even call it, so I made it public. Oh well. + + template + inline constexpr UnitRatio(const UnitRatio& other) + : unit1PerUnit2(other.unit1PerUnit2) {} + + template + inline constexpr UnitRatio + operator+(UnitRatio other) const { + return UnitRatio( + unit1PerUnit2 + other.unit1PerUnit2, unsafe); + } + template + inline constexpr UnitRatio + operator-(UnitRatio other) const { + return UnitRatio( + unit1PerUnit2 - other.unit1PerUnit2, unsafe); + } + + template + inline constexpr UnitRatio + operator*(UnitRatio other) const { + // U1 / U2 * U3 / U1 = U3 / U2 + return UnitRatio( + unit1PerUnit2 * other.unit1PerUnit2, unsafe); + } + template + inline constexpr UnitRatio + operator*(UnitRatio other) const { + // U1 / U2 * U2 / U3 = U1 / U3 + return UnitRatio( + unit1PerUnit2 * other.unit1PerUnit2, unsafe); + } + + template + inline constexpr UnitRatio + operator/(UnitRatio other) const { + // (U1 / U2) / (U1 / U3) = U3 / U2 + return UnitRatio( + unit1PerUnit2 / other.unit1PerUnit2, unsafe); + } + template + inline constexpr UnitRatio + operator/(UnitRatio other) const { + // (U1 / U2) / (U3 / U2) = U1 / U3 + return UnitRatio( + unit1PerUnit2 / other.unit1PerUnit2, unsafe); + } + + template + inline decltype(Number() / OtherNumber()) + operator/(UnitRatio other) const { + return unit1PerUnit2 / other.unit1PerUnit2; + } + + inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } + inline bool operator!=(UnitRatio other) const { return unit1PerUnit2 != other.unit1PerUnit2; } + +private: + Number unit1PerUnit2; + + template + friend class Quantity; + template + friend class UnitRatio; + + template + friend inline constexpr UnitRatio + operator*(N1, UnitRatio); +}; + +template () && isIntegralOrBounded()>> +inline constexpr UnitRatio + operator*(N1 n, UnitRatio r) { + return UnitRatio(n * r.unit1PerUnit2, unsafe); +} + +template +class Quantity { + // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used + // in arithmetic unless they use the same unit. The `Unit` type parameter is only used to prevent + // accidental mixing of units; this type is never instantiated and can very well be incomplete. + // `Number` is the underlying primitive numeric type. + // + // Quantities support most basic arithmetic operators, intelligently handling units, and + // automatically casting the underlying type in the same way that the compiler would. + // + // To convert a primitive number to a Quantity, multiply it by unit>(). + // To convert a Quantity to a primitive number, divide it by unit>(). + // To convert a Quantity of one unit to another unit, multiply or divide by a UnitRatio. + // + // The Quantity class is not well-suited to hardcore physics as it does not allow multiplying + // one quantity by another. For example, multiplying meters by meters won't get you square + // meters; it will get you a compiler error. It would be interesting to see if template + // metaprogramming could properly deal with such things but this isn't needed for the present + // use case. + // + // Sample usage: + // + // class SecondsLabel; + // typedef Quantity Seconds; + // constexpr Seconds SECONDS = unit(); + // + // class MinutesLabel; + // typedef Quantity Minutes; + // constexpr Minutes MINUTES = unit(); + // + // constexpr UnitRatio SECONDS_PER_MINUTE = + // 60 * SECONDS / MINUTES; + // + // void waitFor(Seconds seconds) { + // sleep(seconds / SECONDS); + // } + // void waitFor(Minutes minutes) { + // waitFor(minutes * SECONDS_PER_MINUTE); + // } + // + // void waitThreeMinutes() { + // waitFor(3 * MINUTES); + // } + + static_assert(isIntegralOrBounded(), + "Underlying type for Quantity must be integer."); + +public: + inline constexpr Quantity() = default; + + inline constexpr Quantity(MaxValue_): value(maxValue) {} + inline constexpr Quantity(MinValue_): value(minValue) {} + // Allow initialization from maxValue and minValue. + // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function + // parameters, causing the compiler to complain of a duplicate constructor definition, so we + // specify MaxValue_ and MinValue_ types explicitly. + + inline constexpr Quantity(Number value, decltype(unsafe)): value(value) {} + // This constructor was intended to be private, but GCC complains about it being private in a + // bunch of places that don't appear to even call it, so I made it public. Oh well. + + template + inline constexpr Quantity(const Quantity& other) + : value(other.value) {} + + template + inline Quantity& operator=(const Quantity& other) { + value = other.value; + return *this; + } + + template + inline constexpr Quantity + operator+(const Quantity& other) const { + return Quantity(value + other.value, unsafe); + } + template + inline constexpr Quantity + operator-(const Quantity& other) const { + return Quantity(value - other.value, unsafe); + } + template ()>> + inline constexpr Quantity + operator*(OtherNumber other) const { + return Quantity(value * other, unsafe); + } + template ()>> + inline constexpr Quantity + operator/(OtherNumber other) const { + return Quantity(value / other, unsafe); + } + template + inline constexpr decltype(Number() / OtherNumber()) + operator/(const Quantity& other) const { + return value / other.value; + } + template + inline constexpr Quantity + operator%(const Quantity& other) const { + return Quantity(value % other.value, unsafe); + } + + template + inline constexpr Quantity + operator*(UnitRatio ratio) const { + return Quantity( + value * ratio.unit1PerUnit2, unsafe); + } + template + inline constexpr Quantity + operator/(UnitRatio ratio) const { + return Quantity( + value / ratio.unit1PerUnit2, unsafe); + } + template + inline constexpr Quantity + operator%(UnitRatio ratio) const { + return Quantity( + value % ratio.unit1PerUnit2, unsafe); + } + template + inline constexpr UnitRatio + operator/(Quantity other) const { + return UnitRatio( + value / other.value, unsafe); + } + + template + inline constexpr bool operator==(const Quantity& other) const { + return value == other.value; + } + template + inline constexpr bool operator!=(const Quantity& other) const { + return value != other.value; + } + template + inline constexpr bool operator<=(const Quantity& other) const { + return value <= other.value; + } + template + inline constexpr bool operator>=(const Quantity& other) const { + return value >= other.value; + } + template + inline constexpr bool operator<(const Quantity& other) const { + return value < other.value; + } + template + inline constexpr bool operator>(const Quantity& other) const { + return value > other.value; + } + + template + inline Quantity& operator+=(const Quantity& other) { + value += other.value; + return *this; + } + template + inline Quantity& operator-=(const Quantity& other) { + value -= other.value; + return *this; + } + template + inline Quantity& operator*=(OtherNumber other) { + value *= other; + return *this; + } + template + inline Quantity& operator/=(OtherNumber other) { + value /= other.value; + return *this; + } + +private: + Number value; + + template + friend class Quantity; + + template + friend inline constexpr auto operator*(Number1 a, Quantity b) + -> Quantity; +}; + +template struct Unit_ { + static inline constexpr T get() { return T(1); } +}; +template +struct Unit_> { + static inline constexpr Quantity::get()), U> get() { + return Quantity::get()), U>(Unit_::get(), unsafe); + } +}; + +template +inline constexpr auto unit() -> decltype(Unit_::get()) { return Unit_::get(); } +// unit>() returns a Quantity of value 1. It also, intentionally, works on basic +// numeric types. + +template +inline constexpr auto operator*(Number1 a, Quantity b) + -> Quantity { + return Quantity(a * b.value, unsafe); +} + +template +inline constexpr auto operator*(UnitRatio ratio, + Quantity measure) + -> decltype(measure * ratio) { + return measure * ratio; +} + +// ======================================================================================= +// Absolute measures + +template +class Absolute { + // Wraps some other value -- typically a Quantity -- but represents a value measured based on + // some absolute origin. For example, if `Duration` is a type representing a time duration, + // Absolute might be a calendar date. + // + // Since Absolute represents measurements relative to some arbitrary origin, the only sensible + // arithmetic to perform on them is addition and subtraction. + + // TODO(someday): Do the same automatic expansion of integer width that Quantity does? Doesn't + // matter for our time use case, where we always use 64-bit anyway. Note that fixing this + // would implicitly allow things like multiplying an Absolute by a UnitRatio to change its + // units, which is actually totally logical and kind of neat. + +public: + inline constexpr Absolute operator+(const T& other) const { return Absolute(value + other); } + inline constexpr Absolute operator-(const T& other) const { return Absolute(value - other); } + inline constexpr T operator-(const Absolute& other) const { return value - other.value; } + + inline Absolute& operator+=(const T& other) { value += other; return *this; } + inline Absolute& operator-=(const T& other) { value -= other; return *this; } + + inline constexpr bool operator==(const Absolute& other) const { return value == other.value; } + inline constexpr bool operator!=(const Absolute& other) const { return value != other.value; } + inline constexpr bool operator<=(const Absolute& other) const { return value <= other.value; } + inline constexpr bool operator>=(const Absolute& other) const { return value >= other.value; } + inline constexpr bool operator< (const Absolute& other) const { return value < other.value; } + inline constexpr bool operator> (const Absolute& other) const { return value > other.value; } + +private: + T value; + + explicit constexpr Absolute(T value): value(value) {} + + template + friend inline constexpr U origin(); +}; + +template +inline constexpr Absolute operator+(const T& a, const Absolute& b) { + return b + a; +} + +template struct UnitOf_ { typedef T Type; }; +template struct UnitOf_> { typedef T Type; }; +template +using UnitOf = typename UnitOf_::Type; +// UnitOf> is T. UnitOf is AnythingElse. + +template +inline constexpr T origin() { return T(0 * unit>()); } +// origin>() returns an Absolute of value 0. It also, intentionally, works on basic +// numeric types. + +// ======================================================================================= +// Overflow avoidance + +template +struct BitCount_ { + static constexpr uint value = BitCount_<(n >> 1), accum + 1>::value; +}; +template +struct BitCount_<0, accum> { + static constexpr uint value = accum; +}; + +template +inline constexpr uint bitCount() { return BitCount_::value; } +// Number of bits required to represent the number `n`. + +template struct AtLeastUInt_ { + static_assert(bitCountBitCount < 7, "don't know how to represent integers over 64 bits"); +}; +template <> struct AtLeastUInt_<0> { typedef uint8_t Type; }; +template <> struct AtLeastUInt_<1> { typedef uint8_t Type; }; +template <> struct AtLeastUInt_<2> { typedef uint8_t Type; }; +template <> struct AtLeastUInt_<3> { typedef uint8_t Type; }; +template <> struct AtLeastUInt_<4> { typedef uint16_t Type; }; +template <> struct AtLeastUInt_<5> { typedef uint32_t Type; }; +template <> struct AtLeastUInt_<6> { typedef uint64_t Type; }; + +template +using AtLeastUInt = typename AtLeastUInt_()>::Type; +// AtLeastUInt is an unsigned integer of at least n bits. E.g. AtLeastUInt<12> is uint16_t. + +// ------------------------------------------------------------------- + +template +class BoundedConst { + // A constant integer value on which we can do bit size analysis. + +public: + BoundedConst() = default; + + inline constexpr uint unwrap() const { return value; } + +#define OP(op, check) \ + template \ + inline constexpr BoundedConst<(value op other)> \ + operator op(BoundedConst) const { \ + static_assert(check, "overflow in BoundedConst arithmetic"); \ + return BoundedConst<(value op other)>(); \ + } +#define COMPARE_OP(op) \ + template \ + inline constexpr bool operator op(BoundedConst) const { \ + return value op other; \ + } + + OP(+, value + other >= value) + OP(-, value - other <= value) + OP(*, value * other / other == value) + OP(/, true) // div by zero already errors out; no other division ever overflows + OP(%, true) // mod by zero already errors out; no other modulus ever overflows + OP(<<, value << other >= value) + OP(>>, true) // right shift can't overflow + OP(&, true) // bitwise ops can't overflow + OP(|, true) // bitwise ops can't overflow + + COMPARE_OP(==) + COMPARE_OP(!=) + COMPARE_OP(< ) + COMPARE_OP(> ) + COMPARE_OP(<=) + COMPARE_OP(>=) +#undef OP +#undef COMPARE_OP +}; + +template +struct Unit_> { + static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } +}; + +template +struct Unit_> { + static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } +}; + +template +inline constexpr BoundedConst bounded() { + return BoundedConst(); +} + +template +static constexpr uint64_t boundedAdd() { + static_assert(a + b >= a, "possible overflow detected"); + return a + b; +} +template +static constexpr uint64_t boundedSub() { + static_assert(a - b <= a, "possible underflow detected"); + return a - b; +} +template +static constexpr uint64_t boundedMul() { + static_assert(a * b / b == a, "possible overflow detected"); + return a * b; +} +template +static constexpr uint64_t boundedLShift() { + static_assert(a << b >= a, "possible overflow detected"); + return a << b; +} + +template +inline constexpr BoundedConst min(BoundedConst, BoundedConst) { + return bounded(); +} +template +inline constexpr BoundedConst max(BoundedConst, BoundedConst) { + return bounded(); +} +// We need to override min() and max() between constants because the ternary operator in the +// default implementation would complain. + +// ------------------------------------------------------------------- + +template +class Bounded { +public: + static_assert(maxN <= T(kj::maxValue), "possible overflow detected"); + + Bounded() = default; + + Bounded(const Bounded& other) = default; + template ()>> + inline constexpr Bounded(OtherInt value): value(value) { + static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); + } + template + inline constexpr Bounded(const Bounded& other) + : value(other.value) { + static_assert(otherMax <= maxN, "possible overflow detected"); + } + template + inline constexpr Bounded(BoundedConst) + : value(otherValue) { + static_assert(otherValue <= maxN, "overflow detected"); + } + + Bounded& operator=(const Bounded& other) = default; + template ()>> + Bounded& operator=(OtherInt other) { + static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); + value = other; + return *this; + } + template + inline Bounded& operator=(const Bounded& other) { + static_assert(otherMax <= maxN, "possible overflow detected"); + value = other.value; + return *this; + } + template + inline Bounded& operator=(BoundedConst) { + static_assert(otherValue <= maxN, "overflow detected"); + value = otherValue; + return *this; + } + + inline constexpr T unwrap() const { return value; } + +#define OP(op, newMax) \ + template \ + inline constexpr Bounded \ + operator op(const Bounded& other) const { \ + return Bounded(value op other.value, unsafe); \ + } +#define COMPARE_OP(op) \ + template \ + inline constexpr bool operator op(const Bounded& other) const { \ + return value op other.value; \ + } + + OP(+, (boundedAdd())) + OP(*, (boundedMul())) + OP(/, maxN) + OP(%, otherMax - 1) + + // operator- is intentionally omitted because we mostly use this with unsigned types, and + // subtraction requires proof that subtrahend is not greater than the minuend. + + COMPARE_OP(==) + COMPARE_OP(!=) + COMPARE_OP(< ) + COMPARE_OP(> ) + COMPARE_OP(<=) + COMPARE_OP(>=) + +#undef OP +#undef COMPARE_OP + + template + inline Bounded assertMax(ErrorFunc&& func) const { + // Assert that the number is no more than `newMax`. Otherwise, call `func`. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + if (KJ_UNLIKELY(value > newMax)) func(); + return Bounded(value, unsafe); + } + + template + inline Bounded subtractChecked( + const Bounded& other, ErrorFunc&& func) const { + // Subtract a number, calling func() if the result would underflow. + if (KJ_UNLIKELY(value < other.value)) func(); + return Bounded(value - other.value, unsafe); + } + + template + inline Bounded subtractChecked( + BoundedConst, ErrorFunc&& func) const { + // Subtract a number, calling func() if the result would underflow. + static_assert(otherValue <= maxN, "underflow detected"); + if (KJ_UNLIKELY(value < otherValue)) func(); + return Bounded(value - otherValue, unsafe); + } + + template + inline Maybe> trySubtract( + const Bounded& other) const { + // Subtract a number, calling func() if the result would underflow. + if (value < other.value) { + return nullptr; + } else { + return Bounded(value - other.value, unsafe); + } + } + + template + inline Maybe> trySubtract(BoundedConst) const { + // Subtract a number, calling func() if the result would underflow. + if (value < otherValue) { + return nullptr; + } else { + return Bounded(value - otherValue, unsafe); + } + } + + inline constexpr Bounded(T value, decltype(unsafe)): value(value) {} + template + inline constexpr Bounded(Bounded value, decltype(unsafe)) + : value(value.value) {} + // Mainly for internal use. + // + // Only use these as a last resort, with ample commentary on why you think it's safe. + +private: + T value; + + template + friend class Bounded; +}; + +template +inline constexpr Bounded bounded(Number value) { + return Bounded(value, unsafe); +} + +inline constexpr Bounded<1, uint8_t> bounded(bool value) { + return Bounded<1, uint8_t>(value, unsafe); +} + +template +inline constexpr Bounded(), Number> assumeBits(Number value) { + return Bounded(), Number>(value, unsafe); +} + +template +inline constexpr Bounded(), T> assumeBits(Bounded value) { + return Bounded(), T>(value, unsafe); +} + +template +inline constexpr auto assumeBits(Quantity value) + -> Quantity(value / unit>())), Unit> { + return Quantity(value / unit>())), Unit>( + assumeBits(value / unit>()), unsafe); +} + +template +inline constexpr Bounded assumeMax(Number value) { + return Bounded(value, unsafe); +} + +template +inline constexpr Bounded assumeMax(Bounded value) { + return Bounded(value, unsafe); +} + +template +inline constexpr auto assumeMax(Quantity value) + -> Quantity(value / unit>())), Unit> { + return Quantity(value / unit>())), Unit>( + assumeMax(value / unit>()), unsafe); +} + +template +inline constexpr Bounded assumeMax(BoundedConst, Number value) { + return assumeMax(value); +} + +template +inline constexpr Bounded assumeMax(BoundedConst, Bounded value) { + return assumeMax(value); +} + +template +inline constexpr auto assumeMax(Quantity, Unit>, Quantity value) + -> decltype(assumeMax(value)) { + return assumeMax(value); +} + +template +inline Bounded assertMax(Bounded value, ErrorFunc&& errorFunc) { + // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() + // if not. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + return value.template assertMax(kj::fwd(errorFunc)); +} + +template +inline Quantity, Unit> assertMax( + Quantity, Unit> value, ErrorFunc&& errorFunc) { + // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() + // if not. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + return (value / unit()).template assertMax( + kj::fwd(errorFunc)) * unit(); +} + +template +inline Bounded assertMax( + BoundedConst, Bounded value, ErrorFunc&& errorFunc) { + return assertMax(value, kj::mv(errorFunc)); +} + +template +inline Quantity, Unit> assertMax( + Quantity, Unit>, + Quantity, Unit> value, ErrorFunc&& errorFunc) { + return assertMax(value, kj::mv(errorFunc)); +} + +template +inline Bounded(), T> assertMaxBits( + Bounded value, ErrorFunc&& errorFunc = ErrorFunc()) { + // Assert that the bounded value requires no more than the given number of bits, calling + // errorFunc() if not. + return assertMax()>(value, kj::fwd(errorFunc)); +} + +template +inline Quantity(), T>, Unit> assertMaxBits( + Quantity, Unit> value, ErrorFunc&& errorFunc = ErrorFunc()) { + // Assert that the bounded value requires no more than the given number of bits, calling + // errorFunc() if not. + return assertMax()>(value, kj::fwd(errorFunc)); +} + +template +inline constexpr Bounded upgradeBound(Bounded value) { + return value; +} + +template +inline constexpr Quantity, Unit> upgradeBound( + Quantity, Unit> value) { + return value; +} + +template +inline auto subtractChecked(Bounded value, Other other, ErrorFunc&& errorFunc) + -> decltype(value.subtractChecked(other, kj::fwd(errorFunc))) { + return value.subtractChecked(other, kj::fwd(errorFunc)); +} + +template +inline auto subtractChecked(Quantity value, Quantity other, ErrorFunc&& errorFunc) + -> Quantity(errorFunc))), Unit> { + return subtractChecked(value / unit>(), + other / unit>(), + kj::fwd(errorFunc)) + * unit>(); +} + +template +inline auto trySubtract(Bounded value, Other other) + -> decltype(value.trySubtract(other)) { + return value.trySubtract(other); +} + +template +inline auto trySubtract(Quantity value, Quantity other) + -> Maybe> { + return trySubtract(value / unit>(), + other / unit>()) + .map([](decltype(subtractChecked(T(), U(), int())) x) { + return x * unit>(); + }); +} + +template +inline constexpr Bounded> +min(Bounded a, Bounded b) { + return Bounded>(kj::min(a.unwrap(), b.unwrap()), unsafe); +} +template +inline constexpr Bounded> +max(Bounded a, Bounded b) { + return Bounded>(kj::max(a.unwrap(), b.unwrap()), unsafe); +} +// We need to override min() and max() because: +// 1) WiderType<> might not choose the correct bounds. +// 2) One of the two sides of the ternary operator in the default implementation would fail to +// typecheck even though it is OK in practice. + +// ------------------------------------------------------------------- +// Operators between Bounded and BoundedConst + +#define OP(op, newMax) \ +template \ +inline constexpr Bounded<(newMax), decltype(T() op uint())> operator op( \ + Bounded value, BoundedConst) { \ + return Bounded<(newMax), decltype(T() op uint())>(value.unwrap() op cvalue, unsafe); \ +} + +#define REVERSE_OP(op, newMax) \ +template \ +inline constexpr Bounded<(newMax), decltype(uint() op T())> operator op( \ + BoundedConst, Bounded value) { \ + return Bounded<(newMax), decltype(uint() op T())>(cvalue op value.unwrap(), unsafe); \ +} + +#define COMPARE_OP(op) \ +template \ +inline constexpr bool operator op(Bounded value, BoundedConst) { \ + return value.unwrap() op cvalue; \ +} \ +template \ +inline constexpr bool operator op(BoundedConst, Bounded value) { \ + return cvalue op value.unwrap(); \ +} + +OP(+, (boundedAdd())) +REVERSE_OP(+, (boundedAdd())) + +OP(*, (boundedMul())) +REVERSE_OP(*, (boundedAdd())) + +OP(/, maxN / cvalue) +REVERSE_OP(/, cvalue) // denominator could be 1 + +OP(%, cvalue - 1) +REVERSE_OP(%, maxN - 1) + +OP(<<, (boundedLShift())) +REVERSE_OP(<<, (boundedLShift())) + +OP(>>, maxN >> cvalue) +REVERSE_OP(>>, cvalue >> maxN) + +OP(&, maxValueForBits()>() & cvalue) +REVERSE_OP(&, maxValueForBits()>() & cvalue) + +OP(|, maxN | cvalue) +REVERSE_OP(|, maxN | cvalue) + +COMPARE_OP(==) +COMPARE_OP(!=) +COMPARE_OP(< ) +COMPARE_OP(> ) +COMPARE_OP(<=) +COMPARE_OP(>=) + +#undef OP +#undef REVERSE_OP +#undef COMPARE_OP + +template +inline constexpr Bounded + operator-(BoundedConst, Bounded value) { + // We allow subtraction of a variable from a constant only if the constant is greater than or + // equal to the maximum possible value of the variable. Since the variable could be zero, the + // result can be as large as the constant. + // + // We do not allow subtraction of a constant from a variable because there's never a guarantee it + // won't underflow (unless the constant is zero, which is silly). + static_assert(cvalue >= maxN, "possible underflow detected"); + return Bounded(cvalue - value.unwrap(), unsafe); +} + +template +inline constexpr Bounded min(Bounded a, BoundedConst) { + return Bounded(kj::min(b, a.unwrap()), unsafe); +} +template +inline constexpr Bounded min(BoundedConst, Bounded a) { + return Bounded(kj::min(a.unwrap(), b), unsafe); +} +template +inline constexpr Bounded max(Bounded a, BoundedConst) { + return Bounded(kj::max(b, a.unwrap()), unsafe); +} +template +inline constexpr Bounded max(BoundedConst, Bounded a) { + return Bounded(kj::max(a.unwrap(), b), unsafe); +} +// We need to override min() between a Bounded and a constant since: +// 1) WiderType<> might choose BoundedConst over a 1-byte Bounded, which is wrong. +// 2) To clamp the bounds of the output type. +// 3) Same ternary operator typechecking issues. + +// ------------------------------------------------------------------- + +template +class SafeUnwrapper { +public: + inline explicit constexpr SafeUnwrapper(Bounded value): value(value.unwrap()) {} + + template ()>> + inline constexpr operator U() const { + static_assert(maxN <= U(maxValue), "possible truncation detected"); + return value; + } + + inline constexpr operator bool() const { + static_assert(maxN <= 1, "possible truncation detected"); + return value; + } + +private: + T value; +}; + +template +inline constexpr SafeUnwrapper unbound(Bounded bounded) { + // Unwraps the bounded value, returning a value that can be implicitly cast to any integer type. + // If this implicit cast could truncate, a compile-time error will be raised. + return SafeUnwrapper(bounded); +} + +template +class SafeConstUnwrapper { +public: + template ()>> + inline constexpr operator T() const { + static_assert(value <= T(maxValue), "this operation will truncate"); + return value; + } + + inline constexpr operator bool() const { + static_assert(value <= 1, "this operation will truncate"); + return value; + } +}; + +template +inline constexpr SafeConstUnwrapper unbound(BoundedConst) { + return SafeConstUnwrapper(); +} + +template +inline constexpr T unboundAs(U value) { + return unbound(value); +} + +template +inline constexpr T unboundMax(Bounded value) { + // Explicitly ungaurd expecting a value that is at most `maxN`. + static_assert(maxN <= requestedMax, "possible overflow detected"); + return value.unwrap(); +} + +template +inline constexpr uint unboundMax(BoundedConst) { + // Explicitly ungaurd expecting a value that is at most `maxN`. + static_assert(value <= requestedMax, "overflow detected"); + return value; +} + +template +inline constexpr auto unboundMaxBits(T value) -> + decltype(unboundMax()>(value)) { + // Explicitly ungaurd expecting a value that fits into `bits` bits. + return unboundMax()>(value); +} + +#define OP(op) \ +template \ +inline constexpr auto operator op(T a, SafeUnwrapper b) -> decltype(a op (T)b) { \ + return a op (AtLeastUInt)b; \ +} \ +template \ +inline constexpr auto operator op(SafeUnwrapper b, T a) -> decltype((T)b op a) { \ + return (AtLeastUInt)b op a; \ +} \ +template \ +inline constexpr auto operator op(T a, SafeConstUnwrapper b) -> decltype(a op (T)b) { \ + return a op (AtLeastUInt)b; \ +} \ +template \ +inline constexpr auto operator op(SafeConstUnwrapper b, T a) -> decltype((T)b op a) { \ + return (AtLeastUInt)b op a; \ +} + +OP(+) +OP(-) +OP(*) +OP(/) +OP(%) +OP(<<) +OP(>>) +OP(&) +OP(|) +OP(==) +OP(!=) +OP(<=) +OP(>=) +OP(<) +OP(>) + +#undef OP + +// ------------------------------------------------------------------- + +template +class Range> { +public: + inline constexpr Range(Bounded begin, Bounded end) + : inner(unbound(begin), unbound(end)) {} + inline explicit constexpr Range(Bounded end) + : inner(unbound(end)) {} + + class Iterator { + public: + Iterator() = default; + inline explicit Iterator(typename Range::Iterator inner): inner(inner) {} + + inline Bounded operator* () const { return Bounded(*inner, unsafe); } + inline Iterator& operator++() { ++inner; return *this; } + + inline bool operator==(const Iterator& other) const { return inner == other.inner; } + inline bool operator!=(const Iterator& other) const { return inner != other.inner; } + + private: + typename Range::Iterator inner; + }; + + inline Iterator begin() const { return Iterator(inner.begin()); } + inline Iterator end() const { return Iterator(inner.end()); } + +private: + Range inner; +}; + +template +class Range> { +public: + inline constexpr Range(Quantity begin, Quantity end) + : inner(begin / unit>(), end / unit>()) {} + inline explicit constexpr Range(Quantity end) + : inner(end / unit>()) {} + + class Iterator { + public: + Iterator() = default; + inline explicit Iterator(typename Range::Iterator inner): inner(inner) {} + + inline Quantity operator* () const { return *inner * unit>(); } + inline Iterator& operator++() { ++inner; return *this; } + + inline bool operator==(const Iterator& other) const { return inner == other.inner; } + inline bool operator!=(const Iterator& other) const { return inner != other.inner; } + + private: + typename Range::Iterator inner; + }; + + inline Iterator begin() const { return Iterator(inner.begin()); } + inline Iterator end() const { return Iterator(inner.end()); } + +private: + Range inner; +}; + +template +inline constexpr Range> zeroTo(BoundedConst end) { + return Range>(end); +} + +template +inline constexpr Range, Unit>> + zeroTo(Quantity, Unit> end) { + return Range, Unit>>(end); +} + +} // namespace kj + +#endif // KJ_UNITS_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/vector.h --- a/osx/include/kj/vector.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/vector.h Mon May 22 10:01:37 2017 +0100 @@ -1,145 +1,144 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_VECTOR_H_ -#define KJ_VECTOR_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#include "array.h" - -namespace kj { - -template -class Vector { - // Similar to std::vector, but based on KJ framework. - // - // This implementation always uses move constructors when growing the backing array. If the - // move constructor throws, the Vector is left in an inconsistent state. This is acceptable - // under KJ exception theory which assumes that exceptions leave things in inconsistent states. - - // TODO(someday): Allow specifying a custom allocator. - -public: - inline Vector() = default; - inline explicit Vector(size_t capacity): builder(heapArrayBuilder(capacity)) {} - - inline operator ArrayPtr() { return builder; } - inline operator ArrayPtr() const { return builder; } - inline ArrayPtr asPtr() { return builder.asPtr(); } - inline ArrayPtr asPtr() const { return builder.asPtr(); } - - inline size_t size() const { return builder.size(); } - inline bool empty() const { return size() == 0; } - inline size_t capacity() const { return builder.capacity(); } - inline T& operator[](size_t index) const { return builder[index]; } - - inline const T* begin() const { return builder.begin(); } - inline const T* end() const { return builder.end(); } - inline const T& front() const { return builder.front(); } - inline const T& back() const { return builder.back(); } - inline T* begin() { return builder.begin(); } - inline T* end() { return builder.end(); } - inline T& front() { return builder.front(); } - inline T& back() { return builder.back(); } - - inline Array releaseAsArray() { - // TODO(perf): Avoid a copy/move by allowing Array to point to incomplete space? - if (!builder.isFull()) { - setCapacity(size()); - } - return builder.finish(); - } - - template - inline T& add(Params&&... params) { - if (builder.isFull()) grow(); - return builder.add(kj::fwd(params)...); - } - - template - inline void addAll(Iterator begin, Iterator end) { - size_t needed = builder.size() + (end - begin); - if (needed > builder.capacity()) grow(needed); - builder.addAll(begin, end); - } - - template - inline void addAll(Container&& container) { - addAll(container.begin(), container.end()); - } - - inline void removeLast() { - builder.removeLast(); - } - - inline void resize(size_t size) { - if (size > builder.capacity()) grow(size); - while (builder.size() < size) { - builder.add(T()); - } - while (builder.size() > size) { - builder.removeLast(); - } - } - - inline void operator=(decltype(nullptr)) { - builder = nullptr; - } - - inline void clear() { - while (builder.size() > 0) { - builder.removeLast(); - } - } - - inline void truncate(size_t size) { - while (builder.size() > size) { - builder.removeLast(); - } - } - -private: - ArrayBuilder builder; - - void grow(size_t minCapacity = 0) { - setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2)); - } - void setCapacity(size_t newSize) { - ArrayBuilder newBuilder = heapArrayBuilder(newSize); - size_t moveCount = kj::min(newSize, builder.size()); - for (size_t i = 0; i < moveCount; i++) { - newBuilder.add(kj::mv(builder[i])); - } - builder = kj::mv(newBuilder); - } -}; - -template -inline auto KJ_STRINGIFY(const Vector& v) -> decltype(toCharSequence(v.asPtr())) { - return toCharSequence(v.asPtr()); -} - -} // namespace kj - -#endif // KJ_VECTOR_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_VECTOR_H_ +#define KJ_VECTOR_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "array.h" + +namespace kj { + +template +class Vector { + // Similar to std::vector, but based on KJ framework. + // + // This implementation always uses move constructors when growing the backing array. If the + // move constructor throws, the Vector is left in an inconsistent state. This is acceptable + // under KJ exception theory which assumes that exceptions leave things in inconsistent states. + + // TODO(someday): Allow specifying a custom allocator. + +public: + inline Vector() = default; + inline explicit Vector(size_t capacity): builder(heapArrayBuilder(capacity)) {} + + inline operator ArrayPtr() { return builder; } + inline operator ArrayPtr() const { return builder; } + inline ArrayPtr asPtr() { return builder.asPtr(); } + inline ArrayPtr asPtr() const { return builder.asPtr(); } + + inline size_t size() const { return builder.size(); } + inline bool empty() const { return size() == 0; } + inline size_t capacity() const { return builder.capacity(); } + inline T& operator[](size_t index) const { return builder[index]; } + + inline const T* begin() const { return builder.begin(); } + inline const T* end() const { return builder.end(); } + inline const T& front() const { return builder.front(); } + inline const T& back() const { return builder.back(); } + inline T* begin() { return builder.begin(); } + inline T* end() { return builder.end(); } + inline T& front() { return builder.front(); } + inline T& back() { return builder.back(); } + + inline Array releaseAsArray() { + // TODO(perf): Avoid a copy/move by allowing Array to point to incomplete space? + if (!builder.isFull()) { + setCapacity(size()); + } + return builder.finish(); + } + + template + inline T& add(Params&&... params) { + if (builder.isFull()) grow(); + return builder.add(kj::fwd(params)...); + } + + template + inline void addAll(Iterator begin, Iterator end) { + size_t needed = builder.size() + (end - begin); + if (needed > builder.capacity()) grow(needed); + builder.addAll(begin, end); + } + + template + inline void addAll(Container&& container) { + addAll(container.begin(), container.end()); + } + + inline void removeLast() { + builder.removeLast(); + } + + inline void resize(size_t size) { + if (size > builder.capacity()) grow(size); + builder.resize(size); + } + + inline void operator=(decltype(nullptr)) { + builder = nullptr; + } + + inline void clear() { + while (builder.size() > 0) { + builder.removeLast(); + } + } + + inline void truncate(size_t size) { + builder.truncate(size); + } + + inline void reserve(size_t size) { + if (size > builder.capacity()) { + setCapacity(size); + } + } + +private: + ArrayBuilder builder; + + void grow(size_t minCapacity = 0) { + setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2)); + } + void setCapacity(size_t newSize) { + if (builder.size() > newSize) { + builder.truncate(newSize); + } + ArrayBuilder newBuilder = heapArrayBuilder(newSize); + newBuilder.addAll(kj::mv(builder)); + builder = kj::mv(newBuilder); + } +}; + +template +inline auto KJ_STRINGIFY(const Vector& v) -> decltype(toCharSequence(v.asPtr())) { + return toCharSequence(v.asPtr()); +} + +} // namespace kj + +#endif // KJ_VECTOR_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/include/kj/windows-sanity.h --- a/osx/include/kj/windows-sanity.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/kj/windows-sanity.h Mon May 22 10:01:37 2017 +0100 @@ -1,41 +1,41 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef KJ_WINDOWS_SANITY_H_ -#define KJ_WINDOWS_SANITY_H_ - -#if defined(__GNUC__) && !KJ_HEADER_WARNINGS -#pragma GCC system_header -#endif - -#ifndef _INC_WINDOWS -#error "windows.h needs to be included before kj/windows-sanity.h (or perhaps you don't need either?)" -#endif - -namespace win32 { - const auto ERROR_ = ERROR; -#undef ERROR - const auto ERROR = ERROR_; -} - -using win32::ERROR; - -#endif // KJ_WINDOWS_SANITY_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_WINDOWS_SANITY_H_ +#define KJ_WINDOWS_SANITY_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#ifndef _INC_WINDOWS +#error "windows.h needs to be included before kj/windows-sanity.h (or perhaps you don't need either?)" +#endif + +namespace win32 { + const auto ERROR_ = ERROR; +#undef ERROR + const auto ERROR = ERROR_; +} + +using win32::ERROR; + +#endif // KJ_WINDOWS_SANITY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 osx/lib/libcapnp.a Binary file osx/lib/libcapnp.a has changed diff -r 206f0eb279b8 -r 45360b968bf4 osx/lib/libkj.a Binary file osx/lib/libkj.a has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/.gitignore Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,74 @@ +# Kenton's personal backup script. +/backup.sh + +# Eclipse-generated stuff. +.cproject +.project +.pydevproject +.settings +.dist-buildwrapper +/c++/gen/ + +# Code you may want to map in from elsewhere. +/c++/src/base +/c++/src/capnp/compilerbin +/c++/src/ekam +/c++/src/os +/c++/src/protobuf +/c++/src/snappy +/c++/src/samples + +# Ekam build artifacts. +/c++/tmp/ +/c++/bin/ + +# setup-ekam.sh +/c++/.ekam + +# super-test.sh +/tmp-staging + +# Jekyll-generated site +/doc/_site + +# Checkout of gh-pages made by /doc/push-site.sh +/doc/.gh-pages + +# cabal-install artifacts +/compiler/dist/ + +# Make artefacts +/c++/.libs/ +/c++/Makefile +/c++/Makefile.in +/c++/**/*.o +/c++/**/*.lo +/c++/**/.deps/ +/c++/**/.dirstamp +/c++/stamp-h1 +/c++/**/*.log +/c++/test_capnpc_middleman +/c++/**/test*.capnp.* +/c++/*.la +/c++/**/*.trs +/c++/aclocal.m4 +/c++/autom4te.cache/ +/c++/build-aux/ +/c++/capnp +/c++/capnp-evolution-test +/c++/*.pc +/c++/capnp-test +/c++/capnpc-c++ +/c++/capnpc-capnp +/c++/config.* +/c++/configure +/c++/libtool +/c++/m4/libtool.m4 +/c++/m4/ltoptions.m4 +/c++/m4/ltsugar.m4 +/c++/m4/ltversion.m4 +/c++/m4/lt~obsolete.m4 +/c++/samples/addressbook + +# editor artefacts +*~ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/.travis.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/.travis.yml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,24 @@ +branches: + only: + - master + - /release-.*/ +language: cpp +os: + - linux + - osx +compiler: + - gcc + - clang +dist: trusty +sudo: false +addons: + apt: + packages: + - automake + - autoconf + - libtool + - pkg-config +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install automake autoconf libtool; fi +script: ./super-test.sh -j2 quick # limit parallelism due to limited memory on Travis diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/CONTRIBUTORS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/CONTRIBUTORS Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,22 @@ +The following people have made large code contributions to this repository. +Those contributions are copyright the respective authors and licensed by them +under the same MIT license terms as the rest of the library. + +Kenton Varda : Primary Author +Jason Choy : kj/threadlocal.h and other iOS tweaks, `name` annotation in C++ code generator +Remy Blank (contributions copyright Google Inc.): KJ Timers +Joshua Warner : cmake build, AnyStruct/AnyList, other stuff +Scott Purdy : kj/std iostream interface +Bryan Borham : Initial MSVC support +Philip Quinn : cmake build and other assorted bits +Brian Taylor : emacs syntax highlighting +Ben Laurie : discovered and responsibly disclosed security bugs +Kamal Marhubi : JSON parser +Oliver Kuckertz : FdObserver POLLPRI support +Harris Hancock : MSVC support +Branislav Katreniak : JSON decode +Matthew Maurer : Canonicalization Support +David Renshaw : bugfixes and miscellaneous maintenance + +This file does not list people who maintain their own Cap'n Proto +implementations as separate projects. Those people are awesome too! :) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/LICENSE Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,21 @@ +Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +Licensed under the MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/README.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,7 @@ + + +Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think +JSON, except binary. Or think [Protocol Buffers](http://protobuf.googlecode.com), except faster. +In fact, in benchmarks, Cap'n Proto is INFINITY TIMES faster than Protocol Buffers. + +[Read more...](http://kentonv.github.com/capnproto/) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/RELEASE-PROCESS.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/RELEASE-PROCESS.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,67 @@ +How to release +============== + +**Developing** + +* First, develop some new features to release! As you do, make sure to keep the documentation + up-to-date. + +**Testing** + +* Run `super-test.sh` on as many platforms as you have available. Remember that you can easily run + on any machine available through ssh using `./super-test.sh remote [hostname]`. Also run in + Clang mode. (If you are Kenton and running from Kenton's home machine and network, use + `./mega-test.py mega-test.cfg` to run on all supported compilers and platforms.) + +* Manually test Windows/MSVC -- unfortunately this can't be automated by super-test.sh. + +* Manually run the pointer fuzz tests under Valgrind. This will take 40-80 minutes. + + valgrind ./capnp-test -fcapnp/fuzz-test.c++ + +* Manually run the AFL fuzz tests by running `afl-fuzz.sh`. There are three test cases, and ideally each should run for 24 hours or more. + +**Documenting** + +* Write a blog post discussing what is new, placing it in doc/_posts. + +* Run jekyll locally and review the blog post and docs. + +**Releasing** + +* Check out the master branch in a fresh directory. Do NOT use your regular repo, as the release + script commits changes and if anything goes wrong you'll probably want to trash the whole thing + without pushing. DO NOT git clone the repo from an existing local repo -- check it out directly + from github. Otherwise, when it pushes its changes back, they'll only be pushed back to your + local repo. + +* Run `./release.sh candidate`. This creates a new release branch, updates the version number to + `-rc1`, builds release tarballs, copies them to the current directory, then switches back to the + master branch and bumps the version number there. After asking for final confirmation, it will + upload the tarball to S3 and push all changes back to github. + +* Install your release candidates on your local machine, as if you were a user. + +* Go to `c++/samples` in the git repo and run `./test.sh`. It will try to build against your + installed copy. + +* Post the release candidates somewhere public and then send links to the mailing list for people + to test. Wait a bit for bug reports. + +* If there are any problems, fix them in master and start a new release candidate by running + `./release.sh candidate ...` from the release branch. This will cherry-pick the specified + commits into the release branch and create a new candidate. Repeat until all problems are fixed. + Be sure that any such fixes include tests or process changes so that they don't happen again. + +* You should now be ready for an official release. Run `./release.sh final`. This will remove the + "-rcN" suffix from the version number, update the version number shown on the downloads page, + build the final release package, and -- after final confirmation -- upload the binary, push + changes to git, and publish the new documentation. + +* Submit the newly-published blog post to news sites and social media as you see fit. + +* If problems are discovered in the release, fix them in master and run + `./release.sh candidate ...` in the release branch to start a new micro release. The + script automatically sees that the current branch's version no longer contains `-rc`, so it starts + a new branch. Repeat the rest of the process above. If you decide to write a blog post (not + always necessary), do it in the master branch and cherry-pick it. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/appveyor.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/appveyor.yml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,87 @@ +# Cap'n Proto AppVeyor configuration +# +# See https://www.appveyor.com/docs/appveyor-yml/ for configuration options. +# +# This script configures AppVeyor to: +# - Download and unzip MinGW-w64 4.8.5 for x86_64, the minimum gcc version Cap'n Proto advertises +# support for. +# - Use CMake to ... +# build Cap'n Proto with MinGW. +# build Cap'n Proto with VS2015 and VS2017. +# build Cap'n Proto samples with VS2015 and VS2017. + +version: "{build}" + +branches: + only: + - master + - /release-.*/ +# Don't build non-master branches (unless they open a pull request). + +image: Visual Studio 2017 +# AppVeyor build worker image (VM template). + +shallow_clone: true +# Fetch repository as zip archive. + +cache: + - x86_64-4.8.5-release-win32-seh-rt_v4-rev0.7z + +environment: + MINGW_DIR: mingw64 + MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.8.5/threads-win32/seh/x86_64-4.8.5-release-win32-seh-rt_v4-rev0.7z/download + MINGW_ARCHIVE: x86_64-4.8.5-release-win32-seh-rt_v4-rev0.7z + BUILD_TYPE: debug + + matrix: + # TODO(someday): Add MSVC x64 builds, MinGW x86 build? + + - CMAKE_GENERATOR: Visual Studio 15 2017 + BUILD_NAME: vs2017 + EXTRA_BUILD_FLAGS: # /maxcpucount + # TODO(someday): Right now /maxcpucount occasionally expresses a filesystem-related race: + # capnp-capnpc++ complains that it can't create test.capnp.h. + + - CMAKE_GENERATOR: Visual Studio 14 2015 + BUILD_NAME: vs2015 + EXTRA_BUILD_FLAGS: # /maxcpucount + + - CMAKE_GENERATOR: MinGW Makefiles + BUILD_NAME: mingw + EXTRA_BUILD_FLAGS: -j2 + +install: + - if not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" + - 7z x -y "%MINGW_ARCHIVE%" > nul + - ps: Get-Command sh.exe -All | Remove-Item + # CMake refuses to generate MinGW Makefiles if sh.exe is in the PATH + +before_build: + - set PATH=%CD%\%MINGW_DIR%\bin;%PATH% + - set BUILD_DIR=build-%BUILD_NAME% + - set INSTALL_PREFIX=%CD%\capnproto-c++-%BUILD_NAME% + - cmake --version + +build_script: + - echo "Building Cap'n Proto with %CMAKE_GENERATOR%" + - >- + cmake -Hc++ -B%BUILD_DIR% -G "%CMAKE_GENERATOR%" + -DCMAKE_BUILD_TYPE=%BUILD_TYPE% + -DCMAKE_INSTALL_PREFIX=%INSTALL_PREFIX% + - cmake --build %BUILD_DIR% --config %BUILD_TYPE% --target install -- %EXTRA_BUILD_FLAGS% + # MinGW wants the build type at configure-time while MSVC wants the build type at build-time. We + # can satisfy both by passing the build type to both cmake invocations. We have to suffer a + # warning, but both generators will work. + + - echo "Building Cap'n Proto samples with %CMAKE_GENERATOR%" + - >- + cmake -Hc++/samples -B%BUILD_DIR%-samples -G "%CMAKE_GENERATOR%" + -DCMAKE_BUILD_TYPE=%BUILD_TYPE% + -DCMAKE_PREFIX_PATH=%INSTALL_PREFIX% + - cmake --build %BUILD_DIR%-samples --config %BUILD_TYPE% + +test_script: + - timeout /t 2 + # Sleep a little to prevent interleaving test output with build output. + - cd %BUILD_DIR%\src + - ctest -V -C %BUILD_TYPE% diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/CMakeLists.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,146 @@ +project("Cap'n Proto" CXX) +cmake_minimum_required(VERSION 3.1) +set(VERSION 0.6.0) + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include(CheckIncludeFileCXX) +include(GNUInstallDirs) +if(MSVC) + check_include_file_cxx(initializer_list HAS_CXX11) +else() + check_include_file_cxx(initializer_list HAS_CXX11 "-std=gnu++0x") +endif() +if(NOT HAS_CXX11) + message(SEND_ERROR "Requires a C++11 compiler and standard library.") +endif() + +# these arguments are passed to all install(TARGETS) calls +set(INSTALL_TARGETS_DEFAULT_ARGS + EXPORT CapnProtoTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" +) + +# Options ====================================================================== + +option(BUILD_TESTING "Build unit tests and enable CTest 'check' target." ON) +option(EXTERNAL_CAPNP "Use the system capnp binary, or the one specified in $CAPNP, instead of using the compiled one." OFF) +option(CAPNP_LITE "Compile Cap'n Proto in 'lite mode', in which all reflection APIs (schema.h, dynamic.h, etc.) are not included. Produces a smaller library at the cost of features. All programs built against the library must be compiled with -DCAPNP_LITE. Requires EXTERNAL_CAPNP." OFF) + +# Check for invalid combinations of build options +if(CAPNP_LITE AND BUILD_TESTING AND NOT EXTERNAL_CAPNP) + message(SEND_ERROR "You must set EXTERNAL_CAPNP when using CAPNP_LITE and BUILD_TESTING.") +endif() + +if(CAPNP_LITE) + set(CAPNP_LITE_FLAG "-DCAPNP_LITE") + # This flag is attached as PUBLIC target_compile_definition to kj target +else() + set(CAPNP_LITE_FLAG) +endif() + +if(MSVC) + # TODO(cleanup): Enable higher warning level in MSVC, but make sure to test + # build with that warning level and clean out false positives. + + add_compile_options(/wo4503) + # Only warn once on truncated decorated names. The maximum symbol length MSVC + # supports is 4k characters, which the parser framework regularly blows. The + # compiler likes to print out the entire type that went over the limit along + # with this warning, which gets unbearably spammy. That said, we don't want to + # just ignore it, so I'm letting it trigger once until we find some places to + # inject ParserRefs. +else() + # Note that it's important to add new CXXFLAGS before ones specified by the + # user, so that the user's flags override them. This is particularly + # important if -Werror was enabled and then certain warnings need to be + # disabled, as is done in super-test.sh. + # + # We enable a lot of warnings, but then disable some: + # * strict-aliasing: We use type-punning in known-safe ways that GCC doesn't + # recognize as safe. + # * sign-compare: Low S/N ratio. + # * unused-parameter: Low S/N ratio. + add_compile_options(-Wall -Wextra -Wno-strict-aliasing -Wno-sign-compare -Wno-unused-parameter) + + if(DEFINED CMAKE_CXX_EXTENSIONS AND NOT CMAKE_CXX_EXTENSIONS) + message(SEND_ERROR "Cap'n Proto requires compiler-specific extensions (e.g., -std=gnu++11). Please leave CMAKE_CXX_EXTENSIONS undefined or ON.") + endif() + + if (NOT ANDROID) + add_compile_options(-pthread) + endif() +endif() + +# Source ======================================================================= +include(CapnProtoMacros) +add_subdirectory(src) + +# Install ====================================================================== + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/CapnProtoConfigVersion.cmake" + VERSION ${VERSION} + COMPATIBILITY AnyNewerVersion +) +set(CONFIG_PACKAGE_LOCATION ${CMAKE_INSTALL_LIBDIR}/cmake/CapnProto) + +configure_package_config_file(cmake/CapnProtoConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CapnProtoConfig.cmake + INSTALL_DESTINATION ${CONFIG_PACKAGE_LOCATION} + PATH_VARS CMAKE_INSTALL_FULL_INCLUDEDIR +) +export(EXPORT CapnProtoTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/CapnProtoTargets.cmake" + NAMESPACE CapnProto:: +) +install(EXPORT CapnProtoTargets + FILE CapnProtoTargets.cmake + NAMESPACE CapnProto:: + DESTINATION ${CONFIG_PACKAGE_LOCATION} +) +install(FILES + cmake/CapnProtoMacros.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CapnProtoConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CapnProtoConfigVersion.cmake + DESTINATION ${CONFIG_PACKAGE_LOCATION} +) +#install CapnProtoMacros for CapnProtoConfig.cmake build directory consumers +configure_file(cmake/CapnProtoMacros.cmake cmake/CapnProtoMacros.cmake COPYONLY) + +if(NOT MSVC) # Don't install pkg-config files when building with MSVC + # Variables for pkg-config files + set(prefix "${CMAKE_INSTALL_PREFIX}") + set(exec_prefix "") # not needed since we use absolute paths in libdir and includedir + set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") + set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + set(PTHREAD_CFLAGS "-pthread") + set(STDLIB_FLAG) # TODO: Unsupported + + configure_file(kj.pc.in "${CMAKE_CURRENT_BINARY_DIR}/kj.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kj.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + + configure_file(capnp.pc.in "${CMAKE_CURRENT_BINARY_DIR}/capnp.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/capnp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + + if(NOT CAPNP_LITE) + configure_file(kj-async.pc.in "${CMAKE_CURRENT_BINARY_DIR}/kj-async.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kj-async.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + + configure_file(capnp-rpc.pc.in "${CMAKE_CURRENT_BINARY_DIR}/capnp-rpc.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/capnp-rpc.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + + configure_file(capnp-json.pc.in "${CMAKE_CURRENT_BINARY_DIR}/capnp-json.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/capnp-json.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() + + unset(STDLIB_FLAG) + unset(PTHREAD_CFLAGS) + unset(includedir) + unset(libdir) + unset(exec_prefix) + unset(prefix) +endif() diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/LICENSE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/LICENSE.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1 @@ +../LICENSE \ No newline at end of file diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/Makefile.am Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,493 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS = -I m4 + +AUTOMAKE_OPTIONS = foreign subdir-objects + +# When running distcheck, verify that we've included all the files needed by +# the cmake build. +distcheck-hook: + rm -rf distcheck-cmake + (mkdir distcheck-cmake && cd distcheck-cmake && cmake ../$(distdir) && make -j6 check) + rm -rf distcheck-cmake + +AM_CXXFLAGS = -I$(srcdir)/src -I$(builddir)/src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR='"$(includedir)"' $(PTHREAD_CFLAGS) + +AM_LDFLAGS = $(PTHREAD_CFLAGS) + +EXTRA_DIST = \ + README.txt \ + LICENSE.txt \ + $(test_capnpc_inputs) \ + src/capnp/compiler/capnp-test.sh \ + src/capnp/testdata/segmented-packed \ + src/capnp/testdata/errors.capnp.nobuild \ + src/capnp/testdata/short.txt \ + src/capnp/testdata/flat \ + src/capnp/testdata/binary \ + src/capnp/testdata/errors.txt \ + src/capnp/testdata/segmented \ + src/capnp/testdata/packed \ + src/capnp/testdata/pretty.txt \ + src/capnp/testdata/lists.binary \ + src/capnp/testdata/packedflat \ + CMakeLists.txt \ + cmake/FindCapnProto.cmake \ + cmake/CapnProtoConfig.cmake.in \ + cmake/CapnProtoMacros.cmake \ + src/CMakeLists.txt \ + src/kj/CMakeLists.txt \ + src/capnp/CMakeLists.txt + +CLEANFILES = $(test_capnpc_outputs) test_capnpc_middleman distcheck-cmake + +# Deletes all the files generated by autoreconf. +MAINTAINERCLEANFILES = \ + aclocal.m4 \ + config.guess \ + config.sub \ + configure \ + depcomp \ + install-sh \ + ltmain.sh \ + Makefile.in \ + missing \ + mkinstalldirs \ + config.h.in \ + stamp.h.in \ + m4/ltsugar.m4 \ + m4/libtool.m4 \ + m4/ltversion.m4 \ + m4/lt~obsolete.m4 \ + m4/ltoptions.m4 + +maintainer-clean-local: + -rm -rf build-aux + +# gmake defines an implicit rule building n from n.o. Unfortunately, this triggers on our .capnp +# files because they generate .capnp.c++ which is compiled to .capnp.o. In addition to being +# nonsense, this leads to cyclic dependency issues and could even cause the .capnp files to be +# unexpectedly overwritten! We need to cancel the implicit rule by declaring an explicit one. +# +# I want the hours of my life back that I spent figuring this out. +%.capnp: + @: + +public_capnpc_inputs = \ + src/capnp/c++.capnp \ + src/capnp/schema.capnp \ + src/capnp/rpc.capnp \ + src/capnp/rpc-twoparty.capnp \ + src/capnp/persistent.capnp \ + src/capnp/compat/json.capnp + +capnpc_inputs = \ + $(public_capnpc_inputs) \ + src/capnp/compiler/lexer.capnp \ + src/capnp/compiler/grammar.capnp + +capnpc_outputs = \ + src/capnp/c++.capnp.c++ \ + src/capnp/c++.capnp.h \ + src/capnp/schema.capnp.c++ \ + src/capnp/schema.capnp.h \ + src/capnp/rpc.capnp.c++ \ + src/capnp/rpc.capnp.h \ + src/capnp/rpc-twoparty.capnp.c++ \ + src/capnp/rpc-twoparty.capnp.h \ + src/capnp/persistent.capnp.c++ \ + src/capnp/persistent.capnp.h \ + src/capnp/compat/json.capnp.h \ + src/capnp/compat/json.capnp.c++ \ + src/capnp/compiler/lexer.capnp.c++ \ + src/capnp/compiler/lexer.capnp.h \ + src/capnp/compiler/grammar.capnp.c++ \ + src/capnp/compiler/grammar.capnp.h + +includecapnpdir = $(includedir)/capnp +includecapnpcompatdir = $(includecapnpdir)/compat +includekjdir = $(includedir)/kj +includekjparsedir = $(includekjdir)/parse +includekjstddir = $(includekjdir)/std +includekjcompatdir = $(includekjdir)/compat + +dist_includecapnp_DATA = $(public_capnpc_inputs) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = capnp.pc capnp-rpc.pc kj.pc kj-async.pc + +noinst_HEADERS = \ + src/kj/miniposix.h + +includekj_HEADERS = \ + src/kj/common.h \ + src/kj/units.h \ + src/kj/memory.h \ + src/kj/refcount.h \ + src/kj/array.h \ + src/kj/vector.h \ + src/kj/string.h \ + src/kj/string-tree.h \ + src/kj/exception.h \ + src/kj/debug.h \ + src/kj/arena.h \ + src/kj/io.h \ + src/kj/tuple.h \ + src/kj/one-of.h \ + src/kj/function.h \ + src/kj/mutex.h \ + src/kj/thread.h \ + src/kj/threadlocal.h \ + src/kj/async-prelude.h \ + src/kj/async.h \ + src/kj/async-inl.h \ + src/kj/time.h \ + src/kj/async-unix.h \ + src/kj/async-win32.h \ + src/kj/async-io.h \ + src/kj/main.h \ + src/kj/test.h \ + src/kj/windows-sanity.h + +includekjparse_HEADERS = \ + src/kj/parse/common.h \ + src/kj/parse/char.h + +includekjstd_HEADERS = \ + src/kj/std/iostream.h + +includekjcompat_HEADERS = \ + src/kj/compat/gtest.h \ + src/kj/compat/http.h + +includecapnp_HEADERS = \ + src/capnp/c++.capnp.h \ + src/capnp/common.h \ + src/capnp/blob.h \ + src/capnp/endian.h \ + src/capnp/layout.h \ + src/capnp/orphan.h \ + src/capnp/list.h \ + src/capnp/any.h \ + src/capnp/message.h \ + src/capnp/capability.h \ + src/capnp/membrane.h \ + src/capnp/schema.capnp.h \ + src/capnp/schema-lite.h \ + src/capnp/schema.h \ + src/capnp/schema-loader.h \ + src/capnp/schema-parser.h \ + src/capnp/dynamic.h \ + src/capnp/pretty-print.h \ + src/capnp/serialize.h \ + src/capnp/serialize-async.h \ + src/capnp/serialize-packed.h \ + src/capnp/serialize-text.h \ + src/capnp/pointer-helpers.h \ + src/capnp/generated-header-support.h \ + src/capnp/raw-schema.h \ + src/capnp/rpc-prelude.h \ + src/capnp/rpc.h \ + src/capnp/rpc-twoparty.h \ + src/capnp/rpc.capnp.h \ + src/capnp/rpc-twoparty.capnp.h \ + src/capnp/persistent.capnp.h \ + src/capnp/ez-rpc.h + +includecapnpcompat_HEADERS = \ + src/capnp/compat/json.h \ + src/capnp/compat/json.capnp.h + +if LITE_MODE +lib_LTLIBRARIES = libkj.la libkj-test.la libcapnp.la +else +lib_LTLIBRARIES = libkj.la libkj-test.la libkj-async.la libkj-http.la libcapnp.la libcapnp-rpc.la libcapnp-json.la libcapnpc.la +endif + +# Don't include security release in soname -- we want to replace old binaries +# in this case. +SO_VERSION = $(shell echo $(VERSION) | sed -e 's/^\([0-9]*[.][0-9]*[.][0-9]*\)\([.][0-9]*\)*\(-.*\)*$$/\1\3/g') + +libkj_la_LIBADD = $(PTHREAD_LIBS) +libkj_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libkj_la_SOURCES= \ + src/kj/common.c++ \ + src/kj/units.c++ \ + src/kj/memory.c++ \ + src/kj/refcount.c++ \ + src/kj/array.c++ \ + src/kj/string.c++ \ + src/kj/string-tree.c++ \ + src/kj/exception.c++ \ + src/kj/debug.c++ \ + src/kj/arena.c++ \ + src/kj/io.c++ \ + src/kj/mutex.c++ \ + src/kj/thread.c++ \ + src/kj/test-helpers.c++ \ + src/kj/main.c++ \ + src/kj/parse/char.c++ + +libkj_test_la_LIBADD = libkj.la $(PTHREAD_LIBS) +libkj_test_la_LDFLAGS = -release $(VERSION) -no-undefined +libkj_test_la_SOURCES = src/kj/test.c++ + +if !LITE_MODE +libkj_async_la_LIBADD = libkj.la $(ASYNC_LIBS) $(PTHREAD_LIBS) +libkj_async_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libkj_async_la_SOURCES= \ + src/kj/async.c++ \ + src/kj/async-unix.c++ \ + src/kj/async-win32.c++ \ + src/kj/async-io.c++ \ + src/kj/async-io-unix.c++ \ + src/kj/async-io-win32.c++ \ + src/kj/time.c++ + +libkj_http_la_LIBADD = libkj-async.la libkj.la $(ASYNC_LIBS) $(PTHREAD_LIBS) +libkj_http_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libkj_http_la_SOURCES= \ + src/kj/compat/http.c++ +endif !LITE_MODE + +if !LITE_MODE +heavy_sources = \ + src/capnp/schema.c++ \ + src/capnp/schema-loader.c++ \ + src/capnp/dynamic.c++ \ + src/capnp/stringify.c++ +endif !LITE_MODE + +libcapnp_la_LIBADD = libkj.la $(PTHREAD_LIBS) +libcapnp_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libcapnp_la_SOURCES= \ + src/capnp/c++.capnp.c++ \ + src/capnp/blob.c++ \ + src/capnp/arena.h \ + src/capnp/arena.c++ \ + src/capnp/layout.c++ \ + src/capnp/list.c++ \ + src/capnp/any.c++ \ + src/capnp/message.c++ \ + src/capnp/schema.capnp.c++ \ + src/capnp/serialize.c++ \ + src/capnp/serialize-packed.c++ \ + $(heavy_sources) + +if !LITE_MODE + +libcapnp_rpc_la_LIBADD = libcapnp.la libkj-async.la libkj.la $(ASYNC_LIBS) $(PTHREAD_LIBS) +libcapnp_rpc_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libcapnp_rpc_la_SOURCES= \ + src/capnp/serialize-async.c++ \ + src/capnp/capability.c++ \ + src/capnp/membrane.c++ \ + src/capnp/dynamic-capability.c++ \ + src/capnp/rpc.c++ \ + src/capnp/rpc.capnp.c++ \ + src/capnp/rpc-twoparty.c++ \ + src/capnp/rpc-twoparty.capnp.c++ \ + src/capnp/persistent.capnp.c++ \ + src/capnp/ez-rpc.c++ + +libcapnp_json_la_LIBADD = libcapnp.la libkj.la $(PTHREAD_LIBS) +libcapnp_json_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libcapnp_json_la_SOURCES= \ + src/capnp/compat/json.c++ \ + src/capnp/compat/json.capnp.c++ + +libcapnpc_la_LIBADD = libcapnp.la libkj.la $(PTHREAD_LIBS) +libcapnpc_la_LDFLAGS = -release $(SO_VERSION) -no-undefined +libcapnpc_la_SOURCES= \ + src/capnp/compiler/md5.h \ + src/capnp/compiler/md5.c++ \ + src/capnp/compiler/error-reporter.h \ + src/capnp/compiler/error-reporter.c++ \ + src/capnp/compiler/lexer.capnp.h \ + src/capnp/compiler/lexer.capnp.c++ \ + src/capnp/compiler/lexer.h \ + src/capnp/compiler/lexer.c++ \ + src/capnp/compiler/grammar.capnp.h \ + src/capnp/compiler/grammar.capnp.c++ \ + src/capnp/compiler/parser.h \ + src/capnp/compiler/parser.c++ \ + src/capnp/compiler/node-translator.h \ + src/capnp/compiler/node-translator.c++ \ + src/capnp/compiler/compiler.h \ + src/capnp/compiler/compiler.c++ \ + src/capnp/schema-parser.c++ \ + src/capnp/serialize-text.c++ + +bin_PROGRAMS = capnp capnpc-capnp capnpc-c++ + +capnp_LDADD = libcapnpc.la libcapnp.la libkj.la $(PTHREAD_LIBS) +capnp_SOURCES = \ + src/capnp/compiler/module-loader.h \ + src/capnp/compiler/module-loader.c++ \ + src/capnp/compiler/capnp.c++ + +capnpc_capnp_LDADD = libcapnp.la libkj.la $(PTHREAD_LIBS) +capnpc_capnp_SOURCES = src/capnp/compiler/capnpc-capnp.c++ + +capnpc_c___LDADD = libcapnp.la libkj.la $(PTHREAD_LIBS) +capnpc_c___SOURCES = src/capnp/compiler/capnpc-c++.c++ + +# Symlink capnpc -> capnp. The capnp binary will behave like the old capnpc +# binary (i.e. like "capnp compile") when invoked via this symlink. +# +# Also attempt to run ldconfig, because otherwise users get confused. If +# it fails (e.g. because the platform doesn't have it, or because the +# user doesn't have root privileges), don't worry about it. +install-exec-hook: + ln -sf capnp $(DESTDIR)$(bindir)/capnpc + ldconfig < /dev/null > /dev/null 2>&1 || true + +uninstall-hook: + rm -f $(DESTDIR)$(bindir)/capnpc + +else LITE_MODE + +install-exec-hook: + ldconfig < /dev/null > /dev/null 2>&1 || true + +endif LITE_MODE + +# Source files intentionally not included in the dist at this time: +# src/capnp/serialize-snappy* +# src/capnp/benchmark/... +# src/capnp/compiler/... + +# Tests ============================================================== + +test_capnpc_inputs = \ + src/capnp/test.capnp \ + src/capnp/test-import.capnp \ + src/capnp/test-import2.capnp + +test_capnpc_outputs = \ + src/capnp/test.capnp.c++ \ + src/capnp/test.capnp.h \ + src/capnp/test-import.capnp.c++ \ + src/capnp/test-import.capnp.h \ + src/capnp/test-import2.capnp.c++ \ + src/capnp/test-import2.capnp.h + +if USE_EXTERNAL_CAPNP + +test_capnpc_middleman: $(test_capnpc_inputs) + $(CAPNP) compile --src-prefix=$(srcdir)/src -o$(CAPNPC_CXX):src -I$(srcdir)/src $^ + touch test_capnpc_middleman + +else + +test_capnpc_middleman: capnp$(EXEEXT) capnpc-c++$(EXEEXT) $(test_capnpc_inputs) + echo $^ | (read CAPNP CAPNPC_CXX SOURCES && ./$$CAPNP compile --src-prefix=$(srcdir)/src -o./$$CAPNPC_CXX:src -I$(srcdir)/src $$SOURCES) + touch test_capnpc_middleman + +endif + +$(test_capnpc_outputs): test_capnpc_middleman + +BUILT_SOURCES = $(test_capnpc_outputs) + +check_LIBRARIES = libcapnp-test.a +libcapnp_test_a_SOURCES = \ + src/capnp/test-util.c++ \ + src/capnp/test-util.h +nodist_libcapnp_test_a_SOURCES = $(test_capnpc_outputs) + +if LITE_MODE + +check_PROGRAMS = capnp-test +compiler_tests = +capnp_test_LDADD = libcapnp-test.a libcapnp.la libkj-test.la libkj.la + +else !LITE_MODE + +check_PROGRAMS = capnp-test capnp-evolution-test capnp-afl-testcase +heavy_tests = \ + src/kj/async-test.c++ \ + src/kj/async-unix-test.c++ \ + src/kj/async-win32-test.c++ \ + src/kj/async-io-test.c++ \ + src/kj/parse/common-test.c++ \ + src/kj/parse/char-test.c++ \ + src/kj/std/iostream-test.c++ \ + src/kj/compat/http-test.c++ \ + src/capnp/canonicalize-test.c++ \ + src/capnp/capability-test.c++ \ + src/capnp/membrane-test.c++ \ + src/capnp/schema-test.c++ \ + src/capnp/schema-loader-test.c++ \ + src/capnp/schema-parser-test.c++ \ + src/capnp/dynamic-test.c++ \ + src/capnp/stringify-test.c++ \ + src/capnp/serialize-async-test.c++ \ + src/capnp/serialize-text-test.c++ \ + src/capnp/rpc-test.c++ \ + src/capnp/rpc-twoparty-test.c++ \ + src/capnp/ez-rpc-test.c++ \ + src/capnp/compat/json-test.c++ \ + src/capnp/compiler/lexer-test.c++ \ + src/capnp/compiler/md5-test.c++ +capnp_test_LDADD = \ + libcapnp-test.a \ + libcapnpc.la \ + libcapnp-rpc.la \ + libcapnp-json.la \ + libcapnp.la \ + libkj-http.la \ + libkj-async.la \ + libkj-test.la \ + libkj.la + +endif !LITE_MODE + +capnp_test_CPPFLAGS = -Wno-deprecated-declarations +capnp_test_SOURCES = \ + src/kj/common-test.c++ \ + src/kj/memory-test.c++ \ + src/kj/refcount-test.c++ \ + src/kj/array-test.c++ \ + src/kj/string-test.c++ \ + src/kj/string-tree-test.c++ \ + src/kj/exception-test.c++ \ + src/kj/debug-test.c++ \ + src/kj/arena-test.c++ \ + src/kj/units-test.c++ \ + src/kj/tuple-test.c++ \ + src/kj/one-of-test.c++ \ + src/kj/function-test.c++ \ + src/kj/io-test.c++ \ + src/kj/mutex-test.c++ \ + src/kj/threadlocal-test.c++ \ + src/kj/threadlocal-pthread-test.c++ \ + src/kj/test-test.c++ \ + src/capnp/common-test.c++ \ + src/capnp/blob-test.c++ \ + src/capnp/endian-test.c++ \ + src/capnp/endian-fallback-test.c++ \ + src/capnp/endian-reverse-test.c++ \ + src/capnp/layout-test.c++ \ + src/capnp/any-test.c++ \ + src/capnp/message-test.c++ \ + src/capnp/encoding-test.c++ \ + src/capnp/orphan-test.c++ \ + src/capnp/serialize-test.c++ \ + src/capnp/serialize-packed-test.c++ \ + src/capnp/fuzz-test.c++ \ + $(heavy_tests) + +if !LITE_MODE +capnp_evolution_test_LDADD = libcapnpc.la libcapnp.la libkj.la +capnp_evolution_test_SOURCES = src/capnp/compiler/evolution-test.c++ + +capnp_afl_testcase_LDADD = libcapnp-test.a libcapnp-rpc.la libcapnp.la libkj.la libkj-async.la +capnp_afl_testcase_SOURCES = src/capnp/afl-testcase.c++ +endif !LITE_MODE + +if LITE_MODE +TESTS = capnp-test +else !LITE_MODE +TESTS = capnp-test capnp-evolution-test src/capnp/compiler/capnp-test.sh +endif !LITE_MODE diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/Makefile.ekam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/Makefile.ekam Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,34 @@ +.PHONY: all once continuous continuous-opt clean + +EKAM=`which ekam || echo .ekam/bin/ekam` + +ifeq ($(CXX),clang++) + # Clang's verbose diagnostics don't play nice with the Ekam Eclipse plugin's error parsing, + # so disable them. Also enable some useful Clang warnings (dunno if GCC supports them, and don't + # care). + EXTRA_FLAG=-fno-caret-diagnostics -Wglobal-constructors -Wextra-semi -Werror=return-type +# EXTRA_FLAG=-fno-caret-diagnostics -Weverything -Wno-c++98-compat -Wno-shadow -Wno-c++98-compat-pedantic -Wno-padded -Wno-weak-vtables -Wno-gnu -Wno-unused-parameter -Wno-sign-conversion -Wno-undef -Wno-shorten-64-to-32 -Wno-conversion -Wno-unreachable-code -Wno-non-virtual-dtor +else + EXTRA_FLAG= +endif + +all: + echo "You probably accidentally told Eclipse to build. Stopping." + +once: + CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 + +continuous: + CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -g -DCAPNP_DEBUG_TYPES=1 -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 + +continuous-opt: + CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O2 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 + +continuous-opt3: + CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -O3 -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 + +continuous-opts: + CXXFLAGS="$(EXTRA_FLAG) -std=c++11 -Os -DNDEBUG -Wall" LIBS='-lz -pthread' $(EKAM) -j6 -c -n :51315 + +clean: + rm -rf bin lib tmp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/README.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,27 @@ +Cap'n Proto - Insanely Fast Data Serialization Format +Copyright 2013-2015 Sandstorm Development Group, Inc. +https://capnproto.org + +Cap'n Proto is an insanely fast data interchange format and capability-based +RPC system. Think JSON, except binary. Or think of Google's Protocol Buffers +(http://protobuf.googlecode.com), except faster. In fact, in benchmarks, +Cap'n Proto is INFINITY TIMES faster than Protocol Buffers. + +Full installation and usage instructions and other documentation are maintained +on the Cap'n Proto web site: + http://kentonv.github.io/capnproto/install.html + +WARNING: Cap'n Proto requires a modern compiler. See the above link for +detailed requirements. + +To build and install (from a release package), simply do: + ./configure + make -j4 check + sudo make install + +The -j4 allows the build to use up to four processor cores instead of one. +You can increase this number if you have more cores. Specifying "check" +says to run tests in addition to building. This can be omitted to make the +build slightly faster, but running tests and reporting failures back to the +developers helps us out! + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/afl-fuzz.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/afl-fuzz.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,72 @@ +#! /bin/bash + +set -euo pipefail + +echo "Choose test case:" +echo "1) TestAllTypes parsing" +echo "2) TestLists parsing" +echo "3) Canonicalization" + +read -p "choice: " -n 1 TESTCASE +echo + +case "$TESTCASE" in + 1 ) + TESTDATA=binary + FLAGS= + TESTNAME=default + ;; + 2 ) + TESTDATA=lists.binary + FLAGS=--lists + TESTNAME=lists + ;; + 3 ) + TESTDATA=binary + FLAGS=--canonicalize + TESTNAME=canonicalize + ;; + * ) + echo "Invalid choice: $TESTCASE" >&2 + exit 1 +esac + +echo "Choose compiler:" +echo "1) GCC" +echo "2) Clang" + +read -p "choice: " -n 1 TESTCASE +echo + +case "$TESTCASE" in + 1 ) + export CXX=afl-g++ + ;; + 2 ) + export CXX=afl-clang++ + ;; + * ) + echo "Invalid choice: $TESTCASE" >&2 + exit 1 +esac + +if [ -e Makefile ]; then + if ! grep -q '^CXX *= *'"$CXX" Makefile; then + # Wrong compiler used. + make distclean + $(dirname $0)/configure --disable-shared + fi +else + $(dirname $0)/configure --disable-shared +fi + +make -j$(nproc) +make -j$(nproc) capnp-afl-testcase + +NOW=$(date +%Y-%m-%d.%H-%M-%S).$TESTNAME.$CXX + +mkdir afl.$NOW.inputs afl.$NOW.findings + +cp $(dirname $0)/src/capnp/testdata/$TESTDATA afl.$NOW.inputs + +afl-fuzz -i afl.$NOW.inputs -o afl.$NOW.findings -- ./capnp-afl-testcase $FLAGS diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/capnp-json.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/capnp-json.pc.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Cap'n Proto JSON +Description: JSON encoder and decoder for Cap'n Proto objects +Version: @VERSION@ +Libs: -L${libdir} -lcapnp-json +Requires: capnp = @VERSION@ kj = @VERSION@ +Cflags: -I${includedir} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/capnp-rpc.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/capnp-rpc.pc.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Cap'n Proto RPC +Description: Fast object-oriented RPC system +Version: @VERSION@ +Libs: -L${libdir} -lcapnp-rpc +Requires: capnp = @VERSION@ kj-async = @VERSION@ +Cflags: -I${includedir} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/capnp.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/capnp.pc.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Cap'n Proto +Description: Insanely fast serialization system +Version: @VERSION@ +Libs: -L${libdir} -lcapnp @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ @STDLIB_FLAG@ +Libs.private: @LIBS@ +Requires: kj = @VERSION@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ @STDLIB_FLAG@ @CAPNP_LITE_FLAG@ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/cmake/CapnProtoConfig.cmake.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/cmake/CapnProtoConfig.cmake.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,27 @@ +# Example usage: +# find_package(CapnProto) +# capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS schema.capnp) +# include_directories(${CMAKE_CURRENT_BINARY_DIR}) +# add_executable(foo main.cpp ${CAPNP_SRCS}) +# target_link_libraries(foo CapnProto::capnp) +# +# If you are using RPC features, use 'CapnProto::capnp-rpc' +# in target_link_libraries call. +# +@PACKAGE_INIT@ + +set(CapnProto_VERSION @VERSION@) + +set(CAPNP_EXECUTABLE $) +set(CAPNPC_CXX_EXECUTABLE $) +set(CAPNP_INCLUDE_DIRECTORY "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@") + +# work around http://public.kitware.com/Bug/view.php?id=15258 +if(NOT _IMPORT_PREFIX) + set(_IMPORT_PREFIX ${PACKAGE_PREFIX_DIR}) +endif() + + + +include("${CMAKE_CURRENT_LIST_DIR}/CapnProtoTargets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/CapnProtoMacros.cmake") diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/cmake/CapnProtoMacros.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/cmake/CapnProtoMacros.cmake Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,116 @@ +# CAPNP_GENERATE_CPP =========================================================== +# +# Example usage: +# find_package(CapnProto) +# capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS schema.capnp) +# include_directories(${CMAKE_CURRENT_BINARY_DIR}) +# add_executable(foo main.cpp ${CAPNP_SRCS}) +# target_link_libraries(foo CapnProto::capnp-rpc) +# +# If you are using not using the RPC features you can use +# 'CapnProto::capnp' in target_link_libraries call +# +# Configuration variables (optional): +# CAPNPC_OUTPUT_DIR +# Directory to place compiled schema sources (default: CMAKE_CURRENT_BINARY_DIR). +# CAPNPC_IMPORT_DIRS +# List of additional include directories for the schema compiler. +# (CMAKE_CURRENT_SOURCE_DIR and CAPNP_INCLUDE_DIRECTORY are always included.) +# CAPNPC_SRC_PREFIX +# Schema file source prefix (default: CMAKE_CURRENT_SOURCE_DIR). +# CAPNPC_FLAGS +# Additional flags to pass to the schema compiler. +# +# TODO: convert to cmake_parse_arguments + +function(CAPNP_GENERATE_CPP SOURCES HEADERS) + if(NOT ARGN) + message(SEND_ERROR "CAPNP_GENERATE_CPP() called without any source files.") + endif() + set(tool_depends ${EMPTY_STRING}) + #Use cmake targets available + if(TARGET capnp_tool) + set(CAPNP_EXECUTABLE capnp_tool) + GET_TARGET_PROPERTY(CAPNPC_CXX_EXECUTABLE capnpc_cpp CAPNPC_CXX_EXECUTABLE) + GET_TARGET_PROPERTY(CAPNP_INCLUDE_DIRECTORY capnp_tool CAPNP_INCLUDE_DIRECTORY) + list(APPEND tool_depends capnp_tool capnpc_cpp) + endif() + if(NOT CAPNP_EXECUTABLE) + message(SEND_ERROR "Could not locate capnp executable (CAPNP_EXECUTABLE).") + endif() + if(NOT CAPNPC_CXX_EXECUTABLE) + message(SEND_ERROR "Could not locate capnpc-c++ executable (CAPNPC_CXX_EXECUTABLE).") + endif() + if(NOT CAPNP_INCLUDE_DIRECTORY) + message(SEND_ERROR "Could not locate capnp header files (CAPNP_INCLUDE_DIRECTORY).") + endif() + + # Default compiler includes + set(include_path -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CAPNP_INCLUDE_DIRECTORY}) + + if(DEFINED CAPNPC_IMPORT_DIRS) + # Append each directory as a series of '-I' flags in ${include_path} + foreach(directory ${CAPNPC_IMPORT_DIRS}) + get_filename_component(absolute_path "${directory}" ABSOLUTE) + list(APPEND include_path -I ${absolute_path}) + endforeach() + endif() + + if(DEFINED CAPNPC_OUTPUT_DIR) + # Prepend a ':' to get the format for the '-o' flag right + set(output_dir ":${CAPNPC_OUTPUT_DIR}") + else() + set(output_dir ":.") + endif() + + if(NOT DEFINED CAPNPC_SRC_PREFIX) + set(CAPNPC_SRC_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + get_filename_component(CAPNPC_SRC_PREFIX "${CAPNPC_SRC_PREFIX}" ABSOLUTE) + + set(${SOURCES}) + set(${HEADERS}) + foreach(schema_file ${ARGN}) + if(NOT EXISTS "${CAPNPC_SRC_PREFIX}/${schema_file}") + message(FATAL_ERROR "Cap'n Proto schema file '${CAPNPC_SRC_PREFIX}/${schema_file}' does not exist!") + endif() + get_filename_component(file_path "${schema_file}" ABSOLUTE) + get_filename_component(file_dir "${file_path}" PATH) + + # Figure out where the output files will go + if (NOT DEFINED CAPNPC_OUTPUT_DIR) + set(CAPNPC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/") + endif() + # Output files are placed in CAPNPC_OUTPUT_DIR, at a location as if they were + # relative to CAPNPC_SRC_PREFIX. + string(LENGTH "${CAPNPC_SRC_PREFIX}" prefix_len) + string(SUBSTRING "${file_path}" 0 ${prefix_len} output_prefix) + if(NOT "${CAPNPC_SRC_PREFIX}" STREQUAL "${output_prefix}") + message(SEND_ERROR "Could not determine output path for '${schema_file}' ('${file_path}') with source prefix '${CAPNPC_SRC_PREFIX}' into '${CAPNPC_OUTPUT_DIR}'.") + endif() + + string(SUBSTRING "${file_path}" ${prefix_len} -1 output_path) + set(output_base "${CAPNPC_OUTPUT_DIR}${output_path}") + + add_custom_command( + OUTPUT "${output_base}.c++" "${output_base}.h" + COMMAND "${CAPNP_EXECUTABLE}" + ARGS compile + -o ${CAPNPC_CXX_EXECUTABLE}${output_dir} + --src-prefix ${CAPNPC_SRC_PREFIX} + ${include_path} + ${CAPNPC_FLAGS} + ${file_path} + DEPENDS "${schema_file}" ${tool_depends} + COMMENT "Compiling Cap'n Proto schema ${schema_file}" + VERBATIM + ) + + list(APPEND ${SOURCES} "${output_base}.c++") + list(APPEND ${HEADERS} "${output_base}.h") + endforeach() + + set_source_files_properties(${${SOURCES}} ${${HEADERS}} PROPERTIES GENERATED TRUE) + set(${SOURCES} ${${SOURCES}} PARENT_SCOPE) + set(${HEADERS} ${${HEADERS}} PARENT_SCOPE) +endfunction() diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/cmake/FindCapnProto.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/cmake/FindCapnProto.cmake Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,197 @@ +# +# Finds the Cap'n Proto libraries, and compiles schema files. +# +# Configuration variables (optional): +# CAPNPC_OUTPUT_DIR +# Directory to place compiled schema sources (default: the same directory as the schema file). +# CAPNPC_IMPORT_DIRS +# List of additional include directories for the schema compiler. +# (CMAKE_CURRENT_SOURCE_DIR and CAPNP_INCLUDE_DIRS are always included.) +# CAPNPC_SRC_PREFIX +# Schema file source prefix (default: CMAKE_CURRENT_SOURCE_DIR). +# CAPNPC_FLAGS +# Additional flags to pass to the schema compiler. +# +# Variables that are discovered: +# CAPNP_EXECUTABLE +# Path to the `capnp` tool (can be set to override). +# CAPNPC_CXX_EXECUTABLE +# Path to the `capnpc-c++` tool (can be set to override). +# CAPNP_INCLUDE_DIRS +# Include directories for the library's headers (can be set to override). +# CANP_LIBRARIES +# The Cap'n Proto library paths. +# CAPNP_LIBRARIES_LITE +# Paths to only the 'lite' libraries. +# CAPNP_DEFINITIONS +# Compiler definitions required for building with the library. +# CAPNP_FOUND +# Set if the libraries have been located. +# +# Example usage: +# +# find_package(CapnProto REQUIRED) +# include_directories(${CAPNP_INCLUDE_DIRS}) +# add_definitions(${CAPNP_DEFINITIONS}) +# +# capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS schema.capnp) +# add_executable(a a.cc ${CAPNP_SRCS} ${CAPNP_HDRS}) +# target_link_library(a ${CAPNP_LIBRARIES}) +# +# For out-of-source builds: +# +# set(CAPNPC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +# include_directories(${CAPNPC_OUTPUT_DIR}) +# capnp_generate_cpp(...) +# + +# CAPNP_GENERATE_CPP =========================================================== + +function(CAPNP_GENERATE_CPP SOURCES HEADERS) + if(NOT ARGN) + message(SEND_ERROR "CAPNP_GENERATE_CPP() called without any source files.") + endif() + if(NOT CAPNP_EXECUTABLE) + message(SEND_ERROR "Could not locate capnp executable (CAPNP_EXECUTABLE).") + endif() + if(NOT CAPNPC_CXX_EXECUTABLE) + message(SEND_ERROR "Could not locate capnpc-c++ executable (CAPNPC_CXX_EXECUTABLE).") + endif() + if(NOT CAPNP_INCLUDE_DIRS) + message(SEND_ERROR "Could not locate capnp header files (CAPNP_INCLUDE_DIRS).") + endif() + + # Default compiler includes + set(include_path -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CAPNP_INCLUDE_DIRS}) + + if(DEFINED CAPNPC_IMPORT_DIRS) + # Append each directory as a series of '-I' flags in ${include_path} + foreach(directory ${CAPNPC_IMPORT_DIRS}) + get_filename_component(absolute_path "${directory}" ABSOLUTE) + list(APPEND include_path -I ${absolute_path}) + endforeach() + endif() + + if(DEFINED CAPNPC_OUTPUT_DIR) + # Prepend a ':' to get the format for the '-o' flag right + set(output_dir ":${CAPNPC_OUTPUT_DIR}") + else() + set(output_dir ":.") + endif() + + if(NOT DEFINED CAPNPC_SRC_PREFIX) + set(CAPNPC_SRC_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + get_filename_component(CAPNPC_SRC_PREFIX "${CAPNPC_SRC_PREFIX}" ABSOLUTE) + + set(${SOURCES}) + set(${HEADERS}) + foreach(schema_file ${ARGN}) + get_filename_component(file_path "${schema_file}" ABSOLUTE) + get_filename_component(file_dir "${file_path}" PATH) + + # Figure out where the output files will go + if (NOT DEFINED CAPNPC_OUTPUT_DIR) + set(output_base "${file_path}") + else() + # Output files are placed in CAPNPC_OUTPUT_DIR, at a location as if they were + # relative to CAPNPC_SRC_PREFIX. + string(LENGTH "${CAPNPC_SRC_PREFIX}" prefix_len) + string(SUBSTRING "${file_path}" 0 ${prefix_len} output_prefix) + if(NOT "${CAPNPC_SRC_PREFIX}" STREQUAL "${output_prefix}") + message(SEND_ERROR "Could not determine output path for '${schema_file}' ('${file_path}') with source prefix '${CAPNPC_SRC_PREFIX}' into '${CAPNPC_OUTPUT_DIR}'.") + endif() + + string(SUBSTRING "${file_path}" ${prefix_len} -1 output_path) + set(output_base "${CAPNPC_OUTPUT_DIR}${output_path}") + endif() + + add_custom_command( + OUTPUT "${output_base}.c++" "${output_base}.h" + COMMAND "${CAPNP_EXECUTABLE}" + ARGS compile + -o ${CAPNPC_CXX_EXECUTABLE}${output_dir} + --src-prefix ${CAPNPC_SRC_PREFIX} + ${include_path} + ${CAPNPC_FLAGS} + ${file_path} + DEPENDS "${schema_file}" + COMMENT "Compiling Cap'n Proto schema ${schema_file}" + VERBATIM + ) + list(APPEND ${SOURCES} "${output_base}.c++") + list(APPEND ${HEADERS} "${output_base}.h") + endforeach() + + set_source_files_properties(${${SOURCES}} ${${HEADERS}} PROPERTIES GENERATED TRUE) + set(${SOURCES} ${${SOURCES}} PARENT_SCOPE) + set(${HEADERS} ${${HEADERS}} PARENT_SCOPE) +endfunction() + +# Find Libraries/Paths ========================================================= + +# Use pkg-config to get path hints and definitions +find_package(PkgConfig QUIET) +pkg_check_modules(PKGCONFIG_CAPNP capnp) +pkg_check_modules(PKGCONFIG_CAPNP_RPC capnp-rpc QUIET) +pkg_check_modules(PKGCONFIG_CAPNP_JSON capnp-json QUIET) + +find_library(CAPNP_LIB_KJ kj + HINTS "${PKGCONFIG_CAPNP_LIBDIR}" ${PKGCONFIG_CAPNP_LIBRARY_DIRS} +) +find_library(CAPNP_LIB_KJ-ASYNC kj-async + HINTS "${PKGCONFIG_CAPNP_RPC_LIBDIR}" ${PKGCONFIG_CAPNP_RPC_LIBRARY_DIRS} +) +find_library(CAPNP_LIB_CAPNP capnp + HINTS "${PKGCONFIG_CAPNP_LIBDIR}" ${PKGCONFIG_CAPNP_LIBRARY_DIRS} +) +find_library(CAPNP_LIB_CAPNP-RPC capnp-rpc + HINTS "${PKGCONFIG_CAPNP_RPC_LIBDIR}" ${PKGCONFIG_CAPNP_RPC_LIBRARY_DIRS} +) +find_library(CAPNP_LIB_CAPNP-JSON capnp-json + HINTS "${PKGCONFIG_CAPNP_JSON_LIBDIR}" ${PKGCONFIG_CAPNP_JSON_LIBRARY_DIRS} +) +mark_as_advanced(CAPNP_LIB_KJ CAPNP_LIB_KJ-ASYNC CAPNP_LIB_CAPNP CAPNP_LIB_CAPNP-RPC CAPNP_LIB_CAPNP-JSON) +set(CAPNP_LIBRARIES_LITE + ${CAPNP_LIB_CAPNP} + ${CAPNP_LIB_KJ} +) +set(CAPNP_LIBRARIES + ${CAPNP_LIB_CAPNP-JSON} + ${CAPNP_LIB_CAPNP-RPC} + ${CAPNP_LIB_CAPNP} + ${CAPNP_LIB_KJ-ASYNC} + ${CAPNP_LIB_KJ} +) + +# Was only the 'lite' library found? +if(CAPNP_LIB_CAPNP AND NOT CAPNP_LIB_CAPNP-RPC) + set(CAPNP_DEFINITIONS -DCAPNP_LITE) +else() + set(CAPNP_DEFINITIONS) +endif() + +find_path(CAPNP_INCLUDE_DIRS capnp/generated-header-support.h + HINTS "${PKGCONFIG_CAPNP_INCLUDEDIR}" ${PKGCONFIG_CAPNP_INCLUDE_DIRS} +) + +find_program(CAPNP_EXECUTABLE + NAMES capnp + DOC "Cap'n Proto Command-line Tool" + HINTS "${PKGCONFIG_CAPNP_PREFIX}/bin" +) + +find_program(CAPNPC_CXX_EXECUTABLE + NAMES capnpc-c++ + DOC "Capn'n Proto C++ Compiler" + HINTS "${PKGCONFIG_CAPNP_PREFIX}/bin" +) + +# Only *require* the include directory, libkj, and libcapnp. If compiling with +# CAPNP_LITE, nothing else will be found. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CAPNP DEFAULT_MSG + CAPNP_INCLUDE_DIRS + CAPNP_LIB_KJ + CAPNP_LIB_CAPNP +) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/configure.ac --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/configure.ac Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,109 @@ +## Process this file with autoconf to produce configure. + +AC_INIT([Capn Proto],[0.6.0],[capnproto@googlegroups.com],[capnproto-c++]) + +AC_CONFIG_SRCDIR([src/capnp/layout.c++]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# autoconf's default CXXFLAGS are usually "-g -O2". A far more reasonable +# default is -O2 -NDEBUG. +AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"], + [CFLAGS="-O2 -DNDEBUG"]) +AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"], + [CXXFLAGS="-O2 -DNDEBUG"]) + +AM_INIT_AUTOMAKE([tar-ustar]) + +AC_ARG_WITH([external-capnp], + [AS_HELP_STRING([--with-external-capnp], + [use the system capnp binary (or the one specified with $CAPNP) instead of compiling a new + one (useful for cross-compiling)])], + [external_capnp=yes],[external_capnp=no]) + +AC_ARG_ENABLE([reflection], [ + AS_HELP_STRING([--disable-reflection], [ + compile Cap'n Proto in "lite mode", in which all reflection APIs (schema.h, dynamic.h, etc.) + are not included. Produces a smaller library at the cost of features. All programs built + against the library MUST be compiled with -DCAPNP_LITE=1. Note that because the compiler + itself uses reflection in its implementation, you must also use --with-external-capnp when + using this option.]) + ], [ + case "${enableval}" in + yes) + lite_mode=no + ;; + no) + lite_mode=yes + AS_IF([test "$external_capnp" != "yes"], [ + AC_MSG_ERROR([you must specify --with-external-capnp when using --disable-reflection]) + ]) + ;; + *) + AC_MSG_ERROR([bad value ${enableval} for --enable-reflection]) + ;; + esac + ], [lite_mode=no]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AC_LANG([C++]) +AX_CXX_COMPILE_STDCXX_11 + +AS_CASE("${host_os}", *mingw*, [ + # We don't use pthreads on MinGW. + PTHREAD_CFLAGS="-mthreads" + PTHREAD_LIBS="" + PTHREAD_CC="" + ASYNC_LIBS="-lws2_32" + AC_SUBST(PTHREAD_LIBS) + AC_SUBST(PTHREAD_CFLAGS) + AC_SUBST(PTHREAD_CC) + AC_SUBST(ASYNC_LIBS) + ], *, [ + ACX_PTHREAD + ASYNC_LIBS="" + AC_SUBST(ASYNC_LIBS) + ]) + +LT_INIT + +AS_IF([test "$external_capnp" != "no"], [ + AS_IF([test "x$CAPNP" = "x"], [CAPNP="capnp"], [with_capnp=yes]) + AS_IF([test "x$CAPNPC_CXX" = "x"], [ + # CAPNPC_CXX was not specified. Choose a reasonable default. + AS_CASE([$CAPNP], [*/*], [ + # $CAPNP contains a slash, so it's not on $PATH. Assume capnpc-c++ is not either, but is + # in the same directory. + CAPNPC_CXX=`dirname $CAPNP`/capnpc-c++ + ], [ + # $CAPNP is on $PATH, so tell it to find the plugin on $PATH as well. + CAPNPC_CXX="c++" + ]) + ]) + AC_SUBST([CAPNP]) + AC_SUBST([CAPNPC_CXX]) +]) +AM_CONDITIONAL([USE_EXTERNAL_CAPNP], [test "$external_capnp" != "no"]) + +AM_CONDITIONAL([LITE_MODE], [test "$lite_mode" = "yes"]) + +AS_IF([test "$lite_mode" = "yes"], [ + CXXFLAGS="-DCAPNP_LITE $CXXFLAGS" + CAPNP_LITE_FLAG=-DCAPNP_LITE +]) +AC_SUBST([CAPNP_LITE_FLAG]) + +AC_SEARCH_LIBS(sched_yield, rt) + +# Users will need to use the same -stdlib as us so we'd better let pkg-config know about it. +STDLIB_FLAG=`echo "$CXX $CXXFLAGS" | grep -o ' [[-]]stdlib=[[^ ]]*'` +AC_SUBST([STDLIB_FLAG]) + +LIBS="$PTHREAD_LIBS $LIBS" +CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" + +AC_CONFIG_FILES([Makefile capnp.pc capnp-rpc.pc capnp-json.pc kj.pc kj-async.pc]) +AC_OUTPUT diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/ekam-provider/c++header --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/ekam-provider/c++header Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1 @@ +../src \ No newline at end of file diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/ekam-provider/canonical --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/ekam-provider/canonical Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1 @@ +../src \ No newline at end of file diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/ekam-provider/this-dir-is-to-trick-gdb.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/ekam-provider/this-dir-is-to-trick-gdb.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,4 @@ +The sole purpose of this directory is to allow GDB to find source files when +debugging an executable compiled using Ekam, since the source locations found +in the compiled binary will correspond to Ekam's virtual filesystem, not the +real one. This is a hack, and doesn't always work. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/kj-async.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/kj-async.pc.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: KJ Async Framework Library +Description: Basic utility library called KJ (async part) +Version: @VERSION@ +Libs: -L${libdir} -lkj-async @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ @STDLIB_FLAG@ +Requires: kj = @VERSION@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ @STDLIB_FLAG@ @CAPNP_LITE_FLAG@ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/kj.pc.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/kj.pc.in Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: KJ Framework Library +Description: Basic utility library called KJ +Version: @VERSION@ +Libs: -L${libdir} -lkj @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ @STDLIB_FLAG@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ @STDLIB_FLAG@ @CAPNP_LITE_FLAG@ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/m4/acx_pthread.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/m4/acx_pthread.m4 Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,405 @@ +# This file was copied to Cap'n Proto from the Protocol Buffers distribution, +# version 2.3.0. + +# This was retrieved from +# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi +# See also (perhaps for new versions?) +# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi +# +# We've rewritten the inconsistency check code (from avahi), to work +# more broadly. In particular, it no longer assumes ld accepts -zdefs. +# This caused a restructing of the code, but the functionality has only +# changed a little. + +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl @summary figure out how to build C programs using POSIX threads +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2006-05-29 +dnl @license GPLWithACException +dnl +dnl Checks for GCC shared/pthread inconsistency based on work by +dnl Marcin Owsiany + + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi + + # The next part tries to detect GCC inconsistency with -shared on some + # architectures and systems. The problem is that in certain + # configurations, when -shared is specified, GCC "forgets" to + # internally use various flags which are still necessary. + + # + # Prepare the flags + # + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_CC="$CC" + + # Try with the flags determined by the earlier checks. + # + # -Wl,-z,defs forces link-time symbol resolution, so that the + # linking checks with -shared actually have any value + # + # FIXME: -fPIC is required for -shared on many architectures, + # so we specify it here, but the right way would probably be to + # properly detect whether it is actually required. + CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CC="$PTHREAD_CC" + + # In order not to create several levels of indentation, we test + # the value of "$done" until we find the cure or run out of ideas. + done="no" + + # First, make sure the CFLAGS we added are actually accepted by our + # compiler. If not (and OS X's ld, for instance, does not accept -z), + # then we can't do this test. + if test x"$done" = xno; then + AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) + AC_TRY_LINK(,, , [done=yes]) + + if test "x$done" = xyes ; then + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([yes]) + fi + fi + + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + + # + # Linux gcc on some architectures such as mips/mipsel forgets + # about -lpthread + # + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -lpthread fixes that]) + LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + # + # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc + # + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -lc_r fixes that]) + LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" + else + AC_MSG_RESULT([no]) + fi + fi + if test x"$done" = xno; then + # OK, we have run out of ideas + AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) + + # so it's not safe to assume that we may use pthreads + acx_pthread_ok=no + fi + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + CC="$save_CC" +else + PTHREAD_CC="$CC" +fi + +if test "x$acx_pthread_ok" = xyes; then + # One more check: If we chose to use a compiler flag like -pthread but it is combined with + # -nostdlib then the compiler won't implicitly link against libpthread. This can happen + # in particular when using some versions of libtool on some distros. See: + # https://bugzilla.redhat.com/show_bug.cgi?id=661333 + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_CC="$CC" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="-nostdlib $PTHREAD_LIBS $LIBS -lc" + CC="$PTHREAD_CC" + + AC_MSG_CHECKING([whether pthread flag is sufficient with -nostdlib]) + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [AC_MSG_RESULT([yes])], [ + AC_MSG_RESULT([no]) + + AC_MSG_CHECKING([whether adding -lpthread fixes that]) + + LIBS="-nostdlib $PTHREAD_LIBS -lpthread $save_LIBS -lc" + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [ + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" + ], [AC_MSG_RESULT([no])]) + ]) + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + CC="$save_CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/m4/ax_cxx_compile_stdcxx_11.m4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/m4/ax_cxx_compile_stdcxx_11.m4 Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,179 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# Additionally modified to detect -stdlib by Kenton Varda. +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# Errors out if no mode that supports C++11 baseline syntax can be found. +# The argument, if specified, indicates whether you insist on an extended +# mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -std=c++11). +# If neither is specified, you get whatever works, with preference for an +# extended mode. +# +# Additionally, check if the standard library supports C++11. If not, +# try adding -stdlib=libc++ to see if that fixes it. This is needed e.g. +# on Mac OSX 10.8, which ships with a very old libstdc++ but a relatively +# new libc++. +# +# Both flags are actually added to CXX rather than CXXFLAGS to work around +# a bug in libtool: -stdlib is stripped from CXXFLAGS when linking dynamic +# libraries because it is not recognized. A patch was committed to mainline +# libtool in February 2012 but as of June 2013 there has not yet been a +# release containing this patch. +# http://git.savannah.gnu.org/gitweb/?p=libtool.git;a=commit;h=c0c49f289f22ae670066657c60905986da3b555f +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Kenton Varda +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + // GCC 4.7 introduced __float128 and makes reference to it in type_traits. + // Clang doesn't implement it, so produces an error. Using -std=c++11 + // instead of -std=gnu++11 works around the problem. But on some + // platforms we need -std=gnu++11. So we want to make sure the test of + // -std=gnu++11 fails only where this problem is present, and we hope that + // -std=c++11 is always an acceptable fallback in these cases. Complicating + // matters, though, is that we don't want to fail here if the platform is + // completely missing a C++11 standard library, because we want to probe that + // in a later test. It happens, though, that Clang allows us to check + // whether a header exists at all before we include it. + // + // So, if we detect that __has_include is available (which it is on Clang), + // and we use it to detect that (a C++11 header) exists, then + // we go ahead and #include it to see if it breaks. In all other cases, we + // don't #include it at all. + #ifdef __has_include + #if __has_include() + #include + #endif + #endif +]) + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody_lib], [ + #include + #include + #include + #include +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_ASSERT([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + ac_success=yes + break + fi + done + fi]) + + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + else + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 library features by default, + ax_cv_cxx_compile_cxx11_lib, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody_lib])], + [ax_cv_cxx_compile_cxx11_lib=yes], + [ax_cv_cxx_compile_cxx11_lib=no]) + ]) + if test x$ax_cv_cxx_compile_cxx11_lib = xyes; then + ac_success=yes + else + # Try with -stdlib=libc++ + AC_CACHE_CHECK(whether $CXX supports C++11 library features with -stdlib=libc++, + ax_cv_cxx_compile_cxx11_lib_libcxx, + [ac_save_CXX="$CXX" + CXX="$CXX -stdlib=libc++" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody_lib])], + [eval ax_cv_cxx_compile_cxx11_lib_libcxx=yes], + [eval ax_cv_cxx_compile_cxx11_lib_libcxx=no]) + CXX="$ac_save_CXX"]) + if eval test x$ax_cv_cxx_compile_cxx11_lib_libcxx = xyes; then + CXX="$CXX -stdlib=libc++" + ac_success=yes + break + fi + fi + + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A C++ library with support for C++11 features is required.]) + fi + fi +]) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/regenerate-bootstraps.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/regenerate-bootstraps.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ +#! /usr/bin/env bash + +set -euo pipefail + +export PATH=$PWD/bin:$PWD:$PATH + +capnp compile -Isrc --no-standard-import --src-prefix=src -oc++:src \ + src/capnp/c++.capnp src/capnp/schema.capnp \ + src/capnp/compiler/lexer.capnp src/capnp/compiler/grammar.capnp \ + src/capnp/rpc.capnp src/capnp/rpc-twoparty.capnp src/capnp/persistent.capnp \ + src/capnp/compat/json.capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/CMakeLists.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,35 @@ +# A Cap'n Proto sample project. +# +# To build (non-MSVC): +# 1. Install Cap'n Proto somewhere ($PREFIX below): +# +# mkdir capnproto/build +# cd capnproto/build +# cmake ../c++ -DCMAKE_INSTALL_PREFIX=$PREFIX +# cmake --build . --target install +# +# 2. Ensure Cap'n Proto's executables are on the PATH, then build the sample project: +# +# export PATH=$PREFIX/bin:$PATH +# mkdir ../build-samples +# cd ../build-samples +# cmake ../c++/samples +# cmake --build . + +project("Cap'n Proto Samples" CXX) +cmake_minimum_required(VERSION 3.1) + +find_package(CapnProto CONFIG REQUIRED) + +capnp_generate_cpp(addressbookSources addressbookHeaders addressbook.capnp) +add_executable(addressbook addressbook.c++ ${addressbookSources}) +target_link_libraries(addressbook CapnProto::capnp) +target_include_directories(addressbook PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +capnp_generate_cpp(calculatorSources calculatorHeaders calculator.capnp) +add_executable(calculator-client calculator-client.c++ ${calculatorSources}) +add_executable(calculator-server calculator-server.c++ ${calculatorSources}) +target_link_libraries(calculator-client CapnProto::capnp-rpc) +target_link_libraries(calculator-server CapnProto::capnp-rpc) +target_include_directories(calculator-client PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(calculator-server PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/addressbook.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/addressbook.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,282 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This sample code appears in the documentation for the C++ implementation. +// +// If Cap'n Proto is installed, build the sample like: +// capnp compile -oc++ addressbook.capnp +// c++ -std=c++11 -Wall addressbook.c++ addressbook.capnp.c++ `pkg-config --cflags --libs capnp` -o addressbook +// +// If Cap'n Proto is not installed, but the source is located at $SRC and has been +// compiled in $BUILD (often both are simply ".." from here), you can do: +// $BUILD/capnp compile -I$SRC/src -o$BUILD/capnpc-c++ addressbook.capnp +// c++ -std=c++11 -Wall addressbook.c++ addressbook.capnp.c++ -I$SRC/src -L$BUILD/.libs -lcapnp -lkj -o addressbook +// +// Run like: +// ./addressbook write | ./addressbook read +// Use "dwrite" and "dread" to use dynamic code instead. + +// TODO(test): Needs cleanup. + +#include "addressbook.capnp.h" +#include +#include +#include + +using addressbook::Person; +using addressbook::AddressBook; + +void writeAddressBook(int fd) { + ::capnp::MallocMessageBuilder message; + + AddressBook::Builder addressBook = message.initRoot(); + ::capnp::List::Builder people = addressBook.initPeople(2); + + Person::Builder alice = people[0]; + alice.setId(123); + alice.setName("Alice"); + alice.setEmail("alice@example.com"); + // Type shown for explanation purposes; normally you'd use auto. + ::capnp::List::Builder alicePhones = + alice.initPhones(1); + alicePhones[0].setNumber("555-1212"); + alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE); + alice.getEmployment().setSchool("MIT"); + + Person::Builder bob = people[1]; + bob.setId(456); + bob.setName("Bob"); + bob.setEmail("bob@example.com"); + auto bobPhones = bob.initPhones(2); + bobPhones[0].setNumber("555-4567"); + bobPhones[0].setType(Person::PhoneNumber::Type::HOME); + bobPhones[1].setNumber("555-7654"); + bobPhones[1].setType(Person::PhoneNumber::Type::WORK); + bob.getEmployment().setUnemployed(); + + writePackedMessageToFd(fd, message); +} + +void printAddressBook(int fd) { + ::capnp::PackedFdMessageReader message(fd); + + AddressBook::Reader addressBook = message.getRoot(); + + for (Person::Reader person : addressBook.getPeople()) { + std::cout << person.getName().cStr() << ": " + << person.getEmail().cStr() << std::endl; + for (Person::PhoneNumber::Reader phone: person.getPhones()) { + const char* typeName = "UNKNOWN"; + switch (phone.getType()) { + case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break; + case Person::PhoneNumber::Type::HOME: typeName = "home"; break; + case Person::PhoneNumber::Type::WORK: typeName = "work"; break; + } + std::cout << " " << typeName << " phone: " + << phone.getNumber().cStr() << std::endl; + } + Person::Employment::Reader employment = person.getEmployment(); + switch (employment.which()) { + case Person::Employment::UNEMPLOYED: + std::cout << " unemployed" << std::endl; + break; + case Person::Employment::EMPLOYER: + std::cout << " employer: " + << employment.getEmployer().cStr() << std::endl; + break; + case Person::Employment::SCHOOL: + std::cout << " student at: " + << employment.getSchool().cStr() << std::endl; + break; + case Person::Employment::SELF_EMPLOYED: + std::cout << " self-employed" << std::endl; + break; + } + } +} + +#include "addressbook.capnp.h" +#include +#include +#include +#include +#include + +using ::capnp::DynamicValue; +using ::capnp::DynamicStruct; +using ::capnp::DynamicEnum; +using ::capnp::DynamicList; +using ::capnp::List; +using ::capnp::Schema; +using ::capnp::StructSchema; +using ::capnp::EnumSchema; + +using ::capnp::Void; +using ::capnp::Text; +using ::capnp::MallocMessageBuilder; +using ::capnp::PackedFdMessageReader; + +void dynamicWriteAddressBook(int fd, StructSchema schema) { + // Write a message using the dynamic API to set each + // field by text name. This isn't something you'd + // normally want to do; it's just for illustration. + + MallocMessageBuilder message; + + // Types shown for explanation purposes; normally you'd + // use auto. + DynamicStruct::Builder addressBook = + message.initRoot(schema); + + DynamicList::Builder people = + addressBook.init("people", 2).as(); + + DynamicStruct::Builder alice = + people[0].as(); + alice.set("id", 123); + alice.set("name", "Alice"); + alice.set("email", "alice@example.com"); + auto alicePhones = alice.init("phones", 1).as(); + auto phone0 = alicePhones[0].as(); + phone0.set("number", "555-1212"); + phone0.set("type", "mobile"); + alice.get("employment").as() + .set("school", "MIT"); + + auto bob = people[1].as(); + bob.set("id", 456); + bob.set("name", "Bob"); + bob.set("email", "bob@example.com"); + + // Some magic: We can convert a dynamic sub-value back to + // the native type with as()! + List::Builder bobPhones = + bob.init("phones", 2).as>(); + bobPhones[0].setNumber("555-4567"); + bobPhones[0].setType(Person::PhoneNumber::Type::HOME); + bobPhones[1].setNumber("555-7654"); + bobPhones[1].setType(Person::PhoneNumber::Type::WORK); + bob.get("employment").as() + .set("unemployed", ::capnp::VOID); + + writePackedMessageToFd(fd, message); +} + +void dynamicPrintValue(DynamicValue::Reader value) { + // Print an arbitrary message via the dynamic API by + // iterating over the schema. Look at the handling + // of STRUCT in particular. + + switch (value.getType()) { + case DynamicValue::VOID: + std::cout << ""; + break; + case DynamicValue::BOOL: + std::cout << (value.as() ? "true" : "false"); + break; + case DynamicValue::INT: + std::cout << value.as(); + break; + case DynamicValue::UINT: + std::cout << value.as(); + break; + case DynamicValue::FLOAT: + std::cout << value.as(); + break; + case DynamicValue::TEXT: + std::cout << '\"' << value.as().cStr() << '\"'; + break; + case DynamicValue::LIST: { + std::cout << "["; + bool first = true; + for (auto element: value.as()) { + if (first) { + first = false; + } else { + std::cout << ", "; + } + dynamicPrintValue(element); + } + std::cout << "]"; + break; + } + case DynamicValue::ENUM: { + auto enumValue = value.as(); + KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) { + std::cout << + enumerant->getProto().getName().cStr(); + } else { + // Unknown enum value; output raw number. + std::cout << enumValue.getRaw(); + } + break; + } + case DynamicValue::STRUCT: { + std::cout << "("; + auto structValue = value.as(); + bool first = true; + for (auto field: structValue.getSchema().getFields()) { + if (!structValue.has(field)) continue; + if (first) { + first = false; + } else { + std::cout << ", "; + } + std::cout << field.getProto().getName().cStr() + << " = "; + dynamicPrintValue(structValue.get(field)); + } + std::cout << ")"; + break; + } + default: + // There are other types, we aren't handling them. + std::cout << "?"; + break; + } +} + +void dynamicPrintMessage(int fd, StructSchema schema) { + PackedFdMessageReader message(fd); + dynamicPrintValue(message.getRoot(schema)); + std::cout << std::endl; +} + +int main(int argc, char* argv[]) { + StructSchema schema = Schema::from(); + if (argc != 2) { + std::cerr << "Missing arg." << std::endl; + return 1; + } else if (strcmp(argv[1], "write") == 0) { + writeAddressBook(1); + } else if (strcmp(argv[1], "read") == 0) { + printAddressBook(0); + } else if (strcmp(argv[1], "dwrite") == 0) { + dynamicWriteAddressBook(1, schema); + } else if (strcmp(argv[1], "dread") == 0) { + dynamicPrintMessage(0, schema); + } else { + std::cerr << "Invalid arg: " << argv[1] << std::endl; + return 1; + } + return 0; +} + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/addressbook.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/addressbook.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,56 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x9eb32e19f86ee174; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("addressbook"); + +struct Person { + id @0 :UInt32; + name @1 :Text; + email @2 :Text; + phones @3 :List(PhoneNumber); + + struct PhoneNumber { + number @0 :Text; + type @1 :Type; + + enum Type { + mobile @0; + home @1; + work @2; + } + } + + employment :union { + unemployed @4 :Void; + employer @5 :Text; + school @6 :Text; + selfEmployed @7 :Void; + # We assume that a person is only one of these. + } +} + +struct AddressBook { + people @0 :List(Person); +} + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/calculator-client.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/calculator-client.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,367 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "calculator.capnp.h" +#include +#include +#include +#include + +class PowerFunction final: public Calculator::Function::Server { + // An implementation of the Function interface wrapping pow(). Note that + // we're implementing this on the client side and will pass a reference to + // the server. The server will then be able to make calls back to the client. + +public: + kj::Promise call(CallContext context) { + auto params = context.getParams().getParams(); + KJ_REQUIRE(params.size() == 2, "Wrong number of parameters."); + context.getResults().setValue(pow(params[0], params[1])); + return kj::READY_NOW; + } +}; + +int main(int argc, const char* argv[]) { + if (argc != 2) { + std::cerr << "usage: " << argv[0] << " HOST:PORT\n" + "Connects to the Calculator server at the given address and " + "does some RPCs." << std::endl; + return 1; + } + + capnp::EzRpcClient client(argv[1]); + Calculator::Client calculator = client.getMain(); + + // Keep an eye on `waitScope`. Whenever you see it used is a place where we + // stop and wait for the server to respond. If a line of code does not use + // `waitScope`, then it does not block! + auto& waitScope = client.getWaitScope(); + + { + // Make a request that just evaluates the literal value 123. + // + // What's interesting here is that evaluate() returns a "Value", which is + // another interface and therefore points back to an object living on the + // server. We then have to call read() on that object to read it. + // However, even though we are making two RPC's, this block executes in + // *one* network round trip because of promise pipelining: we do not wait + // for the first call to complete before we send the second call to the + // server. + + std::cout << "Evaluating a literal... "; + std::cout.flush(); + + // Set up the request. + auto request = calculator.evaluateRequest(); + request.getExpression().setLiteral(123); + + // Send it, which returns a promise for the result (without blocking). + auto evalPromise = request.send(); + + // Using the promise, create a pipelined request to call read() on the + // returned object, and then send that. + auto readPromise = evalPromise.getValue().readRequest().send(); + + // Now that we've sent all the requests, wait for the response. Until this + // point, we haven't waited at all! + auto response = readPromise.wait(waitScope); + KJ_ASSERT(response.getValue() == 123); + + std::cout << "PASS" << std::endl; + } + + { + // Make a request to evaluate 123 + 45 - 67. + // + // The Calculator interface requires that we first call getOperator() to + // get the addition and subtraction functions, then call evaluate() to use + // them. But, once again, we can get both functions, call evaluate(), and + // then read() the result -- four RPCs -- in the time of *one* network + // round trip, because of promise pipelining. + + std::cout << "Using add and subtract... "; + std::cout.flush(); + + Calculator::Function::Client add = nullptr; + Calculator::Function::Client subtract = nullptr; + + { + // Get the "add" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::ADD); + add = request.send().getFunc(); + } + + { + // Get the "subtract" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::SUBTRACT); + subtract = request.send().getFunc(); + } + + // Build the request to evaluate 123 + 45 - 67. + auto request = calculator.evaluateRequest(); + + auto subtractCall = request.getExpression().initCall(); + subtractCall.setFunction(subtract); + auto subtractParams = subtractCall.initParams(2); + subtractParams[1].setLiteral(67); + + auto addCall = subtractParams[0].initCall(); + addCall.setFunction(add); + auto addParams = addCall.initParams(2); + addParams[0].setLiteral(123); + addParams[1].setLiteral(45); + + // Send the evaluate() request, read() the result, and wait for read() to + // finish. + auto evalPromise = request.send(); + auto readPromise = evalPromise.getValue().readRequest().send(); + + auto response = readPromise.wait(waitScope); + KJ_ASSERT(response.getValue() == 101); + + std::cout << "PASS" << std::endl; + } + + { + // Make a request to evaluate 4 * 6, then use the result in two more + // requests that add 3 and 5. + // + // Since evaluate() returns its result wrapped in a `Value`, we can pass + // that `Value` back to the server in subsequent requests before the first + // `evaluate()` has actually returned. Thus, this example again does only + // one network round trip. + + std::cout << "Pipelining eval() calls... "; + std::cout.flush(); + + Calculator::Function::Client add = nullptr; + Calculator::Function::Client multiply = nullptr; + + { + // Get the "add" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::ADD); + add = request.send().getFunc(); + } + + { + // Get the "multiply" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::MULTIPLY); + multiply = request.send().getFunc(); + } + + // Build the request to evaluate 4 * 6 + auto request = calculator.evaluateRequest(); + + auto multiplyCall = request.getExpression().initCall(); + multiplyCall.setFunction(multiply); + auto multiplyParams = multiplyCall.initParams(2); + multiplyParams[0].setLiteral(4); + multiplyParams[1].setLiteral(6); + + auto multiplyResult = request.send().getValue(); + + // Use the result in two calls that add 3 and add 5. + + auto add3Request = calculator.evaluateRequest(); + auto add3Call = add3Request.getExpression().initCall(); + add3Call.setFunction(add); + auto add3Params = add3Call.initParams(2); + add3Params[0].setPreviousResult(multiplyResult); + add3Params[1].setLiteral(3); + auto add3Promise = add3Request.send().getValue().readRequest().send(); + + auto add5Request = calculator.evaluateRequest(); + auto add5Call = add5Request.getExpression().initCall(); + add5Call.setFunction(add); + auto add5Params = add5Call.initParams(2); + add5Params[0].setPreviousResult(multiplyResult); + add5Params[1].setLiteral(5); + auto add5Promise = add5Request.send().getValue().readRequest().send(); + + // Now wait for the results. + KJ_ASSERT(add3Promise.wait(waitScope).getValue() == 27); + KJ_ASSERT(add5Promise.wait(waitScope).getValue() == 29); + + std::cout << "PASS" << std::endl; + } + + { + // Our calculator interface supports defining functions. Here we use it + // to define two functions and then make calls to them as follows: + // + // f(x, y) = x * 100 + y + // g(x) = f(x, x + 1) * 2; + // f(12, 34) + // g(21) + // + // Once again, the whole thing takes only one network round trip. + + std::cout << "Defining functions... "; + std::cout.flush(); + + Calculator::Function::Client add = nullptr; + Calculator::Function::Client multiply = nullptr; + Calculator::Function::Client f = nullptr; + Calculator::Function::Client g = nullptr; + + { + // Get the "add" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::ADD); + add = request.send().getFunc(); + } + + { + // Get the "multiply" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::MULTIPLY); + multiply = request.send().getFunc(); + } + + { + // Define f. + auto request = calculator.defFunctionRequest(); + request.setParamCount(2); + + { + // Build the function body. + auto addCall = request.getBody().initCall(); + addCall.setFunction(add); + auto addParams = addCall.initParams(2); + addParams[1].setParameter(1); // y + + auto multiplyCall = addParams[0].initCall(); + multiplyCall.setFunction(multiply); + auto multiplyParams = multiplyCall.initParams(2); + multiplyParams[0].setParameter(0); // x + multiplyParams[1].setLiteral(100); + } + + f = request.send().getFunc(); + } + + { + // Define g. + auto request = calculator.defFunctionRequest(); + request.setParamCount(1); + + { + // Build the function body. + auto multiplyCall = request.getBody().initCall(); + multiplyCall.setFunction(multiply); + auto multiplyParams = multiplyCall.initParams(2); + multiplyParams[1].setLiteral(2); + + auto fCall = multiplyParams[0].initCall(); + fCall.setFunction(f); + auto fParams = fCall.initParams(2); + fParams[0].setParameter(0); + + auto addCall = fParams[1].initCall(); + addCall.setFunction(add); + auto addParams = addCall.initParams(2); + addParams[0].setParameter(0); + addParams[1].setLiteral(1); + } + + g = request.send().getFunc(); + } + + // OK, we've defined all our functions. Now create our eval requests. + + // f(12, 34) + auto fEvalRequest = calculator.evaluateRequest(); + auto fCall = fEvalRequest.initExpression().initCall(); + fCall.setFunction(f); + auto fParams = fCall.initParams(2); + fParams[0].setLiteral(12); + fParams[1].setLiteral(34); + auto fEvalPromise = fEvalRequest.send().getValue().readRequest().send(); + + // g(21) + auto gEvalRequest = calculator.evaluateRequest(); + auto gCall = gEvalRequest.initExpression().initCall(); + gCall.setFunction(g); + gCall.initParams(1)[0].setLiteral(21); + auto gEvalPromise = gEvalRequest.send().getValue().readRequest().send(); + + // Wait for the results. + KJ_ASSERT(fEvalPromise.wait(waitScope).getValue() == 1234); + KJ_ASSERT(gEvalPromise.wait(waitScope).getValue() == 4244); + + std::cout << "PASS" << std::endl; + } + + { + // Make a request that will call back to a function defined locally. + // + // Specifically, we will compute 2^(4 + 5). However, exponent is not + // defined by the Calculator server. So, we'll implement the Function + // interface locally and pass it to the server for it to use when + // evaluating the expression. + // + // This example requires two network round trips to complete, because the + // server calls back to the client once before finishing. In this + // particular case, this could potentially be optimized by using a tail + // call on the server side -- see CallContext::tailCall(). However, to + // keep the example simpler, we haven't implemented this optimization in + // the sample server. + + std::cout << "Using a callback... "; + std::cout.flush(); + + Calculator::Function::Client add = nullptr; + + { + // Get the "add" function from the server. + auto request = calculator.getOperatorRequest(); + request.setOp(Calculator::Operator::ADD); + add = request.send().getFunc(); + } + + // Build the eval request for 2^(4+5). + auto request = calculator.evaluateRequest(); + + auto powCall = request.getExpression().initCall(); + powCall.setFunction(kj::heap()); + auto powParams = powCall.initParams(2); + powParams[0].setLiteral(2); + + auto addCall = powParams[1].initCall(); + addCall.setFunction(add); + auto addParams = addCall.initParams(2); + addParams[0].setLiteral(4); + addParams[1].setLiteral(5); + + // Send the request and wait. + auto response = request.send().getValue().readRequest() + .send().wait(waitScope); + KJ_ASSERT(response.getValue() == 512); + + std::cout << "PASS" << std::endl; + } + + return 0; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/calculator-server.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/calculator-server.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,215 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "calculator.capnp.h" +#include +#include +#include +#include + +typedef unsigned int uint; + +kj::Promise readValue(Calculator::Value::Client value) { + // Helper function to asynchronously call read() on a Calculator::Value and + // return a promise for the result. (In the future, the generated code might + // include something like this automatically.) + + return value.readRequest().send() + .then([](capnp::Response result) { + return result.getValue(); + }); +} + +kj::Promise evaluateImpl( + Calculator::Expression::Reader expression, + capnp::List::Reader params = capnp::List::Reader()) { + // Implementation of CalculatorImpl::evaluate(), also shared by + // FunctionImpl::call(). In the latter case, `params` are the parameter + // values passed to the function; in the former case, `params` is just an + // empty list. + + switch (expression.which()) { + case Calculator::Expression::LITERAL: + return expression.getLiteral(); + + case Calculator::Expression::PREVIOUS_RESULT: + return readValue(expression.getPreviousResult()); + + case Calculator::Expression::PARAMETER: { + KJ_REQUIRE(expression.getParameter() < params.size(), + "Parameter index out-of-range."); + return params[expression.getParameter()]; + } + + case Calculator::Expression::CALL: { + auto call = expression.getCall(); + auto func = call.getFunction(); + + // Evaluate each parameter. + kj::Array> paramPromises = + KJ_MAP(param, call.getParams()) { + return evaluateImpl(param, params); + }; + + // Join the array of promises into a promise for an array. + kj::Promise> joinedParams = + kj::joinPromises(kj::mv(paramPromises)); + + // When the parameters are complete, call the function. + return joinedParams.then([KJ_CPCAP(func)](kj::Array&& paramValues) mutable { + auto request = func.callRequest(); + request.setParams(paramValues); + return request.send().then( + [](capnp::Response&& result) { + return result.getValue(); + }); + }); + } + + default: + // Throw an exception. + KJ_FAIL_REQUIRE("Unknown expression type."); + } +} + +class ValueImpl final: public Calculator::Value::Server { + // Simple implementation of the Calculator.Value Cap'n Proto interface. + +public: + ValueImpl(double value): value(value) {} + + kj::Promise read(ReadContext context) { + context.getResults().setValue(value); + return kj::READY_NOW; + } + +private: + double value; +}; + +class FunctionImpl final: public Calculator::Function::Server { + // Implementation of the Calculator.Function Cap'n Proto interface, where the + // function is defined by a Calculator.Expression. + +public: + FunctionImpl(uint paramCount, Calculator::Expression::Reader body) + : paramCount(paramCount) { + this->body.setRoot(body); + } + + kj::Promise call(CallContext context) { + auto params = context.getParams().getParams(); + KJ_REQUIRE(params.size() == paramCount, "Wrong number of parameters."); + + return evaluateImpl(body.getRoot(), params) + .then([KJ_CPCAP(context)](double value) mutable { + context.getResults().setValue(value); + }); + } + +private: + uint paramCount; + // The function's arity. + + capnp::MallocMessageBuilder body; + // Stores a permanent copy of the function body. +}; + +class OperatorImpl final: public Calculator::Function::Server { + // Implementation of the Calculator.Function Cap'n Proto interface, wrapping + // basic binary arithmetic operators. + +public: + OperatorImpl(Calculator::Operator op): op(op) {} + + kj::Promise call(CallContext context) { + auto params = context.getParams().getParams(); + KJ_REQUIRE(params.size() == 2, "Wrong number of parameters."); + + double result; + switch (op) { + case Calculator::Operator::ADD: result = params[0] + params[1]; break; + case Calculator::Operator::SUBTRACT:result = params[0] - params[1]; break; + case Calculator::Operator::MULTIPLY:result = params[0] * params[1]; break; + case Calculator::Operator::DIVIDE: result = params[0] / params[1]; break; + default: + KJ_FAIL_REQUIRE("Unknown operator."); + } + + context.getResults().setValue(result); + return kj::READY_NOW; + } + +private: + Calculator::Operator op; +}; + +class CalculatorImpl final: public Calculator::Server { + // Implementation of the Calculator Cap'n Proto interface. + +public: + kj::Promise evaluate(EvaluateContext context) override { + return evaluateImpl(context.getParams().getExpression()) + .then([KJ_CPCAP(context)](double value) mutable { + context.getResults().setValue(kj::heap(value)); + }); + } + + kj::Promise defFunction(DefFunctionContext context) override { + auto params = context.getParams(); + context.getResults().setFunc(kj::heap( + params.getParamCount(), params.getBody())); + return kj::READY_NOW; + } + + kj::Promise getOperator(GetOperatorContext context) override { + context.getResults().setFunc(kj::heap( + context.getParams().getOp())); + return kj::READY_NOW; + } +}; + +int main(int argc, const char* argv[]) { + if (argc != 2) { + std::cerr << "usage: " << argv[0] << " ADDRESS[:PORT]\n" + "Runs the server bound to the given address/port.\n" + "ADDRESS may be '*' to bind to all local addresses.\n" + ":PORT may be omitted to choose a port automatically." << std::endl; + return 1; + } + + // Set up a server. + capnp::EzRpcServer server(kj::heap(), argv[1]); + + // Write the port number to stdout, in case it was chosen automatically. + auto& waitScope = server.getWaitScope(); + uint port = server.getPort().wait(waitScope); + if (port == 0) { + // The address format "unix:/path/to/socket" opens a unix domain socket, + // in which case the port will be zero. + std::cout << "Listening on Unix socket..." << std::endl; + } else { + std::cout << "Listening on port " << port << "..." << std::endl; + } + + // Run forever, accepting connections and handling requests. + kj::NEVER_DONE.wait(waitScope); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/calculator.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/calculator.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,118 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x85150b117366d14b; + +interface Calculator { + # A "simple" mathematical calculator, callable via RPC. + # + # But, to show off Cap'n Proto, we add some twists: + # + # - You can use the result from one call as the input to the next + # without a network round trip. To accomplish this, evaluate() + # returns a `Value` object wrapping the actual numeric value. + # This object may be used in a subsequent expression. With + # promise pipelining, the Value can actually be used before + # the evaluate() call that creates it returns! + # + # - You can define new functions, and then call them. This again + # shows off pipelining, but it also gives the client the + # opportunity to define a function on the client side and have + # the server call back to it. + # + # - The basic arithmetic operators are exposed as Functions, and + # you have to call getOperator() to obtain them from the server. + # This again demonstrates pipelining -- using getOperator() to + # get each operator and then using them in evaluate() still + # only takes one network round trip. + + evaluate @0 (expression :Expression) -> (value :Value); + # Evaluate the given expression and return the result. The + # result is returned wrapped in a Value interface so that you + # may pass it back to the server in a pipelined request. To + # actually get the numeric value, you must call read() on the + # Value -- but again, this can be pipelined so that it incurs + # no additional latency. + + struct Expression { + # A numeric expression. + + union { + literal @0 :Float64; + # A literal numeric value. + + previousResult @1 :Value; + # A value that was (or, will be) returned by a previous + # evaluate(). + + parameter @2 :UInt32; + # A parameter to the function (only valid in function bodies; + # see defFunction). + + call :group { + # Call a function on a list of parameters. + function @3 :Function; + params @4 :List(Expression); + } + } + } + + interface Value { + # Wraps a numeric value in an RPC object. This allows the value + # to be used in subsequent evaluate() requests without the client + # waiting for the evaluate() that returns the Value to finish. + + read @0 () -> (value :Float64); + # Read back the raw numeric value. + } + + defFunction @1 (paramCount :Int32, body :Expression) + -> (func :Function); + # Define a function that takes `paramCount` parameters and returns the + # evaluation of `body` after substituting these parameters. + + interface Function { + # An algebraic function. Can be called directly, or can be used inside + # an Expression. + # + # A client can create a Function that runs on the server side using + # `defFunction()` or `getOperator()`. Alternatively, a client can + # implement a Function on the client side and the server will call back + # to it. However, a function defined on the client side will require a + # network round trip whenever the server needs to call it, whereas + # functions defined on the server and then passed back to it are called + # locally. + + call @0 (params :List(Float64)) -> (value :Float64); + # Call the function on the given parameters. + } + + getOperator @2 (op :Operator) -> (func :Function); + # Get a Function representing an arithmetic operator, which can then be + # used in Expressions. + + enum Operator { + add @0; + subtract @1; + multiply @2; + divide @3; + } +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/samples/test.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/samples/test.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,26 @@ +#! /usr/bin/env bash +# +# Quick script that compiles and runs the samples, then cleans up. +# Used for release testing. + +set -exuo pipefail + +capnpc -oc++ addressbook.capnp +c++ -std=c++11 -Wall addressbook.c++ addressbook.capnp.c++ \ + $(pkg-config --cflags --libs capnp) -o addressbook +./addressbook write | ./addressbook read +./addressbook dwrite | ./addressbook dread +rm addressbook addressbook.capnp.c++ addressbook.capnp.h + +capnpc -oc++ calculator.capnp +c++ -std=c++11 -Wall calculator-client.c++ calculator.capnp.c++ \ + $(pkg-config --cflags --libs capnp-rpc) -o calculator-client +c++ -std=c++11 -Wall calculator-server.c++ calculator.capnp.c++ \ + $(pkg-config --cflags --libs capnp-rpc) -o calculator-server +rm -f /tmp/capnp-calculator-example-$$ +./calculator-server unix:/tmp/capnp-calculator-example-$$ & +sleep 0.1 +./calculator-client unix:/tmp/capnp-calculator-example-$$ +kill %+ +wait %+ || true +rm calculator-client calculator-server calculator.capnp.c++ calculator.capnp.h /tmp/capnp-calculator-example-$$ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/setup-autotools.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/setup-autotools.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +set -euo pipefail + +echo "This script is no longer needed. Go ahead and run autoreconf. For example:" +echo " autoreconf -i && ./configure && make -j6 check && sudo make install" diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/setup-ekam.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/setup-ekam.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,94 @@ +#! /usr/bin/env bash + +set -euo pipefail + +if ! uname | grep -iq Linux; then + echo "Sorry, Ekam only works on Linux right now." >&2 + exit 1 +fi + +echo -n "Looking for compiler... " +if [ "x${CXX:-}" == "x" ]; then + if ! (g++ --version | grep -q ' 4[.][789][.]'); then + if which g++-4.7 > /dev/null; then + CXX=g++-4.7 + elif which g++-4.8 > /dev/null; then + CXX=g++-4.8 + else + echo "none" + echo "Please install G++ 4.7 or better. Or, set the environment variable CXX " >&2 + echo "to a compiler that you think will work." >&2 + exit 1 + fi + else + CXX=g++ + fi +fi + +echo "$CXX" +export CXX + +if [ ! -e .ekam ]; then + echo "================================================================================" + echo "Fetching Ekam and Protobuf code..." + echo "================================================================================" + hg clone https://code.google.com/p/kentons-code/ .ekam + + # You don't want these. + rm -rf .ekam/src/modc .ekam/src/evlan +fi + +if [ ! -e .ekam/src/protobuf ]; then + echo "================================================================================" + echo "Fetching Protobuf code..." + echo "================================================================================" + svn checkout http://protobuf.googlecode.com/svn/tags/2.5.0/ .ekam/src/protobuf +fi + +if [ ! -e .ekam/src/protobuf/src/config.h ]; then + echo "================================================================================" + echo "Configuring Protobuf..." + echo "================================================================================" + pushd .ekam/src/protobuf > /dev/null + ./autogen.sh + ./configure + cp config.h src + make maintainer-clean + popd +fi + +if ! which ekam > /dev/null; then + if [ ! -e .ekam/bin/ekam ]; then + echo "================================================================================" + echo "Bootstrapping Ekam..." + echo "================================================================================" + pushd .ekam > /dev/null + ./bootstrap.sh + popd + fi +else + echo "================================================================================" + echo "Using already-installed ekam binary: $(which ekam)" + echo "================================================================================" +fi + +if [ ! -e src/base ]; then + ln -s ../.ekam/src/base src/base +fi +if [ ! -e src/os ]; then + ln -s ../.ekam/src/os src/os +fi +if [ ! -e src/ekam ]; then + ln -s ../.ekam/src/ekam src/ekam +fi +if [ ! -e src/protobuf ]; then + ln -s ../.ekam/src/protobuf src/protobuf +fi + +echo "================================================================================" +echo "All done..." +echo "================================================================================" +echo "Try:" +echo " make -f Makefile.ekam once" +echo " make -f Makefile.ekam continuous" +echo " make -f Makefile.ekam continuous-opt" diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/CMakeLists.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,52 @@ + +# Tests ======================================================================== + +if(BUILD_TESTING) + include(CTest) + + if (EXTERNAL_CAPNP) + # Setup CAPNP_GENERATE_CPP for compiling test schemas + find_package(CapnProto CONFIG QUIET) + if (NOT CapnProto_FOUND) + # Try and find the executables from an autotools-based installation + # Setup paths to the schema compiler for generating ${test_capnp_files} + if(NOT EXTERNAL_CAPNP AND NOT CAPNP_LITE) + set(CAPNP_EXECUTABLE $) + set(CAPNPC_CXX_EXECUTABLE $) + else() + # Allow paths to tools to be set with either environment variables or find_program() + if (NOT CAPNP_EXECUTABLE) + if (DEFINED ENV{CAPNP}) + set(CAPNP_EXECUTABLE "$ENV{CAPNP}") + else() + find_program(CAPNP_EXECUTABLE capnp) + endif() + endif() + + if(NOT CAPNPC_CXX_EXECUTABLE) + if (DEFINED ENV{CAPNPC_CXX}) + set(CAPNPC_CXX_EXECUTABLE "$ENV{CAPNPC_CXX}") + else() + # Also search in the same directory that `capnp` was found in + get_filename_component(capnp_dir "${CAPNP_EXECUTABLE}" DIRECTORY) + find_program(CAPNPC_CXX_EXECUTABLE capnpc-c++ HINTS "${capnp_dir}") + endif() + endif() + endif() + endif() + + set(CAPNP_INCLUDE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + #TODO(someday) It would be nice to use targets instead of variables in CAPNP_GENERATE_CPP macro + endif() + + # Sadly, we can't use the 'test' target, as that's coopted by ctest + add_custom_target(check "${CMAKE_CTEST_COMMAND}" -V) +endif() # BUILD_TESTING + +# kj =========================================================================== + +add_subdirectory(kj) + +# capnp ======================================================================== + +add_subdirectory(capnp) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/capnproto-carsales.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/capnproto-carsales.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,139 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "carsales.capnp.h" +#include "capnproto-common.h" + +namespace capnp { +namespace benchmark { +namespace capnp { + +template +uint64_t carValue(ReaderOrBuilder car) { + // Do not think too hard about realism. + + uint64_t result = 0; + + result += car.getSeats() * 200; + result += car.getDoors() * 350; + for (auto wheel: car.getWheels()) { + result += wheel.getDiameter() * wheel.getDiameter(); + result += wheel.getSnowTires() ? 100 : 0; + } + + result += car.getLength() * car.getWidth() * car.getHeight() / 50; + + auto engine = car.getEngine(); + result += engine.getHorsepower() * 40; + if (engine.getUsesElectric()) { + if (engine.getUsesGas()) { + // hybrid + result += 5000; + } else { + result += 3000; + } + } + + result += car.getHasPowerWindows() ? 100 : 0; + result += car.getHasPowerSteering() ? 200 : 0; + result += car.getHasCruiseControl() ? 400 : 0; + result += car.getHasNavSystem() ? 2000 : 0; + + result += car.getCupHolders() * 25; + + return result; +} + +void randomCar(Car::Builder car) { + // Do not think too hard about realism. + + static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" }; + static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" }; + + car.setMake(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]); + car.setModel(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]); + + car.setColor((Color)fastRand((uint)Color::SILVER + 1)); + car.setSeats(2 + fastRand(6)); + car.setDoors(2 + fastRand(3)); + + for (auto wheel: car.initWheels(4)) { + wheel.setDiameter(25 + fastRand(15)); + wheel.setAirPressure(30 + fastRandDouble(20)); + wheel.setSnowTires(fastRand(16) == 0); + } + + car.setLength(170 + fastRand(150)); + car.setWidth(48 + fastRand(36)); + car.setHeight(54 + fastRand(48)); + car.setWeight(car.getLength() * car.getWidth() * car.getHeight() / 200); + + auto engine = car.initEngine(); + engine.setHorsepower(100 * fastRand(400)); + engine.setCylinders(4 + 2 * fastRand(3)); + engine.setCc(800 + fastRand(10000)); + engine.setUsesGas(true); + engine.setUsesElectric(fastRand(2)); + + car.setFuelCapacity(10.0 + fastRandDouble(30.0)); + car.setFuelLevel(fastRandDouble(car.getFuelCapacity())); + car.setHasPowerWindows(fastRand(2)); + car.setHasPowerSteering(fastRand(2)); + car.setHasCruiseControl(fastRand(2)); + car.setCupHolders(fastRand(12)); + car.setHasNavSystem(fastRand(2)); +} + +class CarSalesTestCase { +public: + typedef ParkingLot Request; + typedef TotalValue Response; + typedef uint64_t Expectation; + + static uint64_t setupRequest(ParkingLot::Builder request) { + uint64_t result = 0; + for (auto car: request.initCars(fastRand(200))) { + randomCar(car); + result += carValue(car); + } + return result; + } + static void handleRequest(ParkingLot::Reader request, TotalValue::Builder response) { + uint64_t result = 0; + for (auto car: request.getCars()) { + result += carValue(car); + } + response.setAmount(result); + } + static inline bool checkResponse(TotalValue::Reader response, uint64_t expected) { + return response.getAmount() == expected; + } +}; + +} // namespace capnp +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::capnp::BenchmarkTypes, + capnp::benchmark::capnp::CarSalesTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/capnproto-catrank.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/capnproto-catrank.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,141 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "catrank.capnp.h" +#include "capnproto-common.h" + +namespace capnp { +namespace benchmark { +namespace capnp { + +struct ScoredResult { + double score; + SearchResult::Reader result; + + ScoredResult() = default; + ScoredResult(double score, SearchResult::Reader result): score(score), result(result) {} + + inline bool operator<(const ScoredResult& other) const { return score > other.score; } +}; + +class CatRankTestCase { +public: + typedef SearchResultList Request; + typedef SearchResultList Response; + typedef int Expectation; + + static int setupRequest(SearchResultList::Builder request) { + int count = fastRand(1000); + int goodCount = 0; + + auto list = request.initResults(count); + + for (int i = 0; i < count; i++) { + SearchResult::Builder result = list[i]; + result.setScore(1000 - i); + int urlSize = fastRand(100); + + static const char URL_PREFIX[] = "http://example.com/"; + size_t urlPrefixLength = strlen(URL_PREFIX); + auto url = result.initUrl(urlSize + urlPrefixLength); + + strcpy(url.begin(), URL_PREFIX); + char* pos = url.begin() + urlPrefixLength; + for (int j = 0; j < urlSize; j++) { + *pos++ = 'a' + fastRand(26); + } + + bool isCat = fastRand(8) == 0; + bool isDog = fastRand(8) == 0; + goodCount += isCat && !isDog; + + static std::string snippet; + snippet.clear(); + snippet.push_back(' '); + + int prefix = fastRand(20); + for (int j = 0; j < prefix; j++) { + snippet.append(WORDS[fastRand(WORDS_COUNT)]); + } + + if (isCat) snippet.append("cat "); + if (isDog) snippet.append("dog "); + + int suffix = fastRand(20); + for (int j = 0; j < suffix; j++) { + snippet.append(WORDS[fastRand(WORDS_COUNT)]); + } + + result.setSnippet(Text::Reader(snippet.c_str(), snippet.size())); + } + + return goodCount; + } + + static void handleRequest(SearchResultList::Reader request, SearchResultList::Builder response) { + std::vector scoredResults; + + for (auto result: request.getResults()) { + double score = result.getScore(); + if (strstr(result.getSnippet().cStr(), " cat ") != nullptr) { + score *= 10000; + } + if (strstr(result.getSnippet().cStr(), " dog ") != nullptr) { + score /= 10000; + } + scoredResults.emplace_back(score, result); + } + + std::sort(scoredResults.begin(), scoredResults.end()); + + auto list = response.initResults(scoredResults.size()); + auto iter = list.begin(); + for (auto result: scoredResults) { + iter->setScore(result.score); + iter->setUrl(result.result.getUrl()); + iter->setSnippet(result.result.getSnippet()); + ++iter; + } + } + + static bool checkResponse(SearchResultList::Reader response, int expectedGoodCount) { + int goodCount = 0; + for (auto result: response.getResults()) { + if (result.getScore() > 1001) { + ++goodCount; + } else { + break; + } + } + + return goodCount == expectedGoodCount; + } +}; + +} // namespace capnp +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::capnp::BenchmarkTypes, + capnp::benchmark::capnp::CatRankTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/capnproto-common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/capnproto-common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,423 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_BENCHMARK_CAPNP_COMMON_H_ +#define CAPNP_BENCHMARK_CAPNP_COMMON_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" +#include +#include +#include +#if HAVE_SNAPPY +#include +#endif // HAVE_SNAPPY +#include + +namespace capnp { +namespace benchmark { +namespace capnp { + +class CountingOutputStream: public kj::FdOutputStream { +public: + CountingOutputStream(int fd): FdOutputStream(fd), throughput(0) {} + + uint64_t throughput; + + void write(const void* buffer, size_t size) override { + FdOutputStream::write(buffer, size); + throughput += size; + } + + void write(kj::ArrayPtr> pieces) override { + FdOutputStream::write(pieces); + for (auto& piece: pieces) { + throughput += piece.size(); + } + } +}; + +// ======================================================================================= + +struct Uncompressed { + typedef kj::FdInputStream& BufferedInput; + typedef InputStreamMessageReader MessageReader; + + class ArrayMessageReader: public FlatArrayMessageReader { + public: + ArrayMessageReader(kj::ArrayPtr array, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : FlatArrayMessageReader(kj::arrayPtr( + reinterpret_cast(array.begin()), + reinterpret_cast(array.end())), options) {} + }; + + static inline void write(kj::OutputStream& output, MessageBuilder& builder) { + writeMessage(output, builder); + } +}; + +struct Packed { + typedef kj::BufferedInputStreamWrapper BufferedInput; + typedef PackedMessageReader MessageReader; + + class ArrayMessageReader: private kj::ArrayInputStream, public PackedMessageReader { + public: + ArrayMessageReader(kj::ArrayPtr array, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : ArrayInputStream(array), + PackedMessageReader(*this, options, scratchSpace) {} + }; + + static inline void write(kj::OutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder); + } + + static inline void write(kj::BufferedOutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder); + } +}; + +#if HAVE_SNAPPY +static byte snappyReadBuffer[SNAPPY_BUFFER_SIZE]; +static byte snappyWriteBuffer[SNAPPY_BUFFER_SIZE]; +static byte snappyCompressedBuffer[SNAPPY_COMPRESSED_BUFFER_SIZE]; + +struct SnappyCompressed { + typedef BufferedInputStreamWrapper BufferedInput; + typedef SnappyPackedMessageReader MessageReader; + + class ArrayMessageReader: private ArrayInputStream, public SnappyPackedMessageReader { + public: + ArrayMessageReader(kj::ArrayPtr array, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : ArrayInputStream(array), + SnappyPackedMessageReader(static_cast(*this), options, scratchSpace, + kj::arrayPtr(snappyReadBuffer, SNAPPY_BUFFER_SIZE)) {} + }; + + static inline void write(OutputStream& output, MessageBuilder& builder) { + writeSnappyPackedMessage(output, builder, + kj::arrayPtr(snappyWriteBuffer, SNAPPY_BUFFER_SIZE), + kj::arrayPtr(snappyCompressedBuffer, SNAPPY_COMPRESSED_BUFFER_SIZE)); + } +}; +#endif // HAVE_SNAPPY + +// ======================================================================================= + +struct NoScratch { + struct ScratchSpace {}; + + template + class MessageReader: public Compression::MessageReader { + public: + inline MessageReader(typename Compression::BufferedInput& input, ScratchSpace& scratch) + : Compression::MessageReader(input) {} + }; + + template + class ArrayMessageReader: public Compression::ArrayMessageReader { + public: + inline ArrayMessageReader(kj::ArrayPtr input, ScratchSpace& scratch) + : Compression::ArrayMessageReader(input) {} + }; + + class MessageBuilder: public MallocMessageBuilder { + public: + inline MessageBuilder(ScratchSpace& scratch): MallocMessageBuilder() {} + }; + + class ObjectSizeCounter { + public: + ObjectSizeCounter(uint64_t iters): counter(0) {} + + template + void add(RequestBuilder& request, ResponseBuilder& response) { + for (auto segment: request.getSegmentsForOutput()) { + counter += segment.size() * sizeof(word); + } + for (auto segment: response.getSegmentsForOutput()) { + counter += segment.size() * sizeof(word); + } + } + + uint64_t get() { return counter; } + + private: + uint64_t counter; + }; +}; + +constexpr size_t SCRATCH_SIZE = 128 * 1024; +word scratchSpace[6 * SCRATCH_SIZE]; +int scratchCounter = 0; + +struct UseScratch { + struct ScratchSpace { + word* words; + + ScratchSpace() { + KJ_REQUIRE(scratchCounter < 6, "Too many scratch spaces needed at once."); + words = scratchSpace + scratchCounter++ * SCRATCH_SIZE; + } + ~ScratchSpace() noexcept { + --scratchCounter; + } + }; + + template + class MessageReader: public Compression::MessageReader { + public: + inline MessageReader(typename Compression::BufferedInput& input, ScratchSpace& scratch) + : Compression::MessageReader( + input, ReaderOptions(), kj::arrayPtr(scratch.words, SCRATCH_SIZE)) {} + }; + + template + class ArrayMessageReader: public Compression::ArrayMessageReader { + public: + inline ArrayMessageReader(kj::ArrayPtr input, ScratchSpace& scratch) + : Compression::ArrayMessageReader( + input, ReaderOptions(), kj::arrayPtr(scratch.words, SCRATCH_SIZE)) {} + }; + + class MessageBuilder: public MallocMessageBuilder { + public: + inline MessageBuilder(ScratchSpace& scratch) + : MallocMessageBuilder(kj::arrayPtr(scratch.words, SCRATCH_SIZE)) {} + }; + + class ObjectSizeCounter { + public: + ObjectSizeCounter(uint64_t iters): iters(iters), maxSize(0) {} + + template + void add(RequestBuilder& request, ResponseBuilder& response) { + size_t counter = 0; + for (auto segment: request.getSegmentsForOutput()) { + counter += segment.size() * sizeof(word); + } + for (auto segment: response.getSegmentsForOutput()) { + counter += segment.size() * sizeof(word); + } + maxSize = std::max(counter, maxSize); + } + + uint64_t get() { return iters * maxSize; } + + private: + uint64_t iters; + size_t maxSize; + }; +}; + +// ======================================================================================= + +template +struct BenchmarkMethods { + static uint64_t syncClient(int inputFd, int outputFd, uint64_t iters) { + kj::FdInputStream inputStream(inputFd); + typename Compression::BufferedInput bufferedInput(inputStream); + + CountingOutputStream output(outputFd); + typename ReuseStrategy::ScratchSpace builderScratch; + typename ReuseStrategy::ScratchSpace readerScratch; + + for (; iters > 0; --iters) { + typename TestCase::Expectation expected; + { + typename ReuseStrategy::MessageBuilder builder(builderScratch); + expected = TestCase::setupRequest( + builder.template initRoot()); + Compression::write(output, builder); + } + + { + typename ReuseStrategy::template MessageReader reader( + bufferedInput, readerScratch); + if (!TestCase::checkResponse( + reader.template getRoot(), expected)) { + throw std::logic_error("Incorrect response."); + } + } + } + + return output.throughput; + } + + static uint64_t asyncClientSender( + int outputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + CountingOutputStream output(outputFd); + typename ReuseStrategy::ScratchSpace scratch; + + for (; iters > 0; --iters) { + typename ReuseStrategy::MessageBuilder builder(scratch); + expectations->post(TestCase::setupRequest( + builder.template initRoot())); + Compression::write(output, builder); + } + + return output.throughput; + } + + static void asyncClientReceiver( + int inputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + kj::FdInputStream inputStream(inputFd); + typename Compression::BufferedInput bufferedInput(inputStream); + + typename ReuseStrategy::ScratchSpace scratch; + + for (; iters > 0; --iters) { + typename TestCase::Expectation expected = expectations->next(); + typename ReuseStrategy::template MessageReader reader(bufferedInput, scratch); + if (!TestCase::checkResponse( + reader.template getRoot(), expected)) { + throw std::logic_error("Incorrect response."); + } + } + } + + static uint64_t asyncClient(int inputFd, int outputFd, uint64_t iters) { + ProducerConsumerQueue expectations; + std::thread receiverThread(asyncClientReceiver, inputFd, &expectations, iters); + uint64_t throughput = asyncClientSender(outputFd, &expectations, iters); + receiverThread.join(); + return throughput; + } + + static uint64_t server(int inputFd, int outputFd, uint64_t iters) { + kj::FdInputStream inputStream(inputFd); + typename Compression::BufferedInput bufferedInput(inputStream); + + CountingOutputStream output(outputFd); + typename ReuseStrategy::ScratchSpace builderScratch; + typename ReuseStrategy::ScratchSpace readerScratch; + + for (; iters > 0; --iters) { + typename ReuseStrategy::MessageBuilder builder(builderScratch); + typename ReuseStrategy::template MessageReader reader( + bufferedInput, readerScratch); + TestCase::handleRequest(reader.template getRoot(), + builder.template initRoot()); + Compression::write(output, builder); + } + + return output.throughput; + } + + static uint64_t passByObject(uint64_t iters, bool countObjectSize) { + typename ReuseStrategy::ScratchSpace requestScratch; + typename ReuseStrategy::ScratchSpace responseScratch; + + typename ReuseStrategy::ObjectSizeCounter counter(iters); + + for (; iters > 0; --iters) { + typename ReuseStrategy::MessageBuilder requestMessage(requestScratch); + auto request = requestMessage.template initRoot(); + typename TestCase::Expectation expected = TestCase::setupRequest(request); + + typename ReuseStrategy::MessageBuilder responseMessage(responseScratch); + auto response = responseMessage.template initRoot(); + TestCase::handleRequest(request.asReader(), response); + + if (!TestCase::checkResponse(response.asReader(), expected)) { + throw std::logic_error("Incorrect response."); + } + + if (countObjectSize) { + counter.add(requestMessage, responseMessage); + } + } + + return counter.get(); + } + + static uint64_t passByBytes(uint64_t iters) { + uint64_t throughput = 0; + typename ReuseStrategy::ScratchSpace clientRequestScratch; + UseScratch::ScratchSpace requestBytesScratch; + typename ReuseStrategy::ScratchSpace serverRequestScratch; + typename ReuseStrategy::ScratchSpace serverResponseScratch; + UseScratch::ScratchSpace responseBytesScratch; + typename ReuseStrategy::ScratchSpace clientResponseScratch; + + for (; iters > 0; --iters) { + typename ReuseStrategy::MessageBuilder requestBuilder(clientRequestScratch); + typename TestCase::Expectation expected = TestCase::setupRequest( + requestBuilder.template initRoot()); + + kj::ArrayOutputStream requestOutput(kj::arrayPtr( + reinterpret_cast(requestBytesScratch.words), SCRATCH_SIZE * sizeof(word))); + Compression::write(requestOutput, requestBuilder); + throughput += requestOutput.getArray().size(); + typename ReuseStrategy::template ArrayMessageReader requestReader( + requestOutput.getArray(), serverRequestScratch); + + typename ReuseStrategy::MessageBuilder responseBuilder(serverResponseScratch); + TestCase::handleRequest(requestReader.template getRoot(), + responseBuilder.template initRoot()); + + kj::ArrayOutputStream responseOutput( + kj::arrayPtr(reinterpret_cast(responseBytesScratch.words), + SCRATCH_SIZE * sizeof(word))); + Compression::write(responseOutput, responseBuilder); + throughput += responseOutput.getArray().size(); + typename ReuseStrategy::template ArrayMessageReader responseReader( + responseOutput.getArray(), clientResponseScratch); + + if (!TestCase::checkResponse( + responseReader.template getRoot(), expected)) { + throw std::logic_error("Incorrect response."); + } + } + + return throughput; + } +}; + +struct BenchmarkTypes { + typedef capnp::Uncompressed Uncompressed; + typedef capnp::Packed Packed; +#if HAVE_SNAPPY + typedef capnp::SnappyCompressed SnappyCompressed; +#endif // HAVE_SNAPPY + + typedef capnp::UseScratch ReusableResources; + typedef capnp::NoScratch SingleUseResources; + + template + struct BenchmarkMethods: public capnp::BenchmarkMethods {}; +}; + +} // namespace capnp +} // namespace benchmark +} // namespace capnp + +#endif // CAPNP_BENCHMARK_CAPNP_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/capnproto-eval.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/capnproto-eval.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,124 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "eval.capnp.h" +#include "capnproto-common.h" + +namespace capnp { +namespace benchmark { +namespace capnp { + +int32_t makeExpression(Expression::Builder exp, uint depth) { + exp.setOp((Operation)(fastRand((int)Operation::MODULUS + 1))); + + uint32_t left, right; + + if (fastRand(8) < depth) { + left = fastRand(128) + 1; + exp.getLeft().setValue(left); + } else { + left = makeExpression(exp.getLeft().initExpression(), depth + 1); + } + + if (fastRand(8) < depth) { + right = fastRand(128) + 1; + exp.getRight().setValue(right); + } else { + right = makeExpression(exp.getRight().initExpression(), depth + 1); + } + + switch (exp.getOp()) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +int32_t evaluateExpression(Expression::Reader exp) { + int32_t left = 0, right = 0; + + switch (exp.getLeft().which()) { + case Expression::Left::VALUE: + left = exp.getLeft().getValue(); + break; + case Expression::Left::EXPRESSION: + left = evaluateExpression(exp.getLeft().getExpression()); + break; + } + + switch (exp.getRight().which()) { + case Expression::Right::VALUE: + right = exp.getRight().getValue(); + break; + case Expression::Right::EXPRESSION: + right = evaluateExpression(exp.getRight().getExpression()); + break; + } + + switch (exp.getOp()) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +class ExpressionTestCase { +public: + typedef Expression Request; + typedef EvaluationResult Response; + typedef int32_t Expectation; + + static inline int32_t setupRequest(Expression::Builder request) { + return makeExpression(request, 0); + } + static inline void handleRequest(Expression::Reader request, EvaluationResult::Builder response) { + response.setValue(evaluateExpression(request)); + } + static inline bool checkResponse(EvaluationResult::Reader response, int32_t expected) { + return response.getValue() == expected; + } +}; + +} // namespace capnp +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::capnp::BenchmarkTypes, + capnp::benchmark::capnp::ExpressionTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/carsales.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/carsales.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,80 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +using Cxx = import "/capnp/c++.capnp"; + +@0xff75ddc6a36723c9; +$Cxx.namespace("capnp::benchmark::capnp"); + +struct ParkingLot { + cars@0: List(Car); +} + +struct TotalValue { + amount@0: UInt64; +} + +struct Car { + make@0: Text; + model@1: Text; + color@2: Color; + seats@3: UInt8; + doors@4: UInt8; + wheels@5: List(Wheel); + length@6: UInt16; + width@7: UInt16; + height@8: UInt16; + weight@9: UInt32; + engine@10: Engine; + fuelCapacity@11: Float32; + fuelLevel@12: Float32; + hasPowerWindows@13: Bool; + hasPowerSteering@14: Bool; + hasCruiseControl@15: Bool; + cupHolders@16: UInt8; + hasNavSystem@17: Bool; +} + +enum Color { + black @0; + white @1; + red @2; + green @3; + blue @4; + cyan @5; + magenta @6; + yellow @7; + silver @8; +} + +struct Wheel { + diameter@0: UInt16; + airPressure@1: Float32; + snowTires@2: Bool; +} + +struct Engine { + horsepower@0: UInt16; + cylinders@1: UInt8; + cc@2: UInt32; + usesGas@3: Bool; + usesElectric@4: Bool; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/carsales.proto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/carsales.proto Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,77 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package capnp.benchmark.protobuf; + +message ParkingLot { + repeated Car car = 1; +} + +message TotalValue { + required uint64 amount = 1; +} + +message Car { + optional string make = 1; + optional string model = 2; + optional Color color = 3; + optional uint32 seats = 4; + optional uint32 doors = 5; + repeated Wheel wheel = 6; + optional uint32 length = 7; + optional uint32 width = 8; + optional uint32 height = 9; + optional uint32 weight = 10; + optional Engine engine = 11; + optional float fuel_capacity = 12; + optional float fuel_level = 13; + optional bool has_power_windows = 14; + optional bool has_power_steering = 15; + optional bool has_cruise_control = 16; + optional uint32 cup_holders = 17; + optional bool has_nav_system = 18; +} + +enum Color { + BLACK = 0; + WHITE = 1; + RED = 2; + GREEN = 3; + BLUE = 4; + CYAN = 5; + MAGENTA = 6; + YELLOW = 7; + SILVER = 8; +} + +message Wheel { + optional uint32 diameter = 1; + optional float air_pressure = 2; + optional bool snow_tires = 3; +} + +message Engine { + optional uint32 horsepower = 1; + optional uint32 cylinders = 2; + optional uint32 cc = 3; + optional bool uses_gas = 4; + optional bool uses_electric = 5; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/catrank.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/catrank.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,35 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +using Cxx = import "/capnp/c++.capnp"; + +@0x82beb8e37ff79aba; +$Cxx.namespace("capnp::benchmark::capnp"); + +struct SearchResultList { + results@0: List(SearchResult); +} + +struct SearchResult { + url@0: Text; + score@1: Float64; + snippet@2: Text; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/catrank.proto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/catrank.proto Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,32 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package capnp.benchmark.protobuf; + +message SearchResultList { + repeated SearchResult result = 1; +} + +message SearchResult { + optional string url = 1; + optional double score = 2; + optional string snippet = 3; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,297 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_BENCHMARK_COMMON_H_ +#define CAPNP_BENCHMARK_COMMON_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace capnp { +namespace benchmark { + +// Use a 128-bit Xorshift algorithm. +static inline uint32_t nextFastRand() { + // These values are arbitrary. Any seed other than all zeroes is OK. + static uint32_t x = 0x1d2acd47; + static uint32_t y = 0x58ca3e14; + static uint32_t z = 0xf563f232; + static uint32_t w = 0x0bc76199; + + uint32_t tmp = x ^ (x << 11); + x = y; + y = z; + z = w; + w = w ^ (w >> 19) ^ tmp ^ (tmp >> 8); + return w; +} + +static inline uint32_t fastRand(uint32_t range) { + return nextFastRand() % range; +} + +static inline double fastRandDouble(double range) { + return nextFastRand() * range / std::numeric_limits::max(); +} + +inline int32_t div(int32_t a, int32_t b) { + if (b == 0) return std::numeric_limits::max(); + // INT_MIN / -1 => SIGFPE. Who knew? + if (a == std::numeric_limits::min() && b == -1) { + return std::numeric_limits::max(); + } + return a / b; +} + +inline int32_t mod(int32_t a, int32_t b) { + if (b == 0) return std::numeric_limits::max(); + // INT_MIN % -1 => SIGFPE. Who knew? + if (a == std::numeric_limits::min() && b == -1) { + return std::numeric_limits::max(); + } + return a % b; +} + +static const char* const WORDS[] = { + "foo ", "bar ", "baz ", "qux ", "quux ", "corge ", "grault ", "garply ", "waldo ", "fred ", + "plugh ", "xyzzy ", "thud " +}; +constexpr size_t WORDS_COUNT = sizeof(WORDS) / sizeof(WORDS[0]); + +template +class ProducerConsumerQueue { +public: + ProducerConsumerQueue() { + front = new Node; + back = front; + sem_init(&semaphore, 0, 0); + } + + ~ProducerConsumerQueue() noexcept(false) { + while (front != nullptr) { + Node* oldFront = front; + front = front->next; + delete oldFront; + } + sem_destroy(&semaphore); + } + + void post(T t) { + back->next = new Node(t); + back = back->next; + sem_post(&semaphore); + } + + T next() { + sem_wait(&semaphore); + Node* oldFront = front; + front = front->next; + delete oldFront; + return front->value; + } + +private: + struct Node { + T value; + Node* next; + + Node(): next(nullptr) {} + Node(T value): value(value), next(nullptr) {} + }; + + Node* front; // Last node that has been consumed. + Node* back; // Last node in list. + sem_t semaphore; +}; + +// TODO(cleanup): Use SYSCALL(), get rid of this exception class. +class OsException: public std::exception { +public: + OsException(int error): error(error) {} + ~OsException() noexcept {} + + const char* what() const noexcept override { + return strerror(error); + } + +private: + int error; +}; + +static void writeAll(int fd, const void* buffer, size_t size) { + const char* pos = reinterpret_cast(buffer); + while (size > 0) { + ssize_t n = write(fd, pos, size); + if (n <= 0) { + throw OsException(errno); + } + pos += n; + size -= n; + } +} + +static void readAll(int fd, void* buffer, size_t size) { + char* pos = reinterpret_cast(buffer); + while (size > 0) { + ssize_t n = read(fd, pos, size); + if (n <= 0) { + throw OsException(errno); + } + pos += n; + size -= n; + } +} + +template +uint64_t passByPipe(Func&& clientFunc, uint64_t iters) { + int clientToServer[2]; + int serverToClient[2]; + if (pipe(clientToServer) < 0) throw OsException(errno); + if (pipe(serverToClient) < 0) throw OsException(errno); + + pid_t child = fork(); + if (child == 0) { + // Client. + close(clientToServer[0]); + close(serverToClient[1]); + + uint64_t throughput = clientFunc(serverToClient[0], clientToServer[1], iters); + writeAll(clientToServer[1], &throughput, sizeof(throughput)); + + exit(0); + } else { + // Server. + close(clientToServer[1]); + close(serverToClient[0]); + + uint64_t throughput = BenchmarkMethods::server(clientToServer[0], serverToClient[1], iters); + + uint64_t clientThroughput = 0; + readAll(clientToServer[0], &clientThroughput, sizeof(clientThroughput)); + throughput += clientThroughput; + + int status; + if (waitpid(child, &status, 0) != child) { + throw OsException(errno); + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + throw std::logic_error("Child exited abnormally."); + } + + return throughput; + } +} + +template +uint64_t doBenchmark(const std::string& mode, uint64_t iters) { + typedef typename BenchmarkTypes::template BenchmarkMethods + BenchmarkMethods; + if (mode == "client") { + return BenchmarkMethods::syncClient(STDIN_FILENO, STDOUT_FILENO, iters); + } else if (mode == "server") { + return BenchmarkMethods::server(STDIN_FILENO, STDOUT_FILENO, iters); + } else if (mode == "object") { + return BenchmarkMethods::passByObject(iters, false); + } else if (mode == "object-size") { + return BenchmarkMethods::passByObject(iters, true); + } else if (mode == "bytes") { + return BenchmarkMethods::passByBytes(iters); + } else if (mode == "pipe") { + return passByPipe(BenchmarkMethods::syncClient, iters); + } else if (mode == "pipe-async") { + return passByPipe(BenchmarkMethods::asyncClient, iters); + } else { + fprintf(stderr, "Unknown mode: %s\n", mode.c_str()); + exit(1); + } +} + +template +uint64_t doBenchmark2(const std::string& mode, const std::string& reuse, uint64_t iters) { + if (reuse == "reuse") { + return doBenchmark< + BenchmarkTypes, TestCase, typename BenchmarkTypes::ReusableResources, Compression>( + mode, iters); + } else if (reuse == "no-reuse") { + return doBenchmark< + BenchmarkTypes, TestCase, typename BenchmarkTypes::SingleUseResources, Compression>( + mode, iters); + } else { + fprintf(stderr, "Unknown reuse mode: %s\n", reuse.c_str()); + exit(1); + } +} + +template +uint64_t doBenchmark3(const std::string& mode, const std::string& reuse, + const std::string& compression, uint64_t iters) { + if (compression == "none") { + return doBenchmark2( + mode, reuse, iters); + } else if (compression == "packed") { + return doBenchmark2( + mode, reuse, iters); +#if HAVE_SNAPPY + } else if (compression == "snappy") { + return doBenchmark2( + mode, reuse, iters); +#endif // HAVE_SNAPPY + } else { + fprintf(stderr, "Unknown compression mode: %s\n", compression.c_str()); + exit(1); + } +} + +template +int benchmarkMain(int argc, char* argv[]) { + if (argc != 5) { + fprintf(stderr, "USAGE: %s MODE REUSE COMPRESSION ITERATION_COUNT\n", argv[0]); + return 1; + } + + uint64_t iters = strtoull(argv[4], nullptr, 0); + uint64_t throughput = doBenchmark3(argv[1], argv[2], argv[3], iters); + fprintf(stdout, "%llu\n", (long long unsigned int)throughput); + + return 0; +} + +} // namespace capnp +} // namespace benchmark + +#endif // CAPNP_BENCHMARK_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/eval.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/eval.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,51 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +using Cxx = import "/capnp/c++.capnp"; + +@0xe12dc4c3e70e9eda; +$Cxx.namespace("capnp::benchmark::capnp"); + +enum Operation { + add @0; + subtract @1; + multiply @2; + divide @3; + modulus @4; +} + +struct Expression { + op@0: Operation; + + left :union { + value@1: Int32; + expression@2: Expression; + } + + right :union { + value@3: Int32; + expression@4: Expression; + } +} + +struct EvaluationResult { + value@0: Int32; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/eval.proto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/eval.proto Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,44 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package capnp.benchmark.protobuf; + +enum Operation { + ADD = 0; + SUBTRACT = 1; + MULTIPLY = 2; + DIVIDE = 3; + MODULUS = 4; +} + +message Expression { + required Operation op = 1; + + optional int32 left_value = 2; + optional Expression left_expression = 3; + + optional int32 right_value = 4; + optional Expression right_expression = 5; +} + +message EvaluationResult { + required sint32 value = 1; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/null-carsales.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/null-carsales.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,201 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "null-common.h" + +namespace capnp { +namespace benchmark { +namespace null { + +enum class Color: uint8_t { + BLACK, + WHITE, + RED, + GREEN, + BLUE, + CYAN, + MAGENTA, + YELLOW, + SILVER +}; +constexpr uint COLOR_RANGE = static_cast(Color::SILVER) + 1; + +struct Wheel { + float airPressure; + uint16_t diameter; + bool snowTires; +}; + +struct Engine { + uint32_t cc; + uint16_t horsepower; + uint8_t cylinders; + uint8_t bits; + inline bool usesGas() const { return bits & 1; } + inline bool usesElectric() const { return bits & 2; } + + inline void setBits(bool usesGas, bool usesElectric) { + bits = (uint8_t)usesGas | ((uint8_t)usesElectric << 1); + } +}; + +struct Car { + // SORT FIELDS BY SIZE since we need "theoretical best" memory usage + Engine engine; + List wheels; + const char* make; + const char* model; + float fuelCapacity; + float fuelLevel; + uint32_t weight; + uint16_t length; + uint16_t width; + uint16_t height; + Color color; + uint8_t seats; + uint8_t doors; + uint8_t cupHolders; + + uint8_t bits; + + inline bool hasPowerWindows() const { return bits & 1; } + inline bool hasPowerSteering() const { return bits & 2; } + inline bool hasCruiseControl() const { return bits & 4; } + inline bool hasNavSystem() const { return bits & 8; } + + inline void setBits(bool hasPowerWindows, bool hasPowerSteering, + bool hasCruiseControl, bool hasNavSystem) { + bits = (uint8_t)hasPowerWindows + | ((uint8_t)hasPowerSteering << 1) + | ((uint8_t)hasCruiseControl << 2) + | ((uint8_t)hasNavSystem << 3); + } +}; + + +uint64_t carValue(const Car& car) { + // Do not think too hard about realism. + + uint64_t result = 0; + + result += car.seats * 200; + result += car.doors * 350; + for (auto wheel: car.wheels) { + result += wheel.diameter * wheel.diameter; + result += wheel.snowTires ? 100 : 0; + } + + result += car.length * car.width * car.height / 50; + + auto engine = car.engine; + result += engine.horsepower * 40; + if (engine.usesElectric()) { + if (engine.usesGas()) { + // hybrid + result += 5000; + } else { + result += 3000; + } + } + + result += car.hasPowerWindows() ? 100 : 0; + result += car.hasPowerSteering() ? 200 : 0; + result += car.hasCruiseControl() ? 400 : 0; + result += car.hasNavSystem() ? 2000 : 0; + + result += car.cupHolders * 25; + + return result; +} + +void randomCar(Car* car) { + // Do not think too hard about realism. + + static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" }; + static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" }; + + car->make = copyString(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]); + car->model = copyString(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]); + + car->color = (Color)fastRand(COLOR_RANGE); + car->seats = 2 + fastRand(6); + car->doors = 2 + fastRand(3); + + for (auto& wheel: car->wheels.init(4)) { + wheel.diameter = 25 + fastRand(15); + wheel.airPressure = 30 + fastRandDouble(20); + wheel.snowTires = fastRand(16) == 0; + } + + car->length = 170 + fastRand(150); + car->width = 48 + fastRand(36); + car->height = 54 + fastRand(48); + car->weight = car->length * car->width * car->height / 200; + + car->engine.horsepower = 100 * fastRand(400); + car->engine.cylinders = 4 + 2 * fastRand(3); + car->engine.cc = 800 + fastRand(10000); + car->engine.setBits(true, fastRand(2)); + + car->fuelCapacity = 10.0 + fastRandDouble(30.0); + car->fuelLevel = fastRandDouble(car->fuelCapacity); + bool hasPowerWindows = fastRand(2); + bool hasPowerSteering = fastRand(2); + bool hasCruiseControl = fastRand(2); + car->cupHolders = fastRand(12); + bool hasNavSystem = fastRand(2); + car->setBits(hasPowerWindows, hasPowerSteering, hasCruiseControl, hasNavSystem); +} + +class CarSalesTestCase { +public: + typedef List Request; + typedef uint64_t Response; + typedef uint64_t Expectation; + + static uint64_t setupRequest(List* request) { + uint64_t result = 0; + for (auto& car: request->init(fastRand(200))) { + randomCar(&car); + result += carValue(car); + } + return result; + } + static void handleRequest(const List& request, uint64_t* response) { + *response = 0; + for (auto& car: request) { + *response += carValue(car); + } + } + static inline bool checkResponse(uint64_t response, uint64_t expected) { + return response == expected; + } +}; + +} // namespace null +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::null::BenchmarkTypes, + capnp::benchmark::null::CarSalesTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/null-catrank.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/null-catrank.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,167 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "null-common.h" + +namespace capnp { +namespace benchmark { +namespace null { + +struct SearchResult { + const char* url; + double score; + const char* snippet; +}; + +struct ScoredResult { + double score; + const SearchResult* result; + + ScoredResult() = default; + ScoredResult(double score, const SearchResult* result): score(score), result(result) {} + + inline bool operator<(const ScoredResult& other) const { return score > other.score; } +}; + +class CatRankTestCase { +public: + typedef List Request; + typedef List Response; + typedef int Expectation; + + static int setupRequest(List* request) { + int count = fastRand(1000); + int goodCount = 0; + + request->init(count); + for (int i = 0; i < count; i++) { + SearchResult& result = request->items[i]; + result.score = 1000 - i; + char* pos = reinterpret_cast(arenaPos); + result.url = pos; + + strcpy(pos, "http://example.com/"); + pos += strlen("http://example.com/"); + int urlSize = fastRand(100); + for (int j = 0; j < urlSize; j++) { + *pos++ = 'a' + fastRand(26); + } + *pos++ = '\0'; + + // Retroactively allocate the space we used. + if (allocate(pos - result.url) != result.url) { + throw std::bad_alloc(); + } + + bool isCat = fastRand(8) == 0; + bool isDog = fastRand(8) == 0; + goodCount += isCat && !isDog; + + pos = reinterpret_cast(arenaPos); + result.snippet = pos; + + *pos++ = ' '; + + int prefix = fastRand(20); + for (int j = 0; j < prefix; j++) { + const char* word = WORDS[fastRand(WORDS_COUNT)]; + size_t len = strlen(word); + memcpy(pos, word, len); + pos += len; + } + + if (isCat) { + strcpy(pos, "cat "); + pos += 4; + } + if (isDog) { + strcpy(pos, "dog "); + pos += 4; + } + + int suffix = fastRand(20); + for (int j = 0; j < suffix; j++) { + const char* word = WORDS[fastRand(WORDS_COUNT)]; + size_t len = strlen(word); + memcpy(pos, word, len); + pos += len; + } + *pos++ = '\0'; + + // Retroactively allocate the space we used. + if (allocate(pos - result.snippet) != result.snippet) { + throw std::bad_alloc(); + } + } + + return goodCount; + } + + static void handleRequest(const List& request, List* response) { + std::vector scoredResults; + scoredResults.reserve(request.size); + + for (auto& result: request) { + double score = result.score; + if (strstr(result.snippet, " cat ") != nullptr) { + score *= 10000; + } + if (strstr(result.snippet, " dog ") != nullptr) { + score /= 10000; + } + scoredResults.emplace_back(score, &result); + } + + std::sort(scoredResults.begin(), scoredResults.end()); + + response->init(scoredResults.size()); + SearchResult* dst = response->items; + for (auto& result: scoredResults) { + dst->url = copyString(result.result->url); + dst->score = result.score; + dst->snippet = copyString(result.result->snippet); + ++dst; + } + } + + static bool checkResponse(const List& response, int expectedGoodCount) { + int goodCount = 0; + for (auto& result: response) { + if (result.score > 1001) { + ++goodCount; + } else { + break; + } + } + + return goodCount == expectedGoodCount; + } +}; + +} // namespace null +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::null::BenchmarkTypes, + capnp::benchmark::null::CatRankTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/null-common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/null-common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,174 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "common.h" + +namespace capnp { +namespace benchmark { +namespace null { + +uint64_t arena[1024*1024]; +uint64_t* arenaPos = arena; + +template +T* allocate(int count = 1) { + T* result = reinterpret_cast(arenaPos); + arenaPos += (sizeof(T) * count + 7) / 8; + if (arenaPos > arena + sizeof(arena) / sizeof(arena[0])) { + throw std::bad_alloc(); + } + return result; +} + +char* copyString(const char* str) { + size_t len = strlen(str); + char* result = allocate(len); + memcpy(result, str, len + 1); + return result; +} + +template +struct List { + size_t size; + T* items; + + inline T* begin() const { return items; } + inline T* end() const { return items + size; } + + inline List& init(size_t size) { + this->size = size; + items = allocate(size); + return *this; + } +}; + +// ======================================================================================= + +struct SingleUseObjects { + class ObjectSizeCounter { + public: + ObjectSizeCounter(uint64_t iters): counter(0) {} + + void add(uint64_t wordCount) { + counter += wordCount; + } + + uint64_t get() { return counter; } + + private: + uint64_t counter; + }; +}; + +struct ReusableObjects { + class ObjectSizeCounter { + public: + ObjectSizeCounter(uint64_t iters): iters(iters), maxSize(0) {} + + void add(size_t wordCount) { + maxSize = std::max(wordCount, maxSize); + } + + uint64_t get() { return iters * maxSize; } + + private: + uint64_t iters; + size_t maxSize; + }; +}; + +// ======================================================================================= + +template +struct BenchmarkMethods { + static uint64_t syncClient(int inputFd, int outputFd, uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } + + static uint64_t asyncClientSender( + int outputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } + + static void asyncClientReceiver( + int inputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } + + static uint64_t asyncClient(int inputFd, int outputFd, uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } + + static uint64_t server(int inputFd, int outputFd, uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } + + static uint64_t passByObject(uint64_t iters, bool countObjectSize) { + typename ReuseStrategy::ObjectSizeCounter sizeCounter(iters); + + for (; iters > 0; --iters) { + arenaPos = arena; + + typename TestCase::Request request; + typename TestCase::Expectation expected = TestCase::setupRequest(&request); + + typename TestCase::Response response; + TestCase::handleRequest(request, &response); + if (!TestCase::checkResponse(response, expected)) { + throw std::logic_error("Incorrect response."); + } + + sizeCounter.add((arenaPos - arena) * sizeof(arena[0])); + } + + return sizeCounter.get(); + } + + static uint64_t passByBytes(uint64_t iters) { + fprintf(stderr, "Null benchmark doesn't do I/O.\n"); + exit(1); + } +}; + +struct BenchmarkTypes { + typedef void Uncompressed; + typedef void Packed; +#if HAVE_SNAPPY + typedef void SnappyCompressed; +#endif // HAVE_SNAPPY + + typedef ReusableObjects ReusableResources; + typedef SingleUseObjects SingleUseResources; + + template + struct BenchmarkMethods: public null::BenchmarkMethods {}; +}; + +} // namespace null +} // namespace benchmark +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/null-eval.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/null-eval.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,155 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "null-common.h" + +namespace capnp { +namespace benchmark { +namespace null { + +enum class Operation { + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + MODULUS +}; +uint OPERATION_RANGE = static_cast(Operation::MODULUS) + 1; + +struct Expression { + Operation op; + + bool leftIsValue; + bool rightIsValue; + + union { + int32_t leftValue; + Expression* leftExpression; + }; + + union { + int32_t rightValue; + Expression* rightExpression; + }; +}; + +int32_t makeExpression(Expression* exp, uint depth) { + exp->op = (Operation)(fastRand(OPERATION_RANGE)); + + int32_t left, right; + + if (fastRand(8) < depth) { + exp->leftIsValue = true; + left = fastRand(128) + 1; + exp->leftValue = left; + } else { + exp->leftIsValue = false; + exp->leftExpression = allocate(); + left = makeExpression(exp->leftExpression, depth + 1); + } + + if (fastRand(8) < depth) { + exp->rightIsValue = true; + right = fastRand(128) + 1; + exp->rightValue = right; + } else { + exp->rightIsValue = false; + exp->rightExpression = allocate(); + right = makeExpression(exp->rightExpression, depth + 1); + } + + switch (exp->op) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +int32_t evaluateExpression(const Expression& exp) { + uint32_t left, right; + + if (exp.leftIsValue) { + left = exp.leftValue; + } else { + left = evaluateExpression(*exp.leftExpression); + } + + if (exp.rightIsValue) { + right = exp.rightValue; + } else { + right = evaluateExpression(*exp.rightExpression); + } + + switch (exp.op) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +class ExpressionTestCase { +public: + typedef Expression Request; + typedef int32_t Response; + typedef int32_t Expectation; + + static inline int32_t setupRequest(Expression* request) { + return makeExpression(request, 0); + } + static inline void handleRequest(const Expression& request, int32_t* response) { + *response = evaluateExpression(request); + } + static inline bool checkResponse(int32_t response, int32_t expected) { + return response == expected; + } + + static size_t spaceUsed(const Expression& expression) { + return sizeof(Expression) + + (expression.leftExpression == nullptr ? 0 : spaceUsed(*expression.leftExpression)) + + (expression.rightExpression == nullptr ? 0 : spaceUsed(*expression.rightExpression)); + } +}; + +} // namespace null +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::null::BenchmarkTypes, + capnp::benchmark::null::ExpressionTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/protobuf-carsales.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/protobuf-carsales.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,141 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "carsales.pb.h" +#include "protobuf-common.h" + +namespace capnp { +namespace benchmark { +namespace protobuf { + +uint64_t carValue(const Car& car) { + // Do not think too hard about realism. + + uint64_t result = 0; + + result += car.seats() * 200; + result += car.doors() * 350; + for (auto& wheel: car.wheel()) { + result += wheel.diameter() * wheel.diameter(); + result += wheel.snow_tires() ? 100 : 0; + } + + result += car.length() * car.width() * car.height() / 50; + + const Engine& engine = car.engine(); + result += engine.horsepower() * 40; + if (engine.uses_electric()) { + if (engine.uses_gas()) { + // hybrid + result += 5000; + } else { + result += 3000; + } + } + + result += car.has_power_windows() ? 100 : 0; + result += car.has_power_steering() ? 200 : 0; + result += car.has_cruise_control() ? 400 : 0; + result += car.has_nav_system() ? 2000 : 0; + + result += car.cup_holders() * 25; + + return result; +} + +void randomCar(Car* car) { + // Do not think too hard about realism. + + static const char* const MAKES[] = { "Toyota", "GM", "Ford", "Honda", "Tesla" }; + static const char* const MODELS[] = { "Camry", "Prius", "Volt", "Accord", "Leaf", "Model S" }; + + car->set_make(MAKES[fastRand(sizeof(MAKES) / sizeof(MAKES[0]))]); + car->set_model(MODELS[fastRand(sizeof(MODELS) / sizeof(MODELS[0]))]); + + car->set_color((Color)fastRand(Color_MAX)); + car->set_seats(2 + fastRand(6)); + car->set_doors(2 + fastRand(3)); + + for (uint i = 0; i < 4; i++) { + Wheel* wheel = car->add_wheel(); + wheel->set_diameter(25 + fastRand(15)); + wheel->set_air_pressure(30 + fastRandDouble(20)); + wheel->set_snow_tires(fastRand(16) == 0); + } + + car->set_length(170 + fastRand(150)); + car->set_width(48 + fastRand(36)); + car->set_height(54 + fastRand(48)); + car->set_weight(car->length() * car->width() * car->height() / 200); + + Engine* engine = car->mutable_engine(); + engine->set_horsepower(100 * fastRand(400)); + engine->set_cylinders(4 + 2 * fastRand(3)); + engine->set_cc(800 + fastRand(10000)); + engine->set_uses_gas(true); + engine->set_uses_electric(fastRand(2)); + + car->set_fuel_capacity(10.0 + fastRandDouble(30.0)); + car->set_fuel_level(fastRandDouble(car->fuel_capacity())); + car->set_has_power_windows(fastRand(2)); + car->set_has_power_steering(fastRand(2)); + car->set_has_cruise_control(fastRand(2)); + car->set_cup_holders(fastRand(12)); + car->set_has_nav_system(fastRand(2)); +} + +class CarSalesTestCase { +public: + typedef ParkingLot Request; + typedef TotalValue Response; + typedef uint64_t Expectation; + + static uint64_t setupRequest(ParkingLot* request) { + uint count = fastRand(200); + uint64_t result = 0; + for (uint i = 0; i < count; i++) { + Car* car = request->add_car(); + randomCar(car); + result += carValue(*car); + } + return result; + } + static void handleRequest(const ParkingLot& request, TotalValue* response) { + uint64_t result = 0; + for (auto& car: request.car()) { + result += carValue(car); + } + response->set_amount(result); + } + static inline bool checkResponse(const TotalValue& response, uint64_t expected) { + return response.amount() == expected; + } +}; + +} // namespace protobuf +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::protobuf::BenchmarkTypes, + capnp::benchmark::protobuf::CarSalesTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/protobuf-catrank.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/protobuf-catrank.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,130 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "catrank.pb.h" +#include "protobuf-common.h" + +namespace capnp { +namespace benchmark { +namespace protobuf { + +struct ScoredResult { + double score; + const SearchResult* result; + + ScoredResult() = default; + ScoredResult(double score, const SearchResult* result): score(score), result(result) {} + + inline bool operator<(const ScoredResult& other) const { return score > other.score; } +}; + +class CatRankTestCase { +public: + typedef SearchResultList Request; + typedef SearchResultList Response; + typedef int Expectation; + + static int setupRequest(SearchResultList* request) { + int count = fastRand(1000); + int goodCount = 0; + + for (int i = 0; i < count; i++) { + SearchResult* result = request->add_result(); + result->set_score(1000 - i); + result->set_url("http://example.com/"); + std::string* url = result->mutable_url(); + int urlSize = fastRand(100); + for (int j = 0; j < urlSize; j++) { + url->push_back('a' + fastRand(26)); + } + + bool isCat = fastRand(8) == 0; + bool isDog = fastRand(8) == 0; + goodCount += isCat && !isDog; + + std::string* snippet = result->mutable_snippet(); + snippet->reserve(7 * 22); + snippet->push_back(' '); + + int prefix = fastRand(20); + for (int j = 0; j < prefix; j++) { + snippet->append(WORDS[fastRand(WORDS_COUNT)]); + } + + if (isCat) snippet->append("cat "); + if (isDog) snippet->append("dog "); + + int suffix = fastRand(20); + for (int j = 0; j < suffix; j++) { + snippet->append(WORDS[fastRand(WORDS_COUNT)]); + } + } + + return goodCount; + } + + static void handleRequest(const SearchResultList& request, SearchResultList* response) { + std::vector scoredResults; + + for (auto& result: request.result()) { + double score = result.score(); + if (result.snippet().find(" cat ") != std::string::npos) { + score *= 10000; + } + if (result.snippet().find(" dog ") != std::string::npos) { + score /= 10000; + } + scoredResults.emplace_back(score, &result); + } + + std::sort(scoredResults.begin(), scoredResults.end()); + + for (auto& result: scoredResults) { + SearchResult* out = response->add_result(); + out->set_score(result.score); + out->set_url(result.result->url()); + out->set_snippet(result.result->snippet()); + } + } + + static bool checkResponse(const SearchResultList& response, int expectedGoodCount) { + int goodCount = 0; + for (auto& result: response.result()) { + if (result.score() > 1001) { + ++goodCount; + } else { + break; + } + } + + return goodCount == expectedGoodCount; + } +}; + +} // namespace protobuf +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::protobuf::BenchmarkTypes, + capnp::benchmark::protobuf::CatRankTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/protobuf-common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/protobuf-common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,359 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "common.h" +#include +#include +#include +#if HAVE_SNAPPY +#include +#include +#endif // HAVE_SNAPPY + +namespace capnp { +namespace benchmark { +namespace protobuf { + +// ======================================================================================= + +struct SingleUseMessages { + template + struct Message { + struct Reusable {}; + struct SingleUse: public MessageType { + inline SingleUse(Reusable&) {} + }; + }; + + struct ReusableString {}; + struct SingleUseString: std::string { + inline SingleUseString(ReusableString&) {} + }; + + template + static inline void doneWith(MessageType& message) { + // Don't clear -- single-use. + } +}; + +struct ReusableMessages { + template + struct Message { + struct Reusable: public MessageType {}; + typedef MessageType& SingleUse; + }; + + typedef std::string ReusableString; + typedef std::string& SingleUseString; + + template + static inline void doneWith(MessageType& message) { + message.Clear(); + } +}; + +// ======================================================================================= +// The protobuf Java library defines a format for writing multiple protobufs to a stream, in which +// each message is prefixed by a varint size. This was never added to the C++ library. It's easy +// to do naively, but tricky to implement without accidentally losing various optimizations. These +// two functions should be optimal. + +struct Uncompressed { + typedef google::protobuf::io::FileInputStream InputStream; + typedef google::protobuf::io::FileOutputStream OutputStream; + + static uint64_t write(const google::protobuf::MessageLite& message, + google::protobuf::io::FileOutputStream* rawOutput) { + google::protobuf::io::CodedOutputStream output(rawOutput); + const int size = message.ByteSize(); + output.WriteVarint32(size); + uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size); + if (buffer != NULL) { + message.SerializeWithCachedSizesToArray(buffer); + } else { + message.SerializeWithCachedSizes(&output); + if (output.HadError()) { + throw OsException(rawOutput->GetErrno()); + } + } + + return size; + } + + static void read(google::protobuf::io::ZeroCopyInputStream* rawInput, + google::protobuf::MessageLite* message) { + google::protobuf::io::CodedInputStream input(rawInput); + uint32_t size; + GOOGLE_CHECK(input.ReadVarint32(&size)); + + auto limit = input.PushLimit(size); + + GOOGLE_CHECK(message->MergePartialFromCodedStream(&input) && + input.ConsumedEntireMessage()); + + input.PopLimit(limit); + } + + static void flush(google::protobuf::io::FileOutputStream* output) { + if (!output->Flush()) throw OsException(output->GetErrno()); + } +}; + +// ======================================================================================= +// The Snappy interface is really obnoxious. I gave up here and am just reading/writing flat +// arrays in some static scratch space. This probably gives protobufs an edge that it doesn't +// deserve. + +#if HAVE_SNAPPY + +static char scratch[1 << 20]; +static char scratch2[1 << 20]; + +struct SnappyCompressed { + typedef int InputStream; + typedef int OutputStream; + + static uint64_t write(const google::protobuf::MessageLite& message, int* output) { + size_t size = message.ByteSize(); + GOOGLE_CHECK_LE(size, sizeof(scratch)); + + message.SerializeWithCachedSizesToArray(reinterpret_cast(scratch)); + + size_t compressedSize = 0; + snappy::RawCompress(scratch, size, scratch2 + sizeof(uint32_t), &compressedSize); + uint32_t tag = compressedSize; + memcpy(scratch2, &tag, sizeof(tag)); + + writeAll(*output, scratch2, compressedSize + sizeof(tag)); + return compressedSize + sizeof(tag); + } + + static void read(int* input, google::protobuf::MessageLite* message) { + uint32_t size; + readAll(*input, &size, sizeof(size)); + readAll(*input, scratch, size); + + size_t uncompressedSize; + GOOGLE_CHECK(snappy::GetUncompressedLength(scratch, size, &uncompressedSize)); + GOOGLE_CHECK(snappy::RawUncompress(scratch, size, scratch2)); + + GOOGLE_CHECK(message->ParsePartialFromArray(scratch2, uncompressedSize)); + } + + static void flush(OutputStream*) {} +}; + +#endif // HAVE_SNAPPY + +// ======================================================================================= + +#define REUSABLE(type) \ + typename ReuseStrategy::template Message::Reusable +#define SINGLE_USE(type) \ + typename ReuseStrategy::template Message::SingleUse + +template +struct BenchmarkMethods { + static uint64_t syncClient(int inputFd, int outputFd, uint64_t iters) { + uint64_t throughput = 0; + + typename Compression::OutputStream output(outputFd); + typename Compression::InputStream input(inputFd); + + REUSABLE(Request) reusableRequest; + REUSABLE(Response) reusableResponse; + + for (; iters > 0; --iters) { + SINGLE_USE(Request) request(reusableRequest); + typename TestCase::Expectation expected = TestCase::setupRequest(&request); + throughput += Compression::write(request, &output); + Compression::flush(&output); + ReuseStrategy::doneWith(request); + + SINGLE_USE(Response) response(reusableResponse); + Compression::read(&input, &response); + if (!TestCase::checkResponse(response, expected)) { + throw std::logic_error("Incorrect response."); + } + ReuseStrategy::doneWith(response); + } + + return throughput; + } + + static uint64_t asyncClientSender( + int outputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + uint64_t throughput = 0; + + typename Compression::OutputStream output(outputFd); + REUSABLE(Request) reusableRequest; + + for (; iters > 0; --iters) { + SINGLE_USE(Request) request(reusableRequest); + expectations->post(TestCase::setupRequest(&request)); + throughput += Compression::write(request, &output); + Compression::flush(&output); + ReuseStrategy::doneWith(request); + } + + return throughput; + } + + static void asyncClientReceiver( + int inputFd, ProducerConsumerQueue* expectations, + uint64_t iters) { + typename Compression::InputStream input(inputFd); + REUSABLE(Response) reusableResponse; + + for (; iters > 0; --iters) { + typename TestCase::Expectation expected = expectations->next(); + SINGLE_USE(Response) response(reusableResponse); + Compression::read(&input, &response); + if (!TestCase::checkResponse(response, expected)) { + throw std::logic_error("Incorrect response."); + } + ReuseStrategy::doneWith(response); + } + } + + static uint64_t asyncClient(int inputFd, int outputFd, uint64_t iters) { + ProducerConsumerQueue expectations; + std::thread receiverThread(asyncClientReceiver, inputFd, &expectations, iters); + uint64_t throughput = asyncClientSender(outputFd, &expectations, iters); + receiverThread.join(); + + return throughput; + } + + static uint64_t server(int inputFd, int outputFd, uint64_t iters) { + uint64_t throughput = 0; + + typename Compression::OutputStream output(outputFd); + typename Compression::InputStream input(inputFd); + + REUSABLE(Request) reusableRequest; + REUSABLE(Response) reusableResponse; + + for (; iters > 0; --iters) { + SINGLE_USE(Request) request(reusableRequest); + Compression::read(&input, &request); + + SINGLE_USE(Response) response(reusableResponse); + TestCase::handleRequest(request, &response); + ReuseStrategy::doneWith(request); + + throughput += Compression::write(response, &output); + Compression::flush(&output); + ReuseStrategy::doneWith(response); + } + + return throughput; + } + + static uint64_t passByObject(uint64_t iters, bool countObjectSize) { + uint64_t throughput = 0; + + REUSABLE(Request) reusableRequest; + REUSABLE(Response) reusableResponse; + + for (; iters > 0; --iters) { + SINGLE_USE(Request) request(reusableRequest); + typename TestCase::Expectation expected = TestCase::setupRequest(&request); + + SINGLE_USE(Response) response(reusableResponse); + TestCase::handleRequest(request, &response); + ReuseStrategy::doneWith(request); + if (!TestCase::checkResponse(response, expected)) { + throw std::logic_error("Incorrect response."); + } + ReuseStrategy::doneWith(response); + + if (countObjectSize) { + throughput += request.SpaceUsed(); + throughput += response.SpaceUsed(); + } + } + + return throughput; + } + + static uint64_t passByBytes(uint64_t iters) { + uint64_t throughput = 0; + + REUSABLE(Request) reusableClientRequest; + REUSABLE(Request) reusableServerRequest; + REUSABLE(Response) reusableServerResponse; + REUSABLE(Response) reusableClientResponse; + typename ReuseStrategy::ReusableString reusableRequestString, reusableResponseString; + + for (; iters > 0; --iters) { + SINGLE_USE(Request) clientRequest(reusableClientRequest); + typename TestCase::Expectation expected = TestCase::setupRequest(&clientRequest); + + typename ReuseStrategy::SingleUseString requestString(reusableRequestString); + clientRequest.SerializePartialToString(&requestString); + throughput += requestString.size(); + ReuseStrategy::doneWith(clientRequest); + + SINGLE_USE(Request) serverRequest(reusableServerRequest); + serverRequest.ParsePartialFromString(requestString); + + SINGLE_USE(Response) serverResponse(reusableServerResponse); + TestCase::handleRequest(serverRequest, &serverResponse); + ReuseStrategy::doneWith(serverRequest); + + typename ReuseStrategy::SingleUseString responseString(reusableResponseString); + serverResponse.SerializePartialToString(&responseString); + throughput += responseString.size(); + ReuseStrategy::doneWith(serverResponse); + + SINGLE_USE(Response) clientResponse(reusableClientResponse); + clientResponse.ParsePartialFromString(responseString); + + if (!TestCase::checkResponse(clientResponse, expected)) { + throw std::logic_error("Incorrect response."); + } + ReuseStrategy::doneWith(clientResponse); + } + + return throughput; + } +}; + +struct BenchmarkTypes { + typedef protobuf::Uncompressed Uncompressed; + typedef protobuf::Uncompressed Packed; +#if HAVE_SNAPPY + typedef protobuf::SnappyCompressed SnappyCompressed; +#endif // HAVE_SNAPPY + + typedef protobuf::ReusableMessages ReusableResources; + typedef protobuf::SingleUseMessages SingleUseResources; + + template + struct BenchmarkMethods + : public protobuf::BenchmarkMethods {}; +}; + +} // namespace protobuf +} // namespace benchmark +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/protobuf-eval.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/protobuf-eval.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,118 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "eval.pb.h" +#include "protobuf-common.h" + +namespace capnp { +namespace benchmark { +namespace protobuf { + +int32_t makeExpression(Expression* exp, uint depth) { + exp->set_op((Operation)(fastRand(Operation_MAX + 1))); + + int32_t left, right; + + if (fastRand(8) < depth) { + left = fastRand(128) + 1; + exp->set_left_value(left); + } else { + left = makeExpression(exp->mutable_left_expression(), depth + 1); + } + + if (fastRand(8) < depth) { + right = fastRand(128) + 1; + exp->set_right_value(right); + } else { + right = makeExpression(exp->mutable_right_expression(), depth + 1); + } + + switch (exp->op()) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +int32_t evaluateExpression(const Expression& exp) { + uint32_t left, right; + + if (exp.has_left_value()) { + left = exp.left_value(); + } else { + left = evaluateExpression(exp.left_expression()); + } + + if (exp.has_right_value()) { + right = exp.right_value(); + } else { + right = evaluateExpression(exp.right_expression()); + } + + switch (exp.op()) { + case Operation::ADD: + return left + right; + case Operation::SUBTRACT: + return left - right; + case Operation::MULTIPLY: + return left * right; + case Operation::DIVIDE: + return div(left, right); + case Operation::MODULUS: + return mod(left, right); + } + throw std::logic_error("Can't get here."); +} + +class ExpressionTestCase { +public: + typedef Expression Request; + typedef EvaluationResult Response; + typedef int32_t Expectation; + + static inline int32_t setupRequest(Expression* request) { + return makeExpression(request, 0); + } + static inline void handleRequest(const Expression& request, EvaluationResult* response) { + response->set_value(evaluateExpression(request)); + } + static inline bool checkResponse(const EvaluationResult& response, int32_t expected) { + return response.value() == expected; + } +}; + +} // namespace protobuf +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::benchmarkMain< + capnp::benchmark::protobuf::BenchmarkTypes, + capnp::benchmark::protobuf::ExpressionTestCase>(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/benchmark/runner.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/benchmark/runner.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,648 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace capnp { +namespace benchmark { +namespace runner { + +struct Times { + uint64_t real; + uint64_t user; + uint64_t sys; + + uint64_t cpu() { return user + sys; } + + Times operator-(const Times& other) { + Times result; + result.real = real - other.real; + result.user = user - other.user; + result.sys = sys - other.sys; + return result; + } +}; + +uint64_t asNanosecs(const struct timeval& tv) { + return (uint64_t)tv.tv_sec * 1000000000 + (uint64_t)tv.tv_usec * 1000; +} + +Times currentTimes() { + Times result; + + struct rusage self, children; + getrusage(RUSAGE_SELF, &self); + getrusage(RUSAGE_CHILDREN, &children); + + struct timeval real; + gettimeofday(&real, nullptr); + + result.real = asNanosecs(real); + result.user = asNanosecs(self.ru_utime) + asNanosecs(children.ru_utime); + result.sys = asNanosecs(self.ru_stime) + asNanosecs(children.ru_stime); + + return result; +} + +struct TestResult { + uint64_t objectSize; + uint64_t messageSize; + Times time; +}; + +enum class Product { + CAPNPROTO, + PROTOBUF, + NULLCASE +}; + +enum class TestCase { + EVAL, + CATRANK, + CARSALES +}; + +const char* testCaseName(TestCase testCase) { + switch (testCase) { + case TestCase::EVAL: + return "eval"; + case TestCase::CATRANK: + return "catrank"; + case TestCase::CARSALES: + return "carsales"; + } + // Can't get here. + return nullptr; +} + +enum class Mode { + OBJECTS, + OBJECT_SIZE, + BYTES, + PIPE_SYNC, + PIPE_ASYNC +}; + +enum class Reuse { + YES, + NO +}; + +enum class Compression { + NONE, + PACKED, + SNAPPY +}; + +TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse, + Compression compression, uint64_t iters) { + char* argv[6]; + + string progName; + + switch (product) { + case Product::CAPNPROTO: + progName = "capnproto-"; + break; + case Product::PROTOBUF: + progName = "protobuf-"; + break; + case Product::NULLCASE: + progName = "null-"; + break; + } + + progName += testCaseName(testCase); + argv[0] = strdup(progName.c_str()); + + switch (mode) { + case Mode::OBJECTS: + argv[1] = strdup("object"); + break; + case Mode::OBJECT_SIZE: + argv[1] = strdup("object-size"); + break; + case Mode::BYTES: + argv[1] = strdup("bytes"); + break; + case Mode::PIPE_SYNC: + argv[1] = strdup("pipe"); + break; + case Mode::PIPE_ASYNC: + argv[1] = strdup("pipe-async"); + break; + } + + switch (reuse) { + case Reuse::YES: + argv[2] = strdup("reuse"); + break; + case Reuse::NO: + argv[2] = strdup("no-reuse"); + break; + } + + switch (compression) { + case Compression::NONE: + argv[3] = strdup("none"); + break; + case Compression::PACKED: + argv[3] = strdup("packed"); + break; + case Compression::SNAPPY: + argv[3] = strdup("snappy"); + break; + } + + char itersStr[64]; + sprintf(itersStr, "%llu", (long long unsigned int)iters); + argv[4] = itersStr; + + argv[5] = nullptr; + + // Make pipe for child to write throughput. + int childPipe[2]; + if (pipe(childPipe) < 0) { + perror("pipe"); + exit(1); + } + + // Spawn the child process. + struct timeval start, end; + gettimeofday(&start, nullptr); + pid_t child = fork(); + if (child == 0) { + close(childPipe[0]); + dup2(childPipe[1], STDOUT_FILENO); + close(childPipe[1]); + execv(argv[0], argv); + exit(1); + } + + close(childPipe[1]); + for (int i = 0; i < 4; i++) { + free(argv[i]); + } + + // Read throughput number written to child's stdout. + FILE* input = fdopen(childPipe[0], "r"); + long long unsigned int throughput; + if (fscanf(input, "%lld", &throughput) != 1) { + fprintf(stderr, "Child didn't write throughput to stdout."); + } + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), input) != nullptr) { + // Loop until EOF. + } + fclose(input); + + // Wait for child exit. + int status; + struct rusage usage; + wait4(child, &status, 0, &usage); + gettimeofday(&end, nullptr); + + // Calculate results. + + TestResult result; + result.objectSize = mode == Mode::OBJECT_SIZE ? throughput : 0; + result.messageSize = mode == Mode::OBJECT_SIZE ? 0 : throughput; + result.time.real = asNanosecs(end) - asNanosecs(start); + result.time.user = asNanosecs(usage.ru_utime); + result.time.sys = asNanosecs(usage.ru_stime); + + return result; +} + +void reportTableHeader() { + cout << setw(40) << left << "Test" + << setw(10) << right << "obj size" + << setw(10) << right << "I/O bytes" + << setw(10) << right << "wall ns" + << setw(10) << right << "user ns" + << setw(10) << right << "sys ns" + << endl; + cout << setfill('=') << setw(90) << "" << setfill(' ') << endl; +} + +void reportResults(const char* name, uint64_t iters, TestResult results) { + cout << setw(40) << left << name + << setw(10) << right << (results.objectSize / iters) + << setw(10) << right << (results.messageSize / iters) + << setw(10) << right << (results.time.real / iters) + << setw(10) << right << (results.time.user / iters) + << setw(10) << right << (results.time.sys / iters) + << endl; +} + +void reportComparisonHeader() { + cout << setw(40) << left << "Measure" + << setw(15) << right << "Protobuf" + << setw(15) << right << "Cap'n Proto" + << setw(15) << right << "Improvement" + << endl; + cout << setfill('=') << setw(85) << "" << setfill(' ') << endl; +} + +void reportOldNewComparisonHeader() { + cout << setw(40) << left << "Measure" + << setw(15) << right << "Old" + << setw(15) << right << "New" + << setw(15) << right << "Improvement" + << endl; + cout << setfill('=') << setw(85) << "" << setfill(' ') << endl; +} + +class Gain { +public: + Gain(double oldValue, double newValue) + : amount(newValue / oldValue) {} + + void writeTo(std::ostream& os) { + if (amount < 2) { + double percent = (amount - 1) * 100; + os << (int)(percent + 0.5) << "%"; + } else { + os << fixed << setprecision(2) << amount << "x"; + } + } + +private: + double amount; +}; + +ostream& operator<<(ostream& os, Gain gain) { + gain.writeTo(os); + return os; +} + +void reportComparison(const char* name, double base, double protobuf, double capnproto, + uint64_t iters) { + cout << setw(40) << left << name + << setw(14) << right << Gain(base, protobuf) + << setw(14) << right << Gain(base, capnproto); + + // Since smaller is better, the "improvement" is the "gain" from capnproto to protobuf. + cout << setw(14) << right << Gain(capnproto - base, protobuf - base) << endl; +} + +void reportComparison(const char* name, const char* unit, double protobuf, double capnproto, + uint64_t iters) { + cout << setw(40) << left << name + << setw(15-strlen(unit)) << fixed << right << setprecision(2) << (protobuf / iters) << unit + << setw(15-strlen(unit)) << fixed << right << setprecision(2) << (capnproto / iters) << unit; + + // Since smaller is better, the "improvement" is the "gain" from capnproto to protobuf. + cout << setw(14) << right << Gain(capnproto, protobuf) << endl; +} + +void reportIntComparison(const char* name, const char* unit, uint64_t protobuf, uint64_t capnproto, + uint64_t iters) { + cout << setw(40) << left << name + << setw(15-strlen(unit)) << right << (protobuf / iters) << unit + << setw(15-strlen(unit)) << right << (capnproto / iters) << unit; + + // Since smaller is better, the "improvement" is the "gain" from capnproto to protobuf. + cout << setw(14) << right << Gain(capnproto, protobuf) << endl; +} + +size_t fileSize(const std::string& name) { + struct stat stats; + if (stat(name.c_str(), &stats) < 0) { + perror(name.c_str()); + exit(1); + } + + return stats.st_size; +} + +int main(int argc, char* argv[]) { + char* path = argv[0]; + char* slashpos = strrchr(path, '/'); + char origDir[1024]; + if (getcwd(origDir, sizeof(origDir)) == nullptr) { + perror("getcwd"); + return 1; + } + if (slashpos != nullptr) { + *slashpos = '\0'; + if (chdir(path) < 0) { + perror("chdir"); + return 1; + } + *slashpos = '/'; + } + + TestCase testCase = TestCase::CATRANK; + Mode mode = Mode::PIPE_SYNC; + Compression compression = Compression::NONE; + uint64_t iters = 1; + const char* oldDir = nullptr; + + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + if (isdigit(argv[i][0])) { + iters = strtoul(argv[i], nullptr, 0); + } else if (arg == "async") { + mode = Mode::PIPE_ASYNC; + } else if (arg == "inmem") { + mode = Mode::BYTES; + } else if (arg == "eval") { + testCase = TestCase::EVAL; + } else if (arg == "carsales") { + testCase = TestCase::CARSALES; + } else if (arg == "snappy") { + compression = Compression::SNAPPY; + } else if (arg == "-c") { + ++i; + if (i == argc) { + fprintf(stderr, "-c requires argument.\n"); + return 1; + } + oldDir = argv[i]; + } else { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return 1; + } + } + + // Scale iterations to something reasonable for each case. + switch (testCase) { + case TestCase::EVAL: + iters *= 100000; + break; + case TestCase::CATRANK: + iters *= 1000; + break; + case TestCase::CARSALES: + iters *= 20000; + break; + } + + cout << "Running " << iters << " iterations of "; + switch (testCase) { + case TestCase::EVAL: + cout << "calculator"; + break; + case TestCase::CATRANK: + cout << "CatRank"; + break; + case TestCase::CARSALES: + cout << "car sales"; + break; + } + + cout << " example case with:" << endl; + + switch (mode) { + case Mode::OBJECTS: + case Mode::OBJECT_SIZE: + // Can't happen. + break; + case Mode::BYTES: + cout << "* in-memory I/O" << endl; + cout << " * with client and server in the same thread" << endl; + break; + case Mode::PIPE_SYNC: + cout << "* pipe I/O" << endl; + cout << " * with client and server in separate processes" << endl; + cout << " * client waits for each response before sending next request" << endl; + break; + case Mode::PIPE_ASYNC: + cout << "* pipe I/O" << endl; + cout << " * with client and server in separate processes" << endl; + cout << " * client sends as many simultaneous requests as it can" << endl; + break; + } + switch (compression) { + case Compression::NONE: + cout << "* no compression" << endl; + break; + case Compression::PACKED: + cout << "* de-zero packing for Cap'n Proto" << endl; + cout << "* standard packing for Protobuf" << endl; + break; + case Compression::SNAPPY: + cout << "* Snappy compression" << endl; + break; + } + + cout << endl; + + reportTableHeader(); + + TestResult nullCase = runTest( + Product::NULLCASE, testCase, Mode::OBJECT_SIZE, Reuse::YES, compression, iters); + reportResults("Theoretical best pass-by-object", iters, nullCase); + + TestResult protobufBase = runTest( + Product::PROTOBUF, testCase, Mode::OBJECTS, Reuse::YES, compression, iters); + protobufBase.objectSize = runTest( + Product::PROTOBUF, testCase, Mode::OBJECT_SIZE, Reuse::YES, compression, iters).objectSize; + reportResults("Protobuf pass-by-object", iters, protobufBase); + + TestResult capnpBase = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECTS, Reuse::YES, compression, iters); + capnpBase.objectSize = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECT_SIZE, Reuse::YES, compression, iters).objectSize; + reportResults("Cap'n Proto pass-by-object", iters, capnpBase); + + TestResult nullCaseNoReuse = runTest( + Product::NULLCASE, testCase, Mode::OBJECT_SIZE, Reuse::NO, compression, iters); + reportResults("Theoretical best w/o object reuse", iters, nullCaseNoReuse); + + TestResult protobufNoReuse = runTest( + Product::PROTOBUF, testCase, Mode::OBJECTS, Reuse::NO, compression, iters); + protobufNoReuse.objectSize = runTest( + Product::PROTOBUF, testCase, Mode::OBJECT_SIZE, Reuse::NO, compression, iters).objectSize; + reportResults("Protobuf w/o object reuse", iters, protobufNoReuse); + + TestResult capnpNoReuse = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECTS, Reuse::NO, compression, iters); + capnpNoReuse.objectSize = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECT_SIZE, Reuse::NO, compression, iters).objectSize; + reportResults("Cap'n Proto w/o object reuse", iters, capnpNoReuse); + + TestResult protobuf = runTest( + Product::PROTOBUF, testCase, mode, Reuse::YES, compression, iters); + protobuf.objectSize = protobufBase.objectSize; + reportResults("Protobuf I/O", iters, protobuf); + + TestResult capnp = runTest( + Product::CAPNPROTO, testCase, mode, Reuse::YES, compression, iters); + capnp.objectSize = capnpBase.objectSize; + reportResults("Cap'n Proto I/O", iters, capnp); + TestResult capnpPacked = runTest( + Product::CAPNPROTO, testCase, mode, Reuse::YES, Compression::PACKED, iters); + capnpPacked.objectSize = capnpBase.objectSize; + reportResults("Cap'n Proto packed I/O", iters, capnpPacked); + + size_t protobufBinarySize = fileSize("protobuf-" + std::string(testCaseName(testCase))); + size_t capnpBinarySize = fileSize("capnproto-" + std::string(testCaseName(testCase))); + size_t protobufCodeSize = fileSize(std::string(testCaseName(testCase)) + ".pb.cc") + + fileSize(std::string(testCaseName(testCase)) + ".pb.h"); + size_t capnpCodeSize = fileSize(std::string(testCaseName(testCase)) + ".capnp.c++") + + fileSize(std::string(testCaseName(testCase)) + ".capnp.h"); + size_t protobufObjSize = fileSize(std::string(testCaseName(testCase)) + ".pb.o"); + size_t capnpObjSize = fileSize(std::string(testCaseName(testCase)) + ".capnp.o"); + + TestResult oldNullCase; + TestResult oldNullCaseNoReuse; + TestResult oldCapnpBase; + TestResult oldCapnpNoReuse; + TestResult oldCapnp; + TestResult oldCapnpPacked; + size_t oldCapnpBinarySize = 0; + size_t oldCapnpCodeSize = 0; + size_t oldCapnpObjSize = 0; + if (oldDir != nullptr) { + if (chdir(origDir) < 0) { + perror("chdir"); + return 1; + } + if (chdir(oldDir) < 0) { + perror(oldDir); + return 1; + } + + oldNullCase = runTest( + Product::NULLCASE, testCase, Mode::OBJECT_SIZE, Reuse::YES, compression, iters); + reportResults("Old theoretical best pass-by-object", iters, nullCase); + + oldCapnpBase = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECTS, Reuse::YES, compression, iters); + oldCapnpBase.objectSize = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECT_SIZE, Reuse::YES, compression, iters) + .objectSize; + reportResults("Old Cap'n Proto pass-by-object", iters, oldCapnpBase); + + oldNullCaseNoReuse = runTest( + Product::NULLCASE, testCase, Mode::OBJECT_SIZE, Reuse::NO, compression, iters); + reportResults("Old theoretical best w/o object reuse", iters, oldNullCaseNoReuse); + + oldCapnpNoReuse = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECTS, Reuse::NO, compression, iters); + oldCapnpNoReuse.objectSize = runTest( + Product::CAPNPROTO, testCase, Mode::OBJECT_SIZE, Reuse::NO, compression, iters).objectSize; + reportResults("Old Cap'n Proto w/o object reuse", iters, oldCapnpNoReuse); + + oldCapnp = runTest( + Product::CAPNPROTO, testCase, mode, Reuse::YES, compression, iters); + oldCapnp.objectSize = oldCapnpBase.objectSize; + reportResults("Old Cap'n Proto I/O", iters, oldCapnp); + oldCapnpPacked = runTest( + Product::CAPNPROTO, testCase, mode, Reuse::YES, Compression::PACKED, iters); + oldCapnpPacked.objectSize = oldCapnpBase.objectSize; + reportResults("Old Cap'n Proto packed I/O", iters, oldCapnpPacked); + + oldCapnpBinarySize = fileSize("capnproto-" + std::string(testCaseName(testCase))); + oldCapnpCodeSize = fileSize(std::string(testCaseName(testCase)) + ".capnp.c++") + + fileSize(std::string(testCaseName(testCase)) + ".capnp.h"); + oldCapnpObjSize = fileSize(std::string(testCaseName(testCase)) + ".capnp.o"); + } + + cout << endl; + + reportComparisonHeader(); + reportComparison("memory overhead (vs ideal)", + nullCase.objectSize, protobufBase.objectSize, capnpBase.objectSize, iters); + reportComparison("memory overhead w/o object reuse", + nullCaseNoReuse.objectSize, protobufNoReuse.objectSize, capnpNoReuse.objectSize, iters); + reportComparison("object manipulation time (us)", "", + ((int64_t)protobufBase.time.user - (int64_t)nullCase.time.user) / 1000.0, + ((int64_t)capnpBase.time.user - (int64_t)nullCase.time.user) / 1000.0, iters); + reportComparison("object manipulation time w/o reuse (us)", "", + ((int64_t)protobufNoReuse.time.user - (int64_t)nullCaseNoReuse.time.user) / 1000.0, + ((int64_t)capnpNoReuse.time.user - (int64_t)nullCaseNoReuse.time.user) / 1000.0, iters); + reportComparison("I/O time (us)", "", + ((int64_t)protobuf.time.user - (int64_t)protobufBase.time.user) / 1000.0, + ((int64_t)capnp.time.user - (int64_t)capnpBase.time.user) / 1000.0, iters); + reportComparison("packed I/O time (us)", "", + ((int64_t)protobuf.time.user - (int64_t)protobufBase.time.user) / 1000.0, + ((int64_t)capnpPacked.time.user - (int64_t)capnpBase.time.user) / 1000.0, iters); + + reportIntComparison("message size (bytes)", "", protobuf.messageSize, capnp.messageSize, iters); + reportIntComparison("packed message size (bytes)", "", + protobuf.messageSize, capnpPacked.messageSize, iters); + + reportComparison("binary size (KiB)", "", + protobufBinarySize / 1024.0, capnpBinarySize / 1024.0, 1); + reportComparison("generated code size (KiB)", "", + protobufCodeSize / 1024.0, capnpCodeSize / 1024.0, 1); + reportComparison("generated obj size (KiB)", "", + protobufObjSize / 1024.0, capnpObjSize / 1024.0, 1); + + if (oldDir != nullptr) { + cout << endl; + reportOldNewComparisonHeader(); + + reportComparison("memory overhead", + oldNullCase.objectSize, oldCapnpBase.objectSize, capnpBase.objectSize, iters); + reportComparison("memory overhead w/o object reuse", + oldNullCaseNoReuse.objectSize, oldCapnpNoReuse.objectSize, capnpNoReuse.objectSize, iters); + reportComparison("object manipulation time (us)", "", + ((int64_t)oldCapnpBase.time.user - (int64_t)oldNullCase.time.user) / 1000.0, + ((int64_t)capnpBase.time.user - (int64_t)oldNullCase.time.user) / 1000.0, iters); + reportComparison("object manipulation time w/o reuse (us)", "", + ((int64_t)oldCapnpNoReuse.time.user - (int64_t)oldNullCaseNoReuse.time.user) / 1000.0, + ((int64_t)capnpNoReuse.time.user - (int64_t)oldNullCaseNoReuse.time.user) / 1000.0, iters); + reportComparison("I/O time (us)", "", + ((int64_t)oldCapnp.time.user - (int64_t)oldCapnpBase.time.user) / 1000.0, + ((int64_t)capnp.time.user - (int64_t)capnpBase.time.user) / 1000.0, iters); + reportComparison("packed I/O time (us)", "", + ((int64_t)oldCapnpPacked.time.user - (int64_t)oldCapnpBase.time.user) / 1000.0, + ((int64_t)capnpPacked.time.user - (int64_t)capnpBase.time.user) / 1000.0, iters); + + reportIntComparison("message size (bytes)", "", oldCapnp.messageSize, capnp.messageSize, iters); + reportIntComparison("packed message size (bytes)", "", + oldCapnpPacked.messageSize, capnpPacked.messageSize, iters); + + reportComparison("binary size (KiB)", "", + oldCapnpBinarySize / 1024.0, capnpBinarySize / 1024.0, 1); + reportComparison("generated code size (KiB)", "", + oldCapnpCodeSize / 1024.0, capnpCodeSize / 1024.0, 1); + reportComparison("generated obj size (KiB)", "", + oldCapnpObjSize / 1024.0, capnpObjSize / 1024.0, 1); + } + + return 0; +} + +} // namespace runner +} // namespace benchmark +} // namespace capnp + +int main(int argc, char* argv[]) { + return capnp::benchmark::runner::main(argc, argv); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/CMakeLists.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,261 @@ + +# capnp ======================================================================== + +set(capnp_sources_lite + c++.capnp.c++ + blob.c++ + arena.c++ + layout.c++ + list.c++ + any.c++ + message.c++ + schema.capnp.c++ + serialize.c++ + serialize-packed.c++ +) +set(capnp_sources_heavy + schema.c++ + schema-loader.c++ + dynamic.c++ + stringify.c++ +) +if(NOT CAPNP_LITE) + set(capnp_sources ${capnp_sources_lite} ${capnp_sources_heavy}) +else() + set(capnp_sources ${capnp_sources_lite}) +endif() + +set(capnp_headers + c++.capnp.h + common.h + blob.h + endian.h + layout.h + orphan.h + list.h + any.h + message.h + capability.h + membrane.h + dynamic.h + schema.h + schema.capnp.h + schema-lite.h + schema-loader.h + schema-parser.h + pretty-print.h + serialize.h + serialize-async.h + serialize-packed.h + serialize-text.h + pointer-helpers.h + generated-header-support.h + raw-schema.h +) +set(capnp_schemas + c++.capnp + schema.capnp +) +add_library(capnp ${capnp_sources}) +add_library(CapnProto::capnp ALIAS capnp) +target_link_libraries(capnp PUBLIC kj) +#make sure external consumers don't need to manually set the include dirs +target_include_directories(capnp INTERFACE + $ + $ +) +install(TARGETS capnp ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES ${capnp_headers} ${capnp_schemas} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/capnp") + +set(capnp-rpc_sources + serialize-async.c++ + capability.c++ + membrane.c++ + dynamic-capability.c++ + rpc.c++ + rpc.capnp.c++ + rpc-twoparty.c++ + rpc-twoparty.capnp.c++ + persistent.capnp.c++ + ez-rpc.c++ +) +set(capnp-rpc_headers + rpc-prelude.h + rpc.h + rpc-twoparty.h + rpc.capnp.h + rpc-twoparty.capnp.h + persistent.capnp.h + ez-rpc.h +) +set(capnp-rpc_schemas + rpc.capnp + rpc-twoparty.capnp + persistent.capnp +) +if(NOT CAPNP_LITE) + add_library(capnp-rpc ${capnp-rpc_sources}) + add_library(CapnProto::capnp-rpc ALIAS capnp-rpc) + target_link_libraries(capnp-rpc PUBLIC capnp kj-async kj) + install(TARGETS capnp-rpc ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES ${capnp-rpc_headers} ${capnp-rpc_schemas} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/capnp") +endif() + +# capnp-json ======================================================================== + +set(capnp-json_sources + compat/json.c++ + compat/json.capnp.c++ +) +set(capnp-json_headers + compat/json.h + compat/json.capnp.h +) +set(capnp-json_schemas + compat/json.capnp +) +if(NOT CAPNP_LITE) + add_library(capnp-json ${capnp-json_sources}) + add_library(CapnProto::capnp-json ALIAS capnp-json) + target_link_libraries(capnp-json PUBLIC capnp kj-async kj) + install(TARGETS capnp-json ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES ${capnp-json_headers} ${capnp-json_schemas} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/capnp/compat") +endif() + +# Tools/Compilers ============================================================== + +set(capnpc_sources + compiler/md5.c++ + compiler/error-reporter.c++ + compiler/lexer.capnp.c++ + compiler/lexer.c++ + compiler/grammar.capnp.c++ + compiler/parser.c++ + compiler/node-translator.c++ + compiler/compiler.c++ + schema-parser.c++ + serialize-text.c++ +) +if(NOT CAPNP_LITE) + add_library(capnpc ${capnpc_sources}) + target_link_libraries(capnpc PUBLIC capnp kj) + install(TARGETS capnpc ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES ${capnpc_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/capnp") +endif() + +if(NOT CAPNP_LITE) + add_executable(capnp_tool + compiler/module-loader.c++ + compiler/capnp.c++ + ) + target_link_libraries(capnp_tool capnpc capnp kj) + set_target_properties(capnp_tool PROPERTIES OUTPUT_NAME capnp) + set_target_properties(capnp_tool PROPERTIES CAPNP_INCLUDE_DIRECTORY + $,$> + ) + + add_executable(capnpc_cpp + compiler/capnpc-c++.c++ + ) + target_link_libraries(capnpc_cpp capnp kj) + set_target_properties(capnpc_cpp PROPERTIES OUTPUT_NAME capnpc-c++) + #Capnp tool needs capnpc_cpp location. But cmake deprecated LOCATION property. + #So we use custom property to pass location + set_target_properties(capnpc_cpp PROPERTIES CAPNPC_CXX_EXECUTABLE + $ + ) + + add_executable(capnpc_capnp + compiler/capnpc-capnp.c++ + ) + target_link_libraries(capnpc_capnp capnp kj) + set_target_properties(capnpc_capnp PROPERTIES OUTPUT_NAME capnpc-capnp) + + install(TARGETS capnp_tool capnpc_cpp capnpc_capnp ${INSTALL_TARGETS_DEFAULT_ARGS}) + + # Symlink capnpc -> capnp + install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink capnp \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/capnpc\")") +endif() # NOT CAPNP_LITE + +# Tests ======================================================================== + +if(BUILD_TESTING) + set(test_capnp_files + test.capnp + test-import.capnp + test-import2.capnp + ) + + # Add "/capnp" to match the path used to import the files in the test sources + set(CAPNPC_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/test_capnp/capnp") + include_directories("${CMAKE_CURRENT_BINARY_DIR}/test_capnp") # Note: no "/capnp" + file(MAKE_DIRECTORY "${CAPNPC_OUTPUT_DIR}") + + capnp_generate_cpp(test_capnp_cpp_files test_capnp_h_files ${test_capnp_files}) + + if(CAPNP_LITE) + set(test_libraries capnp kj-test kj) + else() + set(test_libraries capnp-json capnp-rpc capnp capnpc kj-async kj-test kj) + endif() + + add_executable(capnp-tests + common-test.c++ + blob-test.c++ + endian-test.c++ + endian-fallback-test.c++ + layout-test.c++ + any-test.c++ + message-test.c++ + encoding-test.c++ + orphan-test.c++ + serialize-test.c++ + serialize-packed-test.c++ + canonicalize-test.c++ + fuzz-test.c++ + test-util.c++ + ${test_capnp_cpp_files} + ${test_capnp_h_files} + ) + target_link_libraries(capnp-tests ${test_libraries}) + add_dependencies(check capnp-tests) + add_test(NAME capnp-tests-run COMMAND capnp-tests) + + if(NOT CAPNP_LITE) + add_executable(capnp-heavy-tests + endian-reverse-test.c++ + capability-test.c++ + membrane-test.c++ + schema-test.c++ + schema-loader-test.c++ + schema-parser-test.c++ + dynamic-test.c++ + stringify-test.c++ + serialize-async-test.c++ + serialize-text-test.c++ + rpc-test.c++ + rpc-twoparty-test.c++ + ez-rpc-test.c++ + compiler/lexer-test.c++ + compiler/md5-test.c++ + test-util.c++ + compat/json-test.c++ + ${test_capnp_cpp_files} + ${test_capnp_h_files} + ) + target_link_libraries(capnp-heavy-tests ${test_libraries}) + if(NOT MSVC) + set_target_properties(capnp-heavy-tests + PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations" + ) + endif() + + add_dependencies(check capnp-heavy-tests) + add_test(NAME capnp-heavy-tests-run COMMAND capnp-heavy-tests) + + add_executable(capnp-evolution-tests compiler/evolution-test.c++) + target_link_libraries(capnp-evolution-tests capnpc capnp kj) + add_dependencies(check capnp-evolution-tests) + add_test(NAME capnp-evolution-tests-run COMMAND capnp-evolution-tests) + endif() # NOT CAPNP_LITE +endif() # BUILD_TESTING diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/afl-testcase.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/afl-testcase.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,143 @@ +// Copyright (c) 2017 Cloudflare, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "test-util.h" +#include +#include "serialize.h" +#include +#include + +namespace capnp { +namespace _ { +namespace { + +class AflTestMain { +public: + explicit AflTestMain(kj::ProcessContext& context) + : context(context) {} + + kj::MainFunc getMain() { + return kj::MainBuilder(context, "(unknown version)", + "American Fuzzy Lop test case. Pass input on stdin. Expects a binary " + "message of type TestAllTypes.") + .addOption({"lists"}, KJ_BIND_METHOD(*this, runLists), + "Expect a message of type TestLists instead of TestAllTypes.") + .addOption({"canonicalize"}, KJ_BIND_METHOD(*this, canonicalize), + "Test canonicalization code.") + .callAfterParsing(KJ_BIND_METHOD(*this, run)) + .build(); + } + + kj::MainBuilder::Validity run() { + capnp::StreamFdMessageReader reader(STDIN_FILENO); + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + checkTestMessage(reader.getRoot()); + })) { + KJ_LOG(ERROR, "threw"); + } + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + checkDynamicTestMessage(reader.getRoot(Schema::from())); + })) { + KJ_LOG(ERROR, "dynamic threw"); + } + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + kj::str(reader.getRoot()); + })) { + KJ_LOG(ERROR, "str threw"); + } + return true; + } + + kj::MainBuilder::Validity runLists() { + capnp::StreamFdMessageReader reader(STDIN_FILENO); + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + kj::str(reader.getRoot()); + })) { + KJ_LOG(ERROR, "threw"); + } + return true; + } + + kj::MainBuilder::Validity canonicalize() { + // (Test case contributed by David Renshaw.) + + kj::Array canonical; + bool equal = false; + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + capnp::ReaderOptions options; + + // The default traversal limit of 8 * 1024 * 1024 causes + // AFL to think that it has found "hang" bugs. + options.traversalLimitInWords = 8 * 1024; + + capnp::StreamFdMessageReader message(0, options); // read from stdin + TestAllTypes::Reader myStruct = message.getRoot(); + canonical = capnp::canonicalize(myStruct); + + kj::ArrayPtr segments[1] = {canonical.asPtr()}; + capnp::SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + + auto originalAny = message.getRoot(); + + // Discard cases where the original message is null. + KJ_ASSERT(!originalAny.isNull()); + + equal = originalAny == reader.getRoot(); + })) { + // Probably some kind of decoding exception. + KJ_LOG(ERROR, "threw"); + context.exit(); + } + + KJ_ASSERT(equal); + + kj::ArrayPtr segments[1] = {canonical.asPtr()}; + capnp::SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + KJ_ASSERT(reader.isCanonical()); + + kj::Array canonical2; + { + capnp::ReaderOptions options; + options.traversalLimitInWords = 8 * 1024; + + TestAllTypes::Reader myStruct = reader.getRoot(); + canonical2 = capnp::canonicalize(myStruct); + } + + KJ_ASSERT(canonical.size() == canonical2.size()); + auto b1 = canonical.asBytes(); + auto b2 = canonical2.asBytes(); + for (int idx = 0; idx < b1.size(); ++idx) { + KJ_ASSERT(b1[idx] == b2[idx], idx, b1.size()); + } + + return true; + } + +private: + kj::ProcessContext& context; +}; + +} // namespace +} // namespace _ +} // namespace capnp + +KJ_MAIN(capnp::_::AflTestMain); diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/any-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/any-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,439 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "any.h" +#include "message.h" +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Any, AnyPointer) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + checkTestMessage(root.getAnyPointerField().getAs()); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); + + root.getAnyPointerField().setAs("foo"); + EXPECT_EQ("foo", root.getAnyPointerField().getAs()); + EXPECT_EQ("foo", root.asReader().getAnyPointerField().getAs()); + + root.getAnyPointerField().setAs(data("foo")); + EXPECT_EQ(data("foo"), root.getAnyPointerField().getAs()); + EXPECT_EQ(data("foo"), root.asReader().getAnyPointerField().getAs()); + + { + root.getAnyPointerField().setAs>({123, 456, 789}); + + { + List::Builder list = root.getAnyPointerField().getAs>(); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(123u, list[0]); + EXPECT_EQ(456u, list[1]); + EXPECT_EQ(789u, list[2]); + } + + { + List::Reader list = root.asReader().getAnyPointerField().getAs>(); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(123u, list[0]); + EXPECT_EQ(456u, list[1]); + EXPECT_EQ(789u, list[2]); + } + } + + { + root.getAnyPointerField().setAs>({"foo", "bar"}); + + { + List::Builder list = root.getAnyPointerField().getAs>(); + ASSERT_EQ(2u, list.size()); + EXPECT_EQ("foo", list[0]); + EXPECT_EQ("bar", list[1]); + } + + { + List::Reader list = root.asReader().getAnyPointerField().getAs>(); + ASSERT_EQ(2u, list.size()); + EXPECT_EQ("foo", list[0]); + EXPECT_EQ("bar", list[1]); + } + } + + { + { + List::Builder list = root.getAnyPointerField().initAs>(2); + ASSERT_EQ(2u, list.size()); + initTestMessage(list[0]); + } + + { + List::Builder list = root.getAnyPointerField().getAs>(); + ASSERT_EQ(2u, list.size()); + checkTestMessage(list[0]); + checkTestMessageAllZero(list[1]); + } + + { + List::Reader list = + root.asReader().getAnyPointerField().getAs>(); + ASSERT_EQ(2u, list.size()); + checkTestMessage(list[0]); + checkTestMessageAllZero(list[1]); + } + } +} + +TEST(Any, AnyStruct) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + checkTestMessage(root.getAnyPointerField().getAs()); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); + + auto allTypes = root.getAnyPointerField().getAs().as(); + auto allTypesReader = root.getAnyPointerField().getAs().asReader().as(); + allTypes.setInt32Field(100); + EXPECT_EQ(100, allTypes.getInt32Field()); + EXPECT_EQ(100, allTypesReader.getInt32Field()); + + EXPECT_EQ(48, root.getAnyPointerField().getAs().getDataSection().size()); + EXPECT_EQ(20, root.getAnyPointerField().getAs().getPointerSection().size()); + + EXPECT_EQ(48, root.getAnyPointerField().asReader().getAs().getDataSection().size()); + EXPECT_EQ(20, root.getAnyPointerField().asReader().getAs().getPointerSection().size()); + + auto b = toAny(root.getAnyPointerField().getAs()); + EXPECT_EQ(48, b.getDataSection().size()); + EXPECT_EQ(20, b.getPointerSection().size()); + +#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h. + b = root.getAnyPointerField().getAs(); + EXPECT_EQ(48, b.getDataSection().size()); + EXPECT_EQ(20, b.getPointerSection().size()); +#endif + + auto r = toAny(root.getAnyPointerField().getAs().asReader()); + EXPECT_EQ(48, r.getDataSection().size()); + EXPECT_EQ(20, r.getPointerSection().size()); + + r = toAny(root.getAnyPointerField().getAs()).asReader(); + EXPECT_EQ(48, r.getDataSection().size()); + EXPECT_EQ(20, r.getPointerSection().size()); + +#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h. + r = root.getAnyPointerField().getAs().asReader(); + EXPECT_EQ(48, r.getDataSection().size()); + EXPECT_EQ(20, r.getPointerSection().size()); +#endif + + { + MallocMessageBuilder b2; + auto root2 = b2.getRoot(); + auto sb = root2.getAnyPointerField().initAsAnyStruct( + r.getDataSection().size() / 8, r.getPointerSection().size()); + + EXPECT_EQ(48, sb.getDataSection().size()); + EXPECT_EQ(20, sb.getPointerSection().size()); + + // TODO: is there a higher-level API for this? + memcpy(sb.getDataSection().begin(), r.getDataSection().begin(), r.getDataSection().size()); + } + + { + auto ptrs = r.getPointerSection(); + EXPECT_EQ("foo", ptrs[0].getAs()); + EXPECT_EQ("bar", kj::heapString(ptrs[1].getAs().asChars())); + EXPECT_EQ("xyzzy", ptrs[15].getAs>()[1]); + } + + { + auto ptrs = b.getPointerSection(); + EXPECT_EQ("foo", ptrs[0].getAs()); + EXPECT_EQ("bar", kj::heapString(ptrs[1].getAs().asChars())); + EXPECT_EQ("xyzzy", ptrs[15].getAs>()[1]); + } +} + +TEST(Any, AnyList) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + List::Builder b = root.getAnyPointerField().initAs>(2); + initTestMessage(b[0]); + + auto ptr = root.getAnyPointerField().getAs(); + + EXPECT_EQ(2, ptr.size()); + EXPECT_EQ(48, ptr.as>()[0].getDataSection().size()); + EXPECT_EQ(20, ptr.as>()[0].getPointerSection().size()); + + auto readPtr = root.getAnyPointerField().asReader().getAs(); + + EXPECT_EQ(2, readPtr.size()); + EXPECT_EQ(48, readPtr.as>()[0].getDataSection().size()); + EXPECT_EQ(20, readPtr.as>()[0].getPointerSection().size()); + + auto alb = toAny(root.getAnyPointerField().getAs>()); + EXPECT_EQ(2, alb.size()); + EXPECT_EQ(48, alb.as>()[0].getDataSection().size()); + EXPECT_EQ(20, alb.as>()[0].getPointerSection().size()); + +#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h. + alb = root.getAnyPointerField().getAs>(); + EXPECT_EQ(2, alb.size()); + EXPECT_EQ(48, alb.as>()[0].getDataSection().size()); + EXPECT_EQ(20, alb.as>()[0].getPointerSection().size()); +#endif + + auto alr = toAny(root.getAnyPointerField().getAs>().asReader()); + EXPECT_EQ(2, alr.size()); + EXPECT_EQ(48, alr.as>()[0].getDataSection().size()); + EXPECT_EQ(20, alr.as>()[0].getPointerSection().size()); + + alr = toAny(root.getAnyPointerField().getAs>()).asReader(); + EXPECT_EQ(2, alr.size()); + EXPECT_EQ(48, alr.as>()[0].getDataSection().size()); + EXPECT_EQ(20, alr.as>()[0].getPointerSection().size()); + +#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h. + alr = root.getAnyPointerField().getAs>().asReader(); + EXPECT_EQ(2, alr.size()); + EXPECT_EQ(48, alr.as>()[0].getDataSection().size()); + EXPECT_EQ(20, alr.as>()[0].getPointerSection().size()); +#endif +} + +TEST(Any, AnyStructListCapInSchema) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + { + initTestMessage(root.initAnyStructFieldAs()); + AnyStruct::Builder anyStruct = root.getAnyStructField(); + checkTestMessage(anyStruct.as()); + checkTestMessage(anyStruct.asReader().as()); + + EXPECT_TRUE(root.hasAnyStructField()); + auto orphan = root.disownAnyStructField(); + checkTestMessage(orphan.getReader().as()); + EXPECT_FALSE(root.hasAnyStructField()); + + root.adoptAnyStructField(kj::mv(orphan)); + EXPECT_TRUE(root.hasAnyStructField()); + checkTestMessage(root.getAnyStructField().as()); + } + + { + List::Builder list = root.initAnyListFieldAs>(3); + list.set(0, 123); + list.set(1, 456); + list.set(2, 789); + + AnyList::Builder anyList = root.getAnyListField(); + checkList(anyList.as>(), {123, 456, 789}); + + EXPECT_TRUE(root.hasAnyListField()); + auto orphan = root.disownAnyListField(); + checkList(orphan.getReader().as>(), {123, 456, 789}); + EXPECT_FALSE(root.hasAnyListField()); + + root.adoptAnyListField(kj::mv(orphan)); + EXPECT_TRUE(root.hasAnyListField()); + checkList(root.getAnyListField().as>(), {123, 456, 789}); + } + +#if !CAPNP_LITE + // This portion of the test relies on a Client, not present in lite-mode. + { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + int callCount = 0; + root.setCapabilityField(kj::heap(callCount)); + Capability::Client client = root.getCapabilityField(); + auto req = client.castAs().fooRequest(); + req.setI(123); + req.setJ(true); + req.send().wait(waitScope); + EXPECT_EQ(1, callCount); + } +#endif +} + +KJ_TEST("Builder::isStruct() does not corrupt segment pointer") { + MallocMessageBuilder builder(1); // small first segment + auto root = builder.getRoot(); + + // Do a lot of allocations so that there is likely a segment with a decent + // amount of free space. + initTestMessage(root.initAs()); + + // This will probably get allocated in a segment that still has room for the + // Data allocation below. + root.initAs(); + + // At one point, this caused root.builder.segment to point to the segment + // where the struct is allocated, rather than segment where the root pointer + // lives, i.e. segment zero. + EXPECT_TRUE(root.isStruct()); + + // If root.builder.segment points to the wrong segment and that segment has free + // space, then this triggers a DREQUIRE failure in WirePointer::setKindAndTarget(). + root.initAs(1); +} + +TEST(Any, Equals) { + MallocMessageBuilder builderA; + auto rootA = builderA.getRoot(); + auto anyA = builderA.getRoot(); + initTestMessage(rootA); + + MallocMessageBuilder builderB; + auto rootB = builderB.getRoot(); + auto anyB = builderB.getRoot(); + initTestMessage(rootB); + + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootA.setBoolField(false); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootB.setBoolField(false); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootB.setEnumField(test::TestEnum::GARPLY); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootA.setEnumField(test::TestEnum::GARPLY); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootA.getStructField().setTextField("buzz"); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootB.getStructField().setTextField("buzz"); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootA.initVoidList(3); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootB.initVoidList(3); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootA.getBoolList().set(2, true); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootB.getBoolList().set(2, true); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); + + rootB.getStructList()[1].setTextField("my NEW structlist 2"); + EXPECT_EQ(Equality::NOT_EQUAL, anyA.equals(anyB)); + + rootA.getStructList()[1].setTextField("my NEW structlist 2"); + EXPECT_EQ(Equality::EQUAL, anyA.equals(anyB)); +} + +KJ_TEST("Bit list with nonzero pad bits") { + AlignedData<2> segment1 = {{ + 0x01, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, // eleven bit-sized elements + 0xee, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // twelfth bit is set! + }}; + kj::ArrayPtr segments1[1] = { + kj::arrayPtr(segment1.words, 2) + }; + SegmentArrayMessageReader message1(kj::arrayPtr(segments1, 1)); + + AlignedData<2> segment2 = {{ + 0x01, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, // eleven bit-sized elements + 0xee, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // twelfth bit is not set + }}; + kj::ArrayPtr segments2[1] = { + kj::arrayPtr(segment2.words, 2) + }; + SegmentArrayMessageReader message2(kj::arrayPtr(segments2, 1)); + + // Should be equal, despite nonzero padding. + KJ_ASSERT(message1.getRoot() == message2.getRoot()); +} + +KJ_TEST("Pointer list unequal to struct list") { + AlignedData<1> segment1 = {{ + // list with zero pointer-sized elements + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments1[1] = { + kj::arrayPtr(segment1.words, 1) + }; + SegmentArrayMessageReader message1(kj::arrayPtr(segments1, 1)); + + AlignedData<2> segment2 = {{ + // struct list of length zero + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + + // struct list tag, zero elements + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments2[1] = { + kj::arrayPtr(segment2.words, 2) + }; + SegmentArrayMessageReader message2(kj::arrayPtr(segments2, 1)); + + EXPECT_EQ(Equality::NOT_EQUAL, message1.getRoot().equals(message2.getRoot())); +} + +KJ_TEST("Truncating non-null pointer fields does not preserve equality") { + AlignedData<3> segment1 = {{ + // list with one data word and one pointer field + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + + // data word + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + + // non-null pointer to zero-sized struct + 0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments1[1] = { + kj::arrayPtr(segment1.words, 3) + }; + SegmentArrayMessageReader message1(kj::arrayPtr(segments1, 1)); + + AlignedData<2> segment2 = {{ + // list with one data word and zero pointers + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // data word + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + }}; + kj::ArrayPtr segments2[1] = { + kj::arrayPtr(segment2.words, 2) + }; + SegmentArrayMessageReader message2(kj::arrayPtr(segments2, 1)); + + EXPECT_EQ(Equality::NOT_EQUAL, + message1.getRoot().equals(message2.getRoot())); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/any.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/any.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,269 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "any.h" + +#include + +#if !CAPNP_LITE +#include "capability.h" +#endif // !CAPNP_LITE + +namespace capnp { + +#if !CAPNP_LITE + +kj::Own PipelineHook::getPipelinedCap(kj::Array&& ops) { + return getPipelinedCap(ops.asPtr()); +} + +kj::Own AnyPointer::Reader::getPipelinedCap( + kj::ArrayPtr ops) const { + _::PointerReader pointer = reader; + + for (auto& op: ops) { + switch (op.type) { + case PipelineOp::Type::NOOP: + break; + + case PipelineOp::Type::GET_POINTER_FIELD: + pointer = pointer.getStruct(nullptr).getPointerField(bounded(op.pointerIndex) * POINTERS); + break; + } + } + + return pointer.getCapability(); +} + +AnyPointer::Pipeline AnyPointer::Pipeline::noop() { + auto newOps = kj::heapArray(ops.size()); + for (auto i: kj::indices(ops)) { + newOps[i] = ops[i]; + } + return Pipeline(hook->addRef(), kj::mv(newOps)); +} + +AnyPointer::Pipeline AnyPointer::Pipeline::getPointerField(uint16_t pointerIndex) { + auto newOps = kj::heapArray(ops.size() + 1); + for (auto i: kj::indices(ops)) { + newOps[i] = ops[i]; + } + auto& newOp = newOps[ops.size()]; + newOp.type = PipelineOp::GET_POINTER_FIELD; + newOp.pointerIndex = pointerIndex; + + return Pipeline(hook->addRef(), kj::mv(newOps)); +} + +kj::Own AnyPointer::Pipeline::asCap() { + return hook->getPipelinedCap(ops); +} + +#endif // !CAPNP_LITE + +Equality AnyStruct::Reader::equals(AnyStruct::Reader right) { + auto dataL = getDataSection(); + size_t dataSizeL = dataL.size(); + while(dataSizeL > 0 && dataL[dataSizeL - 1] == 0) { + -- dataSizeL; + } + + auto dataR = right.getDataSection(); + size_t dataSizeR = dataR.size(); + while(dataSizeR > 0 && dataR[dataSizeR - 1] == 0) { + -- dataSizeR; + } + + if(dataSizeL != dataSizeR) { + return Equality::NOT_EQUAL; + } + + if(0 != memcmp(dataL.begin(), dataR.begin(), dataSizeL)) { + return Equality::NOT_EQUAL; + } + + auto ptrsL = getPointerSection(); + size_t ptrsSizeL = ptrsL.size(); + while (ptrsSizeL > 0 && ptrsL[ptrsSizeL - 1].isNull()) { + -- ptrsSizeL; + } + + auto ptrsR = right.getPointerSection(); + size_t ptrsSizeR = ptrsR.size(); + while (ptrsSizeR > 0 && ptrsR[ptrsSizeR - 1].isNull()) { + -- ptrsSizeR; + } + + if(ptrsSizeL != ptrsSizeR) { + return Equality::NOT_EQUAL; + } + + size_t i = 0; + + auto eqResult = Equality::EQUAL; + for (; i < ptrsSizeL; i++) { + auto l = ptrsL[i]; + auto r = ptrsR[i]; + switch(l.equals(r)) { + case Equality::EQUAL: + break; + case Equality::NOT_EQUAL: + return Equality::NOT_EQUAL; + case Equality::UNKNOWN_CONTAINS_CAPS: + eqResult = Equality::UNKNOWN_CONTAINS_CAPS; + break; + default: + KJ_UNREACHABLE; + } + } + + return eqResult; +} + +kj::StringPtr KJ_STRINGIFY(Equality res) { + switch(res) { + case Equality::NOT_EQUAL: + return "NOT_EQUAL"; + case Equality::EQUAL: + return "EQUAL"; + case Equality::UNKNOWN_CONTAINS_CAPS: + return "UNKNOWN_CONTAINS_CAPS"; + } + KJ_UNREACHABLE; +} + +Equality AnyList::Reader::equals(AnyList::Reader right) { + if(size() != right.size()) { + return Equality::NOT_EQUAL; + } + + if (getElementSize() != right.getElementSize()) { + return Equality::NOT_EQUAL; + } + + auto eqResult = Equality::EQUAL; + switch(getElementSize()) { + case ElementSize::VOID: + case ElementSize::BIT: + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: { + size_t cmpSize = getRawBytes().size(); + + if (getElementSize() == ElementSize::BIT && size() % 8 != 0) { + // The list does not end on a byte boundary. We need special handling for the final + // byte because we only care about the bits that are actually elements of the list. + + uint8_t mask = (1 << (size() % 8)) - 1; // lowest size() bits set + if ((getRawBytes()[cmpSize - 1] & mask) != (right.getRawBytes()[cmpSize - 1] & mask)) { + return Equality::NOT_EQUAL; + } + cmpSize -= 1; + } + + if (memcmp(getRawBytes().begin(), right.getRawBytes().begin(), cmpSize) == 0) { + return Equality::EQUAL; + } else { + return Equality::NOT_EQUAL; + } + } + case ElementSize::POINTER: + case ElementSize::INLINE_COMPOSITE: { + auto llist = as>(); + auto rlist = right.as>(); + for(size_t i = 0; i < size(); i++) { + switch(llist[i].equals(rlist[i])) { + case Equality::EQUAL: + break; + case Equality::NOT_EQUAL: + return Equality::NOT_EQUAL; + case Equality::UNKNOWN_CONTAINS_CAPS: + eqResult = Equality::UNKNOWN_CONTAINS_CAPS; + break; + default: + KJ_UNREACHABLE; + } + } + return eqResult; + } + } + KJ_UNREACHABLE; +} + +Equality AnyPointer::Reader::equals(AnyPointer::Reader right) { + if(getPointerType() != right.getPointerType()) { + return Equality::NOT_EQUAL; + } + switch(getPointerType()) { + case PointerType::NULL_: + return Equality::EQUAL; + case PointerType::STRUCT: + return getAs().equals(right.getAs()); + case PointerType::LIST: + return getAs().equals(right.getAs()); + case PointerType::CAPABILITY: + return Equality::UNKNOWN_CONTAINS_CAPS; + } + // There aren't currently any other types of pointers + KJ_UNREACHABLE; +} + +bool AnyPointer::Reader::operator==(AnyPointer::Reader right) { + switch(equals(right)) { + case Equality::EQUAL: + return true; + case Equality::NOT_EQUAL: + return false; + case Equality::UNKNOWN_CONTAINS_CAPS: + KJ_FAIL_REQUIRE( + "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); + } + KJ_UNREACHABLE; +} + +bool AnyStruct::Reader::operator==(AnyStruct::Reader right) { + switch(equals(right)) { + case Equality::EQUAL: + return true; + case Equality::NOT_EQUAL: + return false; + case Equality::UNKNOWN_CONTAINS_CAPS: + KJ_FAIL_REQUIRE( + "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); + } + KJ_UNREACHABLE; +} + +bool AnyList::Reader::operator==(AnyList::Reader right) { + switch(equals(right)) { + case Equality::EQUAL: + return true; + case Equality::NOT_EQUAL: + return false; + case Equality::UNKNOWN_CONTAINS_CAPS: + KJ_FAIL_REQUIRE( + "operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case"); + } + KJ_UNREACHABLE; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/any.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/any.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1073 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ANY_H_ +#define CAPNP_ANY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "pointer-helpers.h" +#include "orphan.h" +#include "list.h" + +namespace capnp { + +class StructSchema; +class ListSchema; +class InterfaceSchema; +class Orphanage; +class ClientHook; +class PipelineHook; +struct PipelineOp; +struct AnyPointer; + +struct AnyList { + AnyList() = delete; + + class Reader; + class Builder; +}; + +struct AnyStruct { + AnyStruct() = delete; + + class Reader; + class Builder; + class Pipeline; +}; + +template<> +struct List { + List() = delete; + + class Reader; + class Builder; +}; + +namespace _ { // private +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +} // namespace _ (private) + +// ======================================================================================= +// AnyPointer! + +enum class Equality { + NOT_EQUAL, + EQUAL, + UNKNOWN_CONTAINS_CAPS +}; + +kj::StringPtr KJ_STRINGIFY(Equality res); + +struct AnyPointer { + // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary + // object. + + AnyPointer() = delete; + + class Reader { + public: + typedef AnyPointer Reads; + + Reader() = default; + inline Reader(_::PointerReader reader): reader(reader) {} + + inline MessageSize targetSize() const; + // Get the total size of the target object and all its children. + + inline PointerType getPointerType() const; + + inline bool isNull() const { return getPointerType() == PointerType::NULL_; } + inline bool isStruct() const { return getPointerType() == PointerType::STRUCT; } + inline bool isList() const { return getPointerType() == PointerType::LIST; } + inline bool isCapability() const { return getPointerType() == PointerType::CAPABILITY; } + + Equality equals(AnyPointer::Reader right); + bool operator==(AnyPointer::Reader right); + inline bool operator!=(AnyPointer::Reader right) { + return !(*this == right); + } + + template + inline ReaderFor getAs() const; + // Valid for T = any generated struct type, interface type, List, Text, or Data. + + template + inline ReaderFor getAs(StructSchema schema) const; + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline ReaderFor getAs(ListSchema schema) const; + // Only valid for T = DynamicList. Requires `#include `. + + template + inline ReaderFor getAs(InterfaceSchema schema) const; + // Only valid for T = DynamicCapability. Requires `#include `. + +#if !CAPNP_LITE + kj::Own getPipelinedCap(kj::ArrayPtr ops) const; + // Used by RPC system to implement pipelining. Applications generally shouldn't use this + // directly. +#endif // !CAPNP_LITE + + private: + _::PointerReader reader; + friend struct AnyPointer; + friend class Orphanage; + friend class CapReaderContext; + friend struct _::PointerHelpers; + }; + + class Builder { + public: + typedef AnyPointer Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)) {} + inline Builder(_::PointerBuilder builder): builder(builder) {} + + inline MessageSize targetSize() const; + // Get the total size of the target object and all its children. + + inline PointerType getPointerType(); + + inline bool isNull() { return getPointerType() == PointerType::NULL_; } + inline bool isStruct() { return getPointerType() == PointerType::STRUCT; } + inline bool isList() { return getPointerType() == PointerType::LIST; } + inline bool isCapability() { return getPointerType() == PointerType::CAPABILITY; } + + inline Equality equals(AnyPointer::Reader right) { + return asReader().equals(right); + } + inline bool operator==(AnyPointer::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyPointer::Reader right) { + return !(*this == right); + } + + inline void clear(); + // Set to null. + + template + inline BuilderFor getAs(); + // Valid for T = any generated struct type, List, Text, or Data. + + template + inline BuilderFor getAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline BuilderFor getAs(ListSchema schema); + // Only valid for T = DynamicList. Requires `#include `. + + template + inline BuilderFor getAs(InterfaceSchema schema); + // Only valid for T = DynamicCapability. Requires `#include `. + + template + inline BuilderFor initAs(); + // Valid for T = any generated struct type. + + template + inline BuilderFor initAs(uint elementCount); + // Valid for T = List, Text, or Data. + + template + inline BuilderFor initAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline BuilderFor initAs(ListSchema schema, uint elementCount); + // Only valid for T = DynamicList. Requires `#include `. + + inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount); + // Note: Does not accept INLINE_COMPOSITE for elementSize. + + inline List::Builder initAsListOfAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount, uint elementCount); + + inline AnyStruct::Builder initAsAnyStruct(uint16_t dataWordCount, uint16_t pointerCount); + + template + inline void setAs(ReaderFor value); + // Valid for ReaderType = T::Reader for T = any generated struct type, List, Text, Data, + // DynamicStruct, or DynamicList (the dynamic types require `#include `). + + template + inline void setAs(std::initializer_list>> list); + // Valid for T = List. + + template + inline void setCanonicalAs(ReaderFor value); + + inline void set(Reader value) { builder.copyFrom(value.reader); } + // Set to a copy of another AnyPointer. + + inline void setCanonical(Reader value) { builder.copyFrom(value.reader, true); } + + template + inline void adopt(Orphan&& orphan); + // Valid for T = any generated struct type, List, Text, Data, DynamicList, DynamicStruct, + // or DynamicValue (the dynamic types require `#include `). + + template + inline Orphan disownAs(); + // Valid for T = any generated struct type, List, Text, Data. + + template + inline Orphan disownAs(StructSchema schema); + // Only valid for T = DynamicStruct. Requires `#include `. + + template + inline Orphan disownAs(ListSchema schema); + // Only valid for T = DynamicList. Requires `#include `. + + template + inline Orphan disownAs(InterfaceSchema schema); + // Only valid for T = DynamicCapability. Requires `#include `. + + inline Orphan disown(); + // Disown without a type. + + inline Reader asReader() const { return Reader(builder.asReader()); } + inline operator Reader() const { return Reader(builder.asReader()); } + + private: + _::PointerBuilder builder; + friend class Orphanage; + friend class CapBuilderContext; + friend struct _::PointerHelpers; + }; + +#if !CAPNP_LITE + class Pipeline { + public: + typedef AnyPointer Pipelines; + + inline Pipeline(decltype(nullptr)) {} + inline explicit Pipeline(kj::Own&& hook): hook(kj::mv(hook)) {} + + Pipeline noop(); + // Just make a copy. + + Pipeline getPointerField(uint16_t pointerIndex); + // Deprecated. In the future, we should use .asAnyStruct.getPointerField. + + inline AnyStruct::Pipeline asAnyStruct(); + + kj::Own asCap(); + // Expect that the result is a capability and construct a pipelined version of it now. + + inline kj::Own releasePipelineHook() { return kj::mv(hook); } + // For use by RPC implementations. + + template ) == Kind::INTERFACE>> + inline operator T() { return T(asCap()); } + + private: + kj::Own hook; + kj::Array ops; + + inline Pipeline(kj::Own&& hook, kj::Array&& ops) + : hook(kj::mv(hook)), ops(kj::mv(ops)) {} + + friend class LocalClient; + friend class PipelineHook; + friend class AnyStruct::Pipeline; + }; +#endif // !CAPNP_LITE +}; + +template <> +class Orphan { + // An orphaned object of unknown type. + +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + inline Orphan(_::OrphanBuilder&& builder) + : builder(kj::mv(builder)) {} + + Orphan& operator=(Orphan&&) = default; + + template + inline Orphan(Orphan&& other): builder(kj::mv(other.builder)) {} + template + inline Orphan& operator=(Orphan&& other) { builder = kj::mv(other.builder); return *this; } + // Cast from typed orphan. + + // It's not possible to get an AnyPointer::{Reader,Builder} directly since there is no + // underlying pointer (the pointer would normally live in the parent, but this object is + // orphaned). It is possible, however, to request typed readers/builders. + + template + inline BuilderFor getAs(); + template + inline BuilderFor getAs(StructSchema schema); + template + inline BuilderFor getAs(ListSchema schema); + template + inline typename T::Client getAs(InterfaceSchema schema); + template + inline ReaderFor getAsReader() const; + template + inline ReaderFor getAsReader(StructSchema schema) const; + template + inline ReaderFor getAsReader(ListSchema schema) const; + template + inline typename T::Client getAsReader(InterfaceSchema schema) const; + + template + inline Orphan releaseAs(); + template + inline Orphan releaseAs(StructSchema schema); + template + inline Orphan releaseAs(ListSchema schema); + template + inline Orphan releaseAs(InterfaceSchema schema); + // Down-cast the orphan to a specific type. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + _::OrphanBuilder builder; + + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend class Orphan; + friend class AnyPointer::Builder; +}; + +template struct AnyTypeFor_; +template <> struct AnyTypeFor_ { typedef AnyStruct Type; }; +template <> struct AnyTypeFor_ { typedef AnyList Type; }; + +template +using AnyTypeFor = typename AnyTypeFor_::Type; + +template +inline ReaderFor>> toAny(T&& value) { + return ReaderFor>>( + _::PointerHelpers>::getInternalReader(value)); +} +template +inline BuilderFor>> toAny(T&& value) { + return BuilderFor>>( + _::PointerHelpers>::getInternalBuilder(kj::mv(value))); +} + +template <> +struct List { + // Note: This cannot be used for a list of structs, since such lists are not encoded as pointer + // lists! Use List. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline AnyPointer::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)): builder(ElementSize::POINTER) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline AnyPointer::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return AnyPointer::Builder(builder.getPointerElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; +}; + +class AnyStruct::Reader { +public: + typedef AnyStruct Reads; + + Reader() = default; + inline Reader(_::StructReader reader): _reader(reader) {} + + template ) == Kind::STRUCT>> + inline Reader(T&& value) + : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} + + kj::ArrayPtr getDataSection() { + return _reader.getDataSectionAsBlob(); + } + List::Reader getPointerSection() { + return List::Reader(_reader.getPointerSectionAsList()); + } + + kj::Array canonicalize() { + return _reader.canonicalize(); + } + + Equality equals(AnyStruct::Reader right); + bool operator==(AnyStruct::Reader right); + inline bool operator!=(AnyStruct::Reader right) { + return !(*this == right); + } + + template + ReaderFor as() const { + // T must be a struct type. + return typename T::Reader(_reader); + } +private: + _::StructReader _reader; + + template + friend struct _::PointerHelpers; + friend class Orphanage; +}; + +class AnyStruct::Builder { +public: + typedef AnyStruct Builds; + + inline Builder(decltype(nullptr)) {} + inline Builder(_::StructBuilder builder): _builder(builder) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::STRUCT>> + inline Builder(T&& value) + : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} +#endif + + inline kj::ArrayPtr getDataSection() { + return _builder.getDataSectionAsBlob(); + } + List::Builder getPointerSection() { + return List::Builder(_builder.getPointerSectionAsList()); + } + + inline Equality equals(AnyStruct::Reader right) { + return asReader().equals(right); + } + inline bool operator==(AnyStruct::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyStruct::Reader right) { + return !(*this == right); + } + + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return Reader(_builder.asReader()); } + + template + BuilderFor as() { + // T must be a struct type. + return typename T::Builder(_builder); + } +private: + _::StructBuilder _builder; + friend class Orphanage; + friend class CapBuilderContext; +}; + +#if !CAPNP_LITE +class AnyStruct::Pipeline { +public: + inline Pipeline(decltype(nullptr)): typeless(nullptr) {} + inline explicit Pipeline(AnyPointer::Pipeline&& typeless) + : typeless(kj::mv(typeless)) {} + + inline AnyPointer::Pipeline getPointerField(uint16_t pointerIndex) { + // Return a new Promise representing a sub-object of the result. `pointerIndex` is the index + // of the sub-object within the pointer section of the result (the result must be a struct). + // + // TODO(perf): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies. + // Also make `ops` into a Vector to optimize this. + return typeless.getPointerField(pointerIndex); + } + +private: + AnyPointer::Pipeline typeless; +}; +#endif // !CAPNP_LITE + +class List::Reader { +public: + typedef List Reads; + + inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline AnyStruct::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return AnyStruct::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; +}; + +class List::Builder { +public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)): builder(ElementSize::INLINE_COMPOSITE) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline AnyStruct::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return AnyStruct::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + +private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; +}; + +class AnyList::Reader { +public: + typedef AnyList Reads; + + inline Reader(): _reader(ElementSize::VOID) {} + inline Reader(_::ListReader reader): _reader(reader) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::LIST>> + inline Reader(T&& value) + : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} +#endif + + inline ElementSize getElementSize() { return _reader.getElementSize(); } + inline uint size() { return unbound(_reader.size() / ELEMENTS); } + + inline kj::ArrayPtr getRawBytes() { return _reader.asRawBytes(); } + + Equality equals(AnyList::Reader right); + bool operator==(AnyList::Reader right); + inline bool operator!=(AnyList::Reader right) { + return !(*this == right); + } + + template ReaderFor as() { + // T must be List. + return ReaderFor(_reader); + } +private: + _::ListReader _reader; + + template + friend struct _::PointerHelpers; + friend class Orphanage; +}; + +class AnyList::Builder { +public: + typedef AnyList Builds; + + inline Builder(decltype(nullptr)): _builder(ElementSize::VOID) {} + inline Builder(_::ListBuilder builder): _builder(builder) {} + +#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. + template ) == Kind::LIST>> + inline Builder(T&& value) + : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} +#endif + + inline ElementSize getElementSize() { return _builder.getElementSize(); } + inline uint size() { return unbound(_builder.size() / ELEMENTS); } + + Equality equals(AnyList::Reader right); + inline bool operator==(AnyList::Reader right) { + return asReader() == right; + } + inline bool operator!=(AnyList::Reader right) { + return !(*this == right); + } + + template BuilderFor as() { + // T must be List. + return BuilderFor(_builder); + } + + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return Reader(_builder.asReader()); } + +private: + _::ListBuilder _builder; + + friend class Orphanage; +}; + +// ======================================================================================= +// Pipeline helpers +// +// These relate to capabilities, but we don't declare them in capability.h because generated code +// for structs needs to know about these, even in files that contain no interfaces. + +#if !CAPNP_LITE + +struct PipelineOp { + // Corresponds to rpc.capnp's PromisedAnswer.Op. + + enum Type { + NOOP, // for convenience + + GET_POINTER_FIELD + + // There may be other types in the future... + }; + + Type type; + union { + uint16_t pointerIndex; // for GET_POINTER_FIELD + }; +}; + +class PipelineHook { + // Represents a currently-running call, and implements pipelined requests on its result. + +public: + virtual kj::Own addRef() = 0; + // Increment this object's reference count. + + virtual kj::Own getPipelinedCap(kj::ArrayPtr ops) = 0; + // Extract a promised Capability from the results. + + virtual kj::Own getPipelinedCap(kj::Array&& ops); + // Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases. + // Default implementation just calls the other version. + + template > + static inline kj::Own from(Pipeline&& pipeline); + +private: + template struct FromImpl; +}; + +#endif // !CAPNP_LITE + +// ======================================================================================= +// Inline implementation details + +inline MessageSize AnyPointer::Reader::targetSize() const { + return reader.targetSize().asPublic(); +} + +inline PointerType AnyPointer::Reader::getPointerType() const { + return reader.getPointerType(); +} + +template +inline ReaderFor AnyPointer::Reader::getAs() const { + return _::PointerHelpers::get(reader); +} + +inline MessageSize AnyPointer::Builder::targetSize() const { + return asReader().targetSize(); +} + +inline PointerType AnyPointer::Builder::getPointerType() { + return builder.getPointerType(); +} + +inline void AnyPointer::Builder::clear() { + return builder.clear(); +} + +template +inline BuilderFor AnyPointer::Builder::getAs() { + return _::PointerHelpers::get(builder); +} + +template +inline BuilderFor AnyPointer::Builder::initAs() { + return _::PointerHelpers::init(builder); +} + +template +inline BuilderFor AnyPointer::Builder::initAs(uint elementCount) { + return _::PointerHelpers::init(builder, elementCount); +} + +inline AnyList::Builder AnyPointer::Builder::initAsAnyList( + ElementSize elementSize, uint elementCount) { + return AnyList::Builder(builder.initList(elementSize, bounded(elementCount) * ELEMENTS)); +} + +inline List::Builder AnyPointer::Builder::initAsListOfAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { + return List::Builder(builder.initStructList(bounded(elementCount) * ELEMENTS, + _::StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); +} + +inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct( + uint16_t dataWordCount, uint16_t pointerCount) { + return AnyStruct::Builder(builder.initStruct( + _::StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); +} + +template +inline void AnyPointer::Builder::setAs(ReaderFor value) { + return _::PointerHelpers::set(builder, value); +} + +template +inline void AnyPointer::Builder::setCanonicalAs(ReaderFor value) { + return _::PointerHelpers::setCanonical(builder, value); +} + +template +inline void AnyPointer::Builder::setAs( + std::initializer_list>> list) { + return _::PointerHelpers::set(builder, list); +} + +template +inline void AnyPointer::Builder::adopt(Orphan&& orphan) { + _::PointerHelpers::adopt(builder, kj::mv(orphan)); +} + +template +inline Orphan AnyPointer::Builder::disownAs() { + return _::PointerHelpers::disown(builder); +} + +inline Orphan AnyPointer::Builder::disown() { + return Orphan(builder.disown()); +} + +template <> struct ReaderFor_ { typedef AnyPointer::Reader Type; }; +template <> struct BuilderFor_ { typedef AnyPointer::Builder Type; }; +template <> struct ReaderFor_ { typedef AnyStruct::Reader Type; }; +template <> struct BuilderFor_ { typedef AnyStruct::Builder Type; }; + +template <> +struct Orphanage::GetInnerReader { + static inline _::PointerReader apply(const AnyPointer::Reader& t) { + return t.reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::PointerBuilder apply(AnyPointer::Builder& t) { + return t.builder; + } +}; + +template <> +struct Orphanage::GetInnerReader { + static inline _::StructReader apply(const AnyStruct::Reader& t) { + return t._reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(AnyStruct::Builder& t) { + return t._builder; + } +}; + +template <> +struct Orphanage::GetInnerReader { + static inline _::ListReader apply(const AnyList::Reader& t) { + return t._reader; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(AnyList::Builder& t) { + return t._builder; + } +}; + +template +inline BuilderFor Orphan::getAs() { + return _::OrphanGetImpl::apply(builder); +} +template +inline ReaderFor Orphan::getAsReader() const { + return _::OrphanGetImpl::applyReader(builder); +} +template +inline Orphan Orphan::releaseAs() { + return Orphan(kj::mv(builder)); +} + +// Using AnyPointer as the template type should work... + +template <> +inline typename AnyPointer::Reader AnyPointer::Reader::getAs() const { + return *this; +} +template <> +inline typename AnyPointer::Builder AnyPointer::Builder::getAs() { + return *this; +} +template <> +inline typename AnyPointer::Builder AnyPointer::Builder::initAs() { + clear(); + return *this; +} +template <> +inline void AnyPointer::Builder::setAs(AnyPointer::Reader value) { + return builder.copyFrom(value.reader); +} +template <> +inline void AnyPointer::Builder::adopt(Orphan&& orphan) { + builder.adopt(kj::mv(orphan.builder)); +} +template <> +inline Orphan AnyPointer::Builder::disownAs() { + return Orphan(builder.disown()); +} +template <> +inline Orphan Orphan::releaseAs() { + return kj::mv(*this); +} + +namespace _ { // private + +// Specialize PointerHelpers for AnyPointer. + +template <> +struct PointerHelpers { + static inline AnyPointer::Reader get(PointerReader reader, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return AnyPointer::Reader(reader); + } + static inline AnyPointer::Builder get(PointerBuilder builder, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return AnyPointer::Builder(builder); + } + static inline void set(PointerBuilder builder, AnyPointer::Reader value) { + AnyPointer::Builder(builder).set(value); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } + static inline _::PointerReader getInternalReader(const AnyPointer::Reader& reader) { + return reader.reader; + } + static inline _::PointerBuilder getInternalBuilder(AnyPointer::Builder&& builder) { + return builder.builder; + } +}; + +template <> +struct PointerHelpers { + static inline AnyStruct::Reader get( + PointerReader reader, const word* defaultValue = nullptr) { + return AnyStruct::Reader(reader.getStruct(defaultValue)); + } + static inline AnyStruct::Builder get( + PointerBuilder builder, const word* defaultValue = nullptr) { + // TODO(someday): Allow specifying the size somehow? + return AnyStruct::Builder(builder.getStruct( + _::StructSize(ZERO * WORDS, ZERO * POINTERS), defaultValue)); + } + static inline void set(PointerBuilder builder, AnyStruct::Reader value) { + builder.setStruct(value._reader); + } + static inline AnyStruct::Builder init( + PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount) { + return AnyStruct::Builder(builder.initStruct( + StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); + } + + static void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +template <> +struct PointerHelpers { + static inline AnyList::Reader get( + PointerReader reader, const word* defaultValue = nullptr) { + return AnyList::Reader(reader.getListAnySize(defaultValue)); + } + static inline AnyList::Builder get( + PointerBuilder builder, const word* defaultValue = nullptr) { + return AnyList::Builder(builder.getListAnySize(defaultValue)); + } + static inline void set(PointerBuilder builder, AnyList::Reader value) { + builder.setList(value._reader); + } + static inline AnyList::Builder init( + PointerBuilder builder, ElementSize elementSize, uint elementCount) { + return AnyList::Builder(builder.initList( + elementSize, bounded(elementCount) * ELEMENTS)); + } + static inline AnyList::Builder init( + PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { + return AnyList::Builder(builder.initStructList( + bounded(elementCount) * ELEMENTS, + StructSize(bounded(dataWordCount) * WORDS, + bounded(pointerCount) * POINTERS))); + } + + static void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +template <> +struct OrphanGetImpl { + static inline AnyStruct::Builder apply(_::OrphanBuilder& builder) { + return AnyStruct::Builder(builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + static inline AnyStruct::Reader applyReader(const _::OrphanBuilder& builder) { + return AnyStruct::Reader(builder.asStructReader(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::StructSize(ZERO * WORDS, ZERO * POINTERS)); + } +}; + +template <> +struct OrphanGetImpl { + static inline AnyList::Builder apply(_::OrphanBuilder& builder) { + return AnyList::Builder(builder.asListAnySize()); + } + static inline AnyList::Reader applyReader(const _::OrphanBuilder& builder) { + return AnyList::Reader(builder.asListReaderAnySize()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +} // namespace _ (private) + +#if !CAPNP_LITE + +template +struct PipelineHook::FromImpl { + static inline kj::Own apply(typename T::Pipeline&& pipeline) { + return from(kj::mv(pipeline._typeless)); + } +}; + +template <> +struct PipelineHook::FromImpl { + static inline kj::Own apply(AnyPointer::Pipeline&& pipeline) { + return kj::mv(pipeline.hook); + } +}; + +template +inline kj::Own PipelineHook::from(Pipeline&& pipeline) { + return FromImpl::apply(kj::fwd(pipeline)); +} + +#endif // !CAPNP_LITE + +} // namespace capnp + +#endif // CAPNP_ANY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/arena.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/arena.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,341 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE +#include "arena.h" +#include "message.h" +#include +#include +#include +#include +#include +#include + +#if !CAPNP_LITE +#include "capability.h" +#endif // !CAPNP_LITE + +namespace capnp { +namespace _ { // private + +Arena::~Arena() noexcept(false) {} + +void ReadLimiter::unread(WordCount64 amount) { + // Be careful not to overflow here. Since ReadLimiter has no thread-safety, it's possible that + // the limit value was not updated correctly for one or more reads, and therefore unread() could + // overflow it even if it is only unreading bytes that were actually read. + uint64_t oldValue = limit; + uint64_t newValue = oldValue + unbound(amount / WORDS); + if (newValue > oldValue) { + limit = newValue; + } +} + +void SegmentReader::abortCheckObjectFault() { + KJ_LOG(FATAL, "checkObject()'s parameter is not in-range; this would segfault in opt mode", + "this is a serious bug in Cap'n Proto; please notify security@sandstorm.io"); + abort(); +} + +void SegmentBuilder::throwNotWritable() { + KJ_FAIL_REQUIRE( + "Tried to form a Builder to an external data segment referenced by the MessageBuilder. " + "When you use Orphanage::reference*(), you are not allowed to obtain Builders to the " + "referenced data, only Readers, because that data is const."); +} + +// ======================================================================================= + +static SegmentWordCount verifySegmentSize(size_t size) { + auto gsize = bounded(size) * WORDS; + return assertMaxBits(gsize, [&]() { + KJ_FAIL_REQUIRE("segment is too large", size); + }); +} + +inline ReaderArena::ReaderArena(MessageReader* message, const word* firstSegment, + SegmentWordCount firstSegmentSize) + : message(message), + readLimiter(bounded(message->getOptions().traversalLimitInWords) * WORDS), + segment0(this, SegmentId(0), firstSegment, firstSegmentSize, &readLimiter) {} + +inline ReaderArena::ReaderArena(MessageReader* message, kj::ArrayPtr firstSegment) + : ReaderArena(message, firstSegment.begin(), verifySegmentSize(firstSegment.size())) {} + +ReaderArena::ReaderArena(MessageReader* message) + : ReaderArena(message, message->getSegment(0)) {} + +ReaderArena::~ReaderArena() noexcept(false) {} + +SegmentReader* ReaderArena::tryGetSegment(SegmentId id) { + if (id == SegmentId(0)) { + if (segment0.getArray() == nullptr) { + return nullptr; + } else { + return &segment0; + } + } + + auto lock = moreSegments.lockExclusive(); + + SegmentMap* segments = nullptr; + KJ_IF_MAYBE(s, *lock) { + auto iter = s->get()->find(id.value); + if (iter != s->get()->end()) { + return iter->second; + } + segments = *s; + } + + kj::ArrayPtr newSegment = message->getSegment(id.value); + if (newSegment == nullptr) { + return nullptr; + } + + SegmentWordCount newSegmentSize = verifySegmentSize(newSegment.size()); + + if (*lock == nullptr) { + // OK, the segment exists, so allocate the map. + auto s = kj::heap(); + segments = s; + *lock = kj::mv(s); + } + + auto segment = kj::heap( + this, id, newSegment.begin(), newSegmentSize, &readLimiter); + SegmentReader* result = segment; + segments->insert(std::make_pair(id.value, mv(segment))); + return result; +} + +void ReaderArena::reportReadLimitReached() { + KJ_FAIL_REQUIRE("Exceeded message traversal limit. See capnp::ReaderOptions.") { + return; + } +} + +// ======================================================================================= + +BuilderArena::BuilderArena(MessageBuilder* message) + : message(message), segment0(nullptr, SegmentId(0), nullptr, nullptr) {} + +BuilderArena::BuilderArena(MessageBuilder* message, + kj::ArrayPtr segments) + : message(message), + segment0(this, SegmentId(0), segments[0].space.begin(), + verifySegmentSize(segments[0].space.size()), + &this->dummyLimiter, verifySegmentSize(segments[0].wordsUsed)) { + if (segments.size() > 1) { + kj::Vector> builders(segments.size() - 1); + + uint i = 1; + for (auto& segment: segments.slice(1, segments.size())) { + builders.add(kj::heap( + this, SegmentId(i++), segment.space.begin(), verifySegmentSize(segment.space.size()), + &this->dummyLimiter, verifySegmentSize(segment.wordsUsed))); + } + + kj::Vector> forOutput; + forOutput.resize(segments.size()); + + segmentWithSpace = builders.back(); + + this->moreSegments = kj::heap( + MultiSegmentState { kj::mv(builders), kj::mv(forOutput) }); + + } else { + segmentWithSpace = &segment0; + } +} + +BuilderArena::~BuilderArena() noexcept(false) {} + +SegmentBuilder* BuilderArena::getSegment(SegmentId id) { + // This method is allowed to fail if the segment ID is not valid. + if (id == SegmentId(0)) { + return &segment0; + } else { + KJ_IF_MAYBE(s, moreSegments) { + KJ_REQUIRE(id.value - 1 < s->get()->builders.size(), "invalid segment id", id.value); + return const_cast(s->get()->builders[id.value - 1].get()); + } else { + KJ_FAIL_REQUIRE("invalid segment id", id.value); + } + } +} + +BuilderArena::AllocateResult BuilderArena::allocate(SegmentWordCount amount) { + if (segment0.getArena() == nullptr) { + // We're allocating the first segment. + kj::ArrayPtr ptr = message->allocateSegment(unbound(amount / WORDS)); + auto actualSize = verifySegmentSize(ptr.size()); + + // Re-allocate segment0 in-place. This is a bit of a hack, but we have not returned any + // pointers to this segment yet, so it should be fine. + kj::dtor(segment0); + kj::ctor(segment0, this, SegmentId(0), ptr.begin(), actualSize, &this->dummyLimiter); + + segmentWithSpace = &segment0; + return AllocateResult { &segment0, segment0.allocate(amount) }; + } else { + if (segmentWithSpace != nullptr) { + // Check if there is space in an existing segment. + // TODO(perf): Check for available space in more than just the last segment. We don't + // want this to be O(n), though, so we'll need to maintain some sort of table. Complicating + // matters, we want SegmentBuilders::allocate() to be fast, so we can't update any such + // table when allocation actually happens. Instead, we could have a priority queue based + // on the last-known available size, and then re-check the size when we pop segments off it + // and shove them to the back of the queue if they have become too small. + word* attempt = segmentWithSpace->allocate(amount); + if (attempt != nullptr) { + return AllocateResult { segmentWithSpace, attempt }; + } + } + + // Need to allocate a new segment. + SegmentBuilder* result = addSegmentInternal(message->allocateSegment(unbound(amount / WORDS))); + + // Check this new segment first the next time we need to allocate. + segmentWithSpace = result; + + // Allocating from the new segment is guaranteed to succeed since we made it big enough. + return AllocateResult { result, result->allocate(amount) }; + } +} + +SegmentBuilder* BuilderArena::addExternalSegment(kj::ArrayPtr content) { + return addSegmentInternal(content); +} + +template +SegmentBuilder* BuilderArena::addSegmentInternal(kj::ArrayPtr content) { + // This check should never fail in practice, since you can't get an Orphanage without allocating + // the root segment. + KJ_REQUIRE(segment0.getArena() != nullptr, + "Can't allocate external segments before allocating the root segment."); + + auto contentSize = verifySegmentSize(content.size()); + + MultiSegmentState* segmentState; + KJ_IF_MAYBE(s, moreSegments) { + segmentState = *s; + } else { + auto newSegmentState = kj::heap(); + segmentState = newSegmentState; + moreSegments = kj::mv(newSegmentState); + } + + kj::Own newBuilder = kj::heap( + this, SegmentId(segmentState->builders.size() + 1), + content.begin(), contentSize, &this->dummyLimiter); + SegmentBuilder* result = newBuilder.get(); + segmentState->builders.add(kj::mv(newBuilder)); + + // Keep forOutput the right size so that we don't have to re-allocate during + // getSegmentsForOutput(), which callers might reasonably expect is a thread-safe method. + segmentState->forOutput.resize(segmentState->builders.size() + 1); + + return result; +} + +kj::ArrayPtr> BuilderArena::getSegmentsForOutput() { + // Although this is a read-only method, we shouldn't need to lock a mutex here because if this + // is called multiple times simultaneously, we should only be overwriting the array with the + // exact same data. If the number or size of segments is actually changing due to an activity + // in another thread, then the caller has a problem regardless of locking here. + + KJ_IF_MAYBE(segmentState, moreSegments) { + KJ_DASSERT(segmentState->get()->forOutput.size() == segmentState->get()->builders.size() + 1, + "segmentState->forOutput wasn't resized correctly when the last builder was added.", + segmentState->get()->forOutput.size(), segmentState->get()->builders.size()); + + kj::ArrayPtr> result( + &segmentState->get()->forOutput[0], segmentState->get()->forOutput.size()); + uint i = 0; + result[i++] = segment0.currentlyAllocated(); + for (auto& builder: segmentState->get()->builders) { + result[i++] = builder->currentlyAllocated(); + } + return result; + } else { + if (segment0.getArena() == nullptr) { + // We haven't actually allocated any segments yet. + return nullptr; + } else { + // We have only one segment so far. + segment0ForOutput = segment0.currentlyAllocated(); + return kj::arrayPtr(&segment0ForOutput, 1); + } + } +} + +SegmentReader* BuilderArena::tryGetSegment(SegmentId id) { + if (id == SegmentId(0)) { + if (segment0.getArena() == nullptr) { + // We haven't allocated any segments yet. + return nullptr; + } else { + return &segment0; + } + } else { + KJ_IF_MAYBE(segmentState, moreSegments) { + if (id.value <= segmentState->get()->builders.size()) { + // TODO(cleanup): Return a const SegmentReader and tediously constify all SegmentBuilder + // pointers throughout the codebase. + return const_cast(kj::implicitCast( + segmentState->get()->builders[id.value - 1].get())); + } + } + return nullptr; + } +} + +void BuilderArena::reportReadLimitReached() { + KJ_FAIL_ASSERT("Read limit reached for BuilderArena, but it should have been unlimited.") { + return; + } +} + +#if !CAPNP_LITE +kj::Maybe> BuilderArena::LocalCapTable::extractCap(uint index) { + if (index < capTable.size()) { + return capTable[index].map([](kj::Own& cap) { return cap->addRef(); }); + } else { + return nullptr; + } +} + +uint BuilderArena::LocalCapTable::injectCap(kj::Own&& cap) { + uint result = capTable.size(); + capTable.add(kj::mv(cap)); + return result; +} + +void BuilderArena::LocalCapTable::dropCap(uint index) { + KJ_ASSERT(index < capTable.size(), "Invalid capability descriptor in message.") { + return; + } + capTable[index] = nullptr; +} +#endif // !CAPNP_LITE + +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/arena.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/arena.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,496 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ARENA_H_ +#define CAPNP_ARENA_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#ifndef CAPNP_PRIVATE +#error "This header is only meant to be included by Cap'n Proto's own source code." +#endif + +#include +#include +#include +#include +#include +#include "common.h" +#include "message.h" +#include "layout.h" +#include + +#if !CAPNP_LITE +#include "capability.h" +#endif // !CAPNP_LITE + +namespace capnp { + +#if !CAPNP_LITE +class ClientHook; +#endif // !CAPNP_LITE + +namespace _ { // private + +class SegmentReader; +class SegmentBuilder; +class Arena; +class BuilderArena; +class ReadLimiter; + +class Segment; +typedef kj::Id SegmentId; + +class ReadLimiter { + // Used to keep track of how much data has been processed from a message, and cut off further + // processing if and when a particular limit is reached. This is primarily intended to guard + // against maliciously-crafted messages which contain cycles or overlapping structures. Cycles + // and overlapping are not permitted by the Cap'n Proto format because in many cases they could + // be used to craft a deceptively small message which could consume excessive server resources to + // process, perhaps even sending it into an infinite loop. Actually detecting overlaps would be + // time-consuming, so instead we just keep track of how many words worth of data structures the + // receiver has actually dereferenced and error out if this gets too high. + // + // This counting takes place as you call getters (for non-primitive values) on the message + // readers. If you call the same getter twice, the data it returns may be double-counted. This + // should not be a big deal in most cases -- just set the read limit high enough that it will + // only trigger in unreasonable cases. + // + // This class is "safe" to use from multiple threads for its intended use case. Threads may + // overwrite each others' changes to the counter, but this is OK because it only means that the + // limit is enforced a bit less strictly -- it will still kick in eventually. + +public: + inline explicit ReadLimiter(); // No limit. + inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words. + + inline void reset(WordCount64 limit); + + KJ_ALWAYS_INLINE(bool canRead(WordCount64 amount, Arena* arena)); + + void unread(WordCount64 amount); + // Adds back some words to the limit. Useful when the caller knows they are double-reading + // some data. + +private: + volatile uint64_t limit; + // Current limit, decremented each time catRead() is called. Volatile because multiple threads + // could be trying to modify it at once. (This is not real thread-safety, but good enough for + // the purpose of this class. See class comment.) + + KJ_DISALLOW_COPY(ReadLimiter); +}; + +#if !CAPNP_LITE +class BrokenCapFactory { + // Callback for constructing broken caps. We use this so that we can avoid arena.c++ having a + // link-time dependency on capability code that lives in libcapnp-rpc. + +public: + virtual kj::Own newBrokenCap(kj::StringPtr description) = 0; + virtual kj::Own newNullCap() = 0; +}; +#endif // !CAPNP_LITE + +class SegmentReader { +public: + inline SegmentReader(Arena* arena, SegmentId id, const word* ptr, SegmentWordCount size, + ReadLimiter* readLimiter); + + KJ_ALWAYS_INLINE(const word* checkOffset(const word* from, ptrdiff_t offset)); + // Adds the given offset to the given pointer, checks that it is still within the bounds of the + // segment, then returns it. Note that the "end" pointer of the segment (which technically points + // to the word after the last in the segment) is considered in-bounds for this purpose, so you + // can't necessarily dereference it. You must call checkObject() next to check that the object + // you want to read is entirely in-bounds. + // + // If `from + offset` is out-of-range, this returns a pointer to the end of the segment. Thus, + // any non-zero-sized object will fail `checkObject()`. We do this instead of throwing to save + // some code footprint. + + KJ_ALWAYS_INLINE(bool checkObject(const word* start, WordCountN<31> size)); + // Assuming that `start` is in-bounds for this segment (probably checked using `checkOffset()`), + // check that `start + size` is also in-bounds, and hence the whole area in-between is valid. + + KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); + // Indicates that the reader should pretend that `virtualAmount` additional data was read even + // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer + // where the element sizes are zero -- the sender could set the list size arbitrarily high and + // cause the receiver to iterate over this list even though the message itself is small, so we + // need to defend against DoS attacks based on this. + + inline Arena* getArena(); + inline SegmentId getSegmentId(); + + inline const word* getStartPtr(); + inline SegmentWordCount getOffsetTo(const word* ptr); + inline SegmentWordCount getSize(); + + inline kj::ArrayPtr getArray(); + + inline void unread(WordCount64 amount); + // Add back some words to the ReadLimiter. + +private: + Arena* arena; + SegmentId id; + kj::ArrayPtr ptr; // size guaranteed to fit in SEGMENT_WORD_COUNT_BITS bits + ReadLimiter* readLimiter; + + KJ_DISALLOW_COPY(SegmentReader); + + friend class SegmentBuilder; + + static void abortCheckObjectFault(); + // Called in debug mode in cases that would segfault in opt mode. (Should be impossible!) +}; + +class SegmentBuilder: public SegmentReader { +public: + inline SegmentBuilder(BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size, + ReadLimiter* readLimiter, SegmentWordCount wordsUsed = ZERO * WORDS); + inline SegmentBuilder(BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size, + ReadLimiter* readLimiter); + inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), + ReadLimiter* readLimiter); + + KJ_ALWAYS_INLINE(word* allocate(SegmentWordCount amount)); + + KJ_ALWAYS_INLINE(void checkWritable()); + // Throw an exception if the segment is read-only (meaning it is a reference to external data). + + KJ_ALWAYS_INLINE(word* getPtrUnchecked(SegmentWordCount offset)); + // Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e. + // a reference to external immutable data). + + inline BuilderArena* getArena(); + + inline kj::ArrayPtr currentlyAllocated(); + + inline void reset(); + + inline bool isWritable() { return !readOnly; } + + inline void tryTruncate(word* from, word* to); + // If `from` points just past the current end of the segment, then move the end back to `to`. + // Otherwise, do nothing. + + inline bool tryExtend(word* from, word* to); + // If `from` points just past the current end of the segment, and `to` is within the segment + // boundaries, then move the end up to `to` and return true. Otherwise, do nothing and return + // false. + +private: + word* pos; + // Pointer to a pointer to the current end point of the segment, i.e. the location where the + // next object should be allocated. + + bool readOnly; + + void throwNotWritable(); + + KJ_DISALLOW_COPY(SegmentBuilder); +}; + +class Arena { +public: + virtual ~Arena() noexcept(false); + + virtual SegmentReader* tryGetSegment(SegmentId id) = 0; + // Gets the segment with the given ID, or return nullptr if no such segment exists. + + virtual void reportReadLimitReached() = 0; + // Called to report that the read limit has been reached. See ReadLimiter, below. This invokes + // the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller + // will need to continue with default values. +}; + +class ReaderArena final: public Arena { +public: + explicit ReaderArena(MessageReader* message); + ~ReaderArena() noexcept(false); + KJ_DISALLOW_COPY(ReaderArena); + + // implements Arena ------------------------------------------------ + SegmentReader* tryGetSegment(SegmentId id) override; + void reportReadLimitReached() override; + +private: + MessageReader* message; + ReadLimiter readLimiter; + + // Optimize for single-segment messages so that small messages are handled quickly. + SegmentReader segment0; + + typedef std::unordered_map> SegmentMap; + kj::MutexGuarded>> moreSegments; + // We need to mutex-guard the segment map because we lazily initialize segments when they are + // first requested, but a Reader is allowed to be used concurrently in multiple threads. Luckily + // this only applies to large messages. + // + // TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data + // in a different way, where you have to construct a new MessageReader in each thread (but + // possibly backed by the same data)? + + ReaderArena(MessageReader* message, kj::ArrayPtr firstSegment); + ReaderArena(MessageReader* message, const word* firstSegment, SegmentWordCount firstSegmentSize); +}; + +class BuilderArena final: public Arena { + // A BuilderArena that does not allow the injection of capabilities. + +public: + explicit BuilderArena(MessageBuilder* message); + BuilderArena(MessageBuilder* message, kj::ArrayPtr segments); + ~BuilderArena() noexcept(false); + KJ_DISALLOW_COPY(BuilderArena); + + inline SegmentBuilder* getRootSegment() { return &segment0; } + + kj::ArrayPtr> getSegmentsForOutput(); + // Get an array of all the segments, suitable for writing out. This only returns the allocated + // portion of each segment, whereas tryGetSegment() returns something that includes + // not-yet-allocated space. + + inline CapTableBuilder* getLocalCapTable() { + // Return a CapTableBuilder that merely implements local loopback. That is, you can set + // capabilities, then read the same capabilities back, but there is no intent ever to transmit + // these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this + // by default. + // + // TODO(cleanup): It's sort of a hack that this exists. In theory, perhaps, unimbued + // MessageBuilders should throw exceptions on any attempt to access capability fields, like + // unimbued MessageReaders do. However, lots of code exists which uses MallocMessageBuilder + // as a temporary holder for data to be copied in and out (without being serialized), and it + // is expected that such data can include capabilities, which is admittedly reasonable. + // Therefore, all MessageBuilders must have a cap table by default. Arguably we should + // deprecate this usage and instead define a new helper type for this exact purpose. + + return &localCapTable; + } + + SegmentBuilder* getSegment(SegmentId id); + // Get the segment with the given id. Crashes or throws an exception if no such segment exists. + + struct AllocateResult { + SegmentBuilder* segment; + word* words; + }; + + AllocateResult allocate(SegmentWordCount amount); + // Find a segment with at least the given amount of space available and allocate the space. + // Note that allocating directly from a particular segment is much faster, but allocating from + // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific + // segment first if there is one, then fall back to the arena. + + SegmentBuilder* addExternalSegment(kj::ArrayPtr content); + // Add a new segment to the arena which points to some existing memory region. The segment is + // assumed to be completley full; the arena will never allocate from it. In fact, the segment + // is considered read-only. Any attempt to get a Builder pointing into this segment will throw + // an exception. Readers are allowed, however. + // + // This can be used to inject some external data into a message without a copy, e.g. embedding a + // large mmap'd file into a message as `Data` without forcing that data to actually be read in + // from disk (until the message itself is written out). `Orphanage` provides the public API for + // this feature. + + // implements Arena ------------------------------------------------ + SegmentReader* tryGetSegment(SegmentId id) override; + void reportReadLimitReached() override; + +private: + MessageBuilder* message; + ReadLimiter dummyLimiter; + + class LocalCapTable: public CapTableBuilder { +#if !CAPNP_LITE + public: + kj::Maybe> extractCap(uint index) override; + uint injectCap(kj::Own&& cap) override; + void dropCap(uint index) override; + + private: + kj::Vector>> capTable; +#endif // ! CAPNP_LITE + }; + + LocalCapTable localCapTable; + + SegmentBuilder segment0; + kj::ArrayPtr segment0ForOutput; + + struct MultiSegmentState { + kj::Vector> builders; + kj::Vector> forOutput; + }; + kj::Maybe> moreSegments; + + SegmentBuilder* segmentWithSpace = nullptr; + // When allocating, look for space in this segment first before resorting to allocating a new + // segment. This is not necessarily the last segment because addExternalSegment() may add a + // segment that is already-full, in which case we don't update this pointer. + + template // Can be `word` or `const word`. + SegmentBuilder* addSegmentInternal(kj::ArrayPtr content); +}; + +// ======================================================================================= + +inline ReadLimiter::ReadLimiter() + : limit(kj::maxValue) {} + +inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(unbound(limit / WORDS)) {} + +inline void ReadLimiter::reset(WordCount64 limit) { this->limit = unbound(limit / WORDS); } + +inline bool ReadLimiter::canRead(WordCount64 amount, Arena* arena) { + // Be careful not to store an underflowed value into `limit`, even if multiple threads are + // decrementing it. + uint64_t current = limit; + if (KJ_UNLIKELY(unbound(amount / WORDS) > current)) { + arena->reportReadLimitReached(); + return false; + } else { + limit = current - unbound(amount / WORDS); + return true; + } +} + +// ------------------------------------------------------------------- + +inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, const word* ptr, + SegmentWordCount size, ReadLimiter* readLimiter) + : arena(arena), id(id), ptr(kj::arrayPtr(ptr, unbound(size / WORDS))), + readLimiter(readLimiter) {} + +inline const word* SegmentReader::checkOffset(const word* from, ptrdiff_t offset) { + ptrdiff_t min = ptr.begin() - from; + ptrdiff_t max = ptr.end() - from; + if (offset >= min && offset <= max) { + return from + offset; + } else { + return ptr.end(); + } +} + +inline bool SegmentReader::checkObject(const word* start, WordCountN<31> size) { + auto startOffset = intervalLength(ptr.begin(), start, MAX_SEGMENT_WORDS); +#ifdef KJ_DEBUG + if (startOffset > bounded(ptr.size()) * WORDS) { + abortCheckObjectFault(); + } +#endif + return startOffset + size <= bounded(ptr.size()) * WORDS && + readLimiter->canRead(size, arena); +} + +inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { + return readLimiter->canRead(virtualAmount, arena); +} + +inline Arena* SegmentReader::getArena() { return arena; } +inline SegmentId SegmentReader::getSegmentId() { return id; } +inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } +inline SegmentWordCount SegmentReader::getOffsetTo(const word* ptr) { + KJ_IREQUIRE(this->ptr.begin() <= ptr && ptr <= this->ptr.end()); + return intervalLength(this->ptr.begin(), ptr, MAX_SEGMENT_WORDS); +} +inline SegmentWordCount SegmentReader::getSize() { + return assumeBits(ptr.size()) * WORDS; +} +inline kj::ArrayPtr SegmentReader::getArray() { return ptr; } +inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); } + +// ------------------------------------------------------------------- + +inline SegmentBuilder::SegmentBuilder( + BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size, + ReadLimiter* readLimiter, SegmentWordCount wordsUsed) + : SegmentReader(arena, id, ptr, size, readLimiter), + pos(ptr + wordsUsed), readOnly(false) {} +inline SegmentBuilder::SegmentBuilder( + BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size, + ReadLimiter* readLimiter) + : SegmentReader(arena, id, ptr, size, readLimiter), + // const_cast is safe here because the member won't ever be dereferenced because it appears + // to point to the end of the segment anyway. + pos(const_cast(ptr + size)), readOnly(true) {} +inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), + ReadLimiter* readLimiter) + : SegmentReader(arena, id, nullptr, ZERO * WORDS, readLimiter), + pos(nullptr), readOnly(false) {} + +inline word* SegmentBuilder::allocate(SegmentWordCount amount) { + if (intervalLength(pos, ptr.end(), MAX_SEGMENT_WORDS) < amount) { + // Not enough space in the segment for this allocation. + return nullptr; + } else { + // Success. + word* result = pos; + pos = pos + amount; + return result; + } +} + +inline void SegmentBuilder::checkWritable() { + if (KJ_UNLIKELY(readOnly)) throwNotWritable(); +} + +inline word* SegmentBuilder::getPtrUnchecked(SegmentWordCount offset) { + return const_cast(ptr.begin() + offset); +} + +inline BuilderArena* SegmentBuilder::getArena() { + // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base + // class with an Arena pointer that actually points to a BuilderArena. + return static_cast(arena); +} + +inline kj::ArrayPtr SegmentBuilder::currentlyAllocated() { + return kj::arrayPtr(ptr.begin(), pos - ptr.begin()); +} + +inline void SegmentBuilder::reset() { + word* start = getPtrUnchecked(ZERO * WORDS); + memset(start, 0, (pos - start) * sizeof(word)); + pos = start; +} + +inline void SegmentBuilder::tryTruncate(word* from, word* to) { + if (pos == from) pos = to; +} + +inline bool SegmentBuilder::tryExtend(word* from, word* to) { + // Careful about overflow. + if (pos == from && to <= ptr.end() && to >= from) { + pos = to; + return true; + } else { + return false; + } +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_ARENA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/blob-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/blob-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,129 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "blob.h" +#include +#include +#include +#include "test-util.h" + +// TODO(test): This test is outdated -- it predates the retrofit of Text and Data on top of +// kj::ArrayPtr/kj::StringPtr. Clean it up. + +namespace capnp { +namespace { + +TEST(Blob, Text) { + std::string str = "foo"; + Text::Reader text = str.c_str(); + + EXPECT_EQ("foo", text); + EXPECT_STREQ("foo", text.cStr()); + EXPECT_STREQ("foo", text.begin()); + EXPECT_EQ(3u, text.size()); + + Text::Reader text2 = "bar"; + EXPECT_EQ("bar", text2); + + char c[4] = "baz"; + Text::Reader text3(c); + EXPECT_EQ("baz", text3); + + Text::Builder builder(c, 3); + EXPECT_EQ("baz", builder); + + EXPECT_EQ(kj::arrayPtr("az", 2), builder.slice(1, 3)); +} + +Data::Reader dataLit(const char* str) { + return Data::Reader(reinterpret_cast(str), strlen(str)); +} + +TEST(Blob, Data) { + Data::Reader data = dataLit("foo"); + + EXPECT_EQ(dataLit("foo"), data); + EXPECT_EQ(3u, data.size()); + + Data::Reader data2 = dataLit("bar"); + EXPECT_EQ(dataLit("bar"), data2); + + byte c[4] = "baz"; + Data::Reader data3(c, 3); + EXPECT_EQ(dataLit("baz"), data3); + + Data::Builder builder(c, 3); + EXPECT_EQ(dataLit("baz"), builder); + + EXPECT_EQ(dataLit("az"), builder.slice(1, 3)); +} + +TEST(Blob, Compare) { + EXPECT_TRUE (Text::Reader("foo") == Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("foo") != Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("foo") <= Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("foo") >= Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("foo") < Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("foo") > Text::Reader("foo")); + + EXPECT_FALSE(Text::Reader("foo") == Text::Reader("bar")); + EXPECT_TRUE (Text::Reader("foo") != Text::Reader("bar")); + EXPECT_FALSE(Text::Reader("foo") <= Text::Reader("bar")); + EXPECT_TRUE (Text::Reader("foo") >= Text::Reader("bar")); + EXPECT_FALSE(Text::Reader("foo") < Text::Reader("bar")); + EXPECT_TRUE (Text::Reader("foo") > Text::Reader("bar")); + + EXPECT_FALSE(Text::Reader("bar") == Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("bar") != Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("bar") <= Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("bar") >= Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("bar") < Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("bar") > Text::Reader("foo")); + + EXPECT_FALSE(Text::Reader("foobar") == Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("foobar") != Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("foobar") <= Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("foobar") >= Text::Reader("foo")); + EXPECT_FALSE(Text::Reader("foobar") < Text::Reader("foo")); + EXPECT_TRUE (Text::Reader("foobar") > Text::Reader("foo")); + + EXPECT_FALSE(Text::Reader("foo") == Text::Reader("foobar")); + EXPECT_TRUE (Text::Reader("foo") != Text::Reader("foobar")); + EXPECT_TRUE (Text::Reader("foo") <= Text::Reader("foobar")); + EXPECT_FALSE(Text::Reader("foo") >= Text::Reader("foobar")); + EXPECT_TRUE (Text::Reader("foo") < Text::Reader("foobar")); + EXPECT_FALSE(Text::Reader("foo") > Text::Reader("foobar")); +} + +#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP +TEST(Blob, StlInterop) { + std::string foo = "foo"; + Text::Reader reader = foo; + + EXPECT_EQ("foo", reader); + + std::string bar = reader; + EXPECT_EQ("foo", bar); +} +#endif + +} // namespace +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/blob.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/blob.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,28 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "blob.h" + +namespace capnp { + +char Text::Builder::nulstr[1] = ""; + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/blob.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/blob.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,220 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_BLOB_H_ +#define CAPNP_BLOB_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include "common.h" +#include + +namespace capnp { + +struct Data { + Data() = delete; + class Reader; + class Builder; + class Pipeline {}; +}; + +struct Text { + Text() = delete; + class Reader; + class Builder; + class Pipeline {}; +}; + +class Data::Reader: public kj::ArrayPtr { + // Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple + // pointer which does not own its target, can be passed by value, etc. + +public: + typedef Data Reads; + + Reader() = default; + inline Reader(decltype(nullptr)): ArrayPtr(nullptr) {} + inline Reader(const byte* value, size_t size): ArrayPtr(value, size) {} + inline Reader(const kj::Array& value): ArrayPtr(value) {} + inline Reader(const ArrayPtr& value): ArrayPtr(value) {} + inline Reader(const kj::Array& value): ArrayPtr(value) {} + inline Reader(const ArrayPtr& value): ArrayPtr(value) {} +}; + +class Text::Reader: public kj::StringPtr { + // Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted + // in the size but must be present immediately after the last byte. + // + // Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of + // the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD + // also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares. + +public: + typedef Text Reads; + + Reader() = default; + inline Reader(decltype(nullptr)): StringPtr(nullptr) {} + inline Reader(const char* value): StringPtr(value) {} + inline Reader(const char* value, size_t size): StringPtr(value, size) {} + inline Reader(const kj::String& value): StringPtr(value) {} + inline Reader(const StringPtr& value): StringPtr(value) {} + +#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP + template ().c_str())> + inline Reader(const T& t): StringPtr(t) {} + // Allow implicit conversion from any class that has a c_str() method (namely, std::string). + // We use a template trick to detect std::string in order to avoid including the header for + // those who don't want it. +#endif +}; + +class Data::Builder: public kj::ArrayPtr { + // Like Data::Reader except the pointers aren't const. + +public: + typedef Data Builds; + + Builder() = default; + inline Builder(decltype(nullptr)): ArrayPtr(nullptr) {} + inline Builder(byte* value, size_t size): ArrayPtr(value, size) {} + inline Builder(kj::Array& value): ArrayPtr(value) {} + inline Builder(ArrayPtr value): ArrayPtr(value) {} + + inline Data::Reader asReader() const { return Data::Reader(*this); } + inline operator Reader() const { return asReader(); } +}; + +class Text::Builder: public kj::DisallowConstCopy { + // Basically identical to kj::StringPtr, except that the contents are non-const. + +public: + inline Builder(): content(nulstr, 1) {} + inline Builder(decltype(nullptr)): content(nulstr, 1) {} + inline Builder(char* value): content(value, strlen(value) + 1) {} + inline Builder(char* value, size_t size): content(value, size + 1) { + KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); + } + + inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); } + inline operator Reader() const { return asReader(); } + + inline operator kj::ArrayPtr(); + inline kj::ArrayPtr asArray(); + inline operator kj::ArrayPtr() const; + inline kj::ArrayPtr asArray() const; + inline kj::ArrayPtr asBytes() { return asArray().asBytes(); } + inline kj::ArrayPtr asBytes() const { return asArray().asBytes(); } + // Result does not include NUL terminator. + + inline operator kj::StringPtr() const; + inline kj::StringPtr asString() const; + + inline const char* cStr() const { return content.begin(); } + // Returns NUL-terminated string. + + inline size_t size() const { return content.size() - 1; } + // Result does not include NUL terminator. + + inline char operator[](size_t index) const { return content[index]; } + inline char& operator[](size_t index) { return content[index]; } + + inline char* begin() { return content.begin(); } + inline char* end() { return content.end() - 1; } + inline const char* begin() const { return content.begin(); } + inline const char* end() const { return content.end() - 1; } + + inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } + inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } + + inline bool operator==(Builder other) const { return asString() == other.asString(); } + inline bool operator!=(Builder other) const { return asString() != other.asString(); } + inline bool operator< (Builder other) const { return asString() < other.asString(); } + inline bool operator> (Builder other) const { return asString() > other.asString(); } + inline bool operator<=(Builder other) const { return asString() <= other.asString(); } + inline bool operator>=(Builder other) const { return asString() >= other.asString(); } + + inline kj::StringPtr slice(size_t start) const; + inline kj::ArrayPtr slice(size_t start, size_t end) const; + inline Builder slice(size_t start); + inline kj::ArrayPtr slice(size_t start, size_t end); + // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter + // version that assumes end = size(). + +private: + inline explicit Builder(kj::ArrayPtr content): content(content) {} + + kj::ArrayPtr content; + + static char nulstr[1]; +}; + +inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) { + return builder.asString(); +} + +inline bool operator==(const char* a, const Text::Builder& b) { return a == b.asString(); } +inline bool operator!=(const char* a, const Text::Builder& b) { return a != b.asString(); } + +inline Text::Builder::operator kj::StringPtr() const { + return kj::StringPtr(content.begin(), content.size() - 1); +} + +inline kj::StringPtr Text::Builder::asString() const { + return kj::StringPtr(content.begin(), content.size() - 1); +} + +inline Text::Builder::operator kj::ArrayPtr() { + return content.slice(0, content.size() - 1); +} + +inline kj::ArrayPtr Text::Builder::asArray() { + return content.slice(0, content.size() - 1); +} + +inline Text::Builder::operator kj::ArrayPtr() const { + return content.slice(0, content.size() - 1); +} + +inline kj::ArrayPtr Text::Builder::asArray() const { + return content.slice(0, content.size() - 1); +} + +inline kj::StringPtr Text::Builder::slice(size_t start) const { + return asReader().slice(start); +} +inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) const { + return content.slice(start, end); +} + +inline Text::Builder Text::Builder::slice(size_t start) { + return Text::Builder(content.slice(start, content.size())); +} +inline kj::ArrayPtr Text::Builder::slice(size_t start, size_t end) { + return content.slice(start, end); +} + +} // namespace capnp + +#endif // CAPNP_BLOB_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/bootstrap-test.ekam-rule --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/bootstrap-test.ekam-rule Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,76 @@ +#! /bin/sh + +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a one-off test rule. + +set -eu + +echo findProvider special:ekam-interceptor +read INTERCEPTOR + +if test "$INTERCEPTOR" = ""; then + echo "error: couldn't find intercept.so." >&2 + exit 1 +fi + +echo findProvider file:capnp +read CAPNP + +if test "$CAPNP" = ""; then + echo "error: couldn't find capnp." >&2 + exit 1 +fi + +echo findProvider file:capnpc-c++ +read CAPNPC_CXX + +if test "$CAPNPC_CXX" = ""; then + echo "error: couldn't find capnpc-c++." >&2 + exit 1 +fi + +mkdir -p tmp/capnp/bootstrap-test-tmp + +INPUTS="capnp/c++.capnp capnp/schema.capnp capnp/compiler/lexer.capnp capnp/compiler/grammar.capnp \ +capnp/rpc.capnp capnp/rpc-twoparty.capnp capnp/persistent.capnp" + +SRC_INPUTS="" +for file in $INPUTS; do + echo findProvider file:$file + read srcfile + SRC_INPUTS="$SRC_INPUTS $srcfile" +done + +$CAPNP compile --src-prefix=src -Isrc --no-standard-import \ + -o$CAPNPC_CXX:tmp/capnp/bootstrap-test-tmp $SRC_INPUTS + +for file in $INPUTS; do + for ext in h c++; do + echo findProvider file:$file.$ext + read srcfile + test "x$srcfile" != x || (echo "missing: $file.$ext" >&2 && exit 1) + diff -u $srcfile tmp/capnp/bootstrap-test-tmp/$file.$ext >&2 + done +done + +echo passed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/c++.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/c++.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,26 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xbdf87d7bb8304e81; +$namespace("capnp::annotations"); + +annotation namespace(file): Text; +annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/c++.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/c++.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,68 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: c++.capnp + +#include "c++.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<21> b_b9c6f99ebf805f2c = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 44, 95, 128, 191, 158, 249, 198, 185, + 16, 0, 0, 0, 5, 0, 1, 0, + 129, 78, 48, 184, 123, 125, 248, 189, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 210, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 0, 0, 0, 3, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 43, + 43, 46, 99, 97, 112, 110, 112, 58, + 110, 97, 109, 101, 115, 112, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b9c6f99ebf805f2c = b_b9c6f99ebf805f2c.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = { + 0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 21, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_b9c6f99ebf805f2c, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 206, 145, 241, 254, 121, 167, 100, 242, + 16, 0, 0, 0, 5, 0, 252, 7, + 129, 78, 48, 184, 123, 125, 248, 189, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 170, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 3, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 43, + 43, 46, 99, 97, 112, 110, 112, 58, + 110, 97, 109, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f264a779fef191ce = b_f264a779fef191ce.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_f264a779fef191ce = { + 0xf264a779fef191ce, b_f264a779fef191ce.words, 20, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_f264a779fef191ce, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/c++.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/c++.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,33 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: c++.capnp + +#ifndef CAPNP_INCLUDED_bdf87d7bb8304e81_ +#define CAPNP_INCLUDED_bdf87d7bb8304e81_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(b9c6f99ebf805f2c); +CAPNP_DECLARE_SCHEMA(f264a779fef191ce); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace annotations { + +// ======================================================================================= + +// ======================================================================================= + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_bdf87d7bb8304e81_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/canonicalize-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/canonicalize-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,392 @@ +// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "message.h" +#include "any.h" +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +using test::TestLists; +namespace { + + +KJ_TEST("canonicalize yields canonical message") { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root); + + auto canonicalWords = canonicalize(root.asReader()); + // Throws an exception on canonicalization failure. + + kj::ArrayPtr canonicalSegments[1] = {canonicalWords.asPtr()}; + capnp::SegmentArrayMessageReader canonicalReader(kj::arrayPtr(canonicalSegments, 1)); + + KJ_ASSERT(AnyStruct::Reader(root.asReader()) == + AnyStruct::Reader(canonicalReader.getRoot())); +} + +KJ_TEST("canonicalize succeeds on empty struct") { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + canonicalize(root.asReader()); // Throws an exception on canoncalization failure. +} + +KJ_TEST("data word with only its most significant bit set does not get truncated") { + AlignedData<3> segment = {{ + // Struct pointer, body immediately follows, two data words + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + + // First data word + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + + // Second data word, all zero except most significant bit + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 3)}; + SegmentArrayMessageReader messageReader(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(messageReader.isCanonical()); + auto canonicalWords = canonicalize(messageReader.getRoot()); + + // At one point this failed because an off-by-one bug in canonicalization + // caused the second word of the data section to be truncated. + ASSERT_EQ(canonicalWords.asBytes(), kj::arrayPtr(segment.bytes, 3 * 8)); +} + +KJ_TEST("INLINE_COMPOSITE data word with only its most significant bit set does not get truncated") { + AlignedData<5> segment = {{ + // Struct pointer, body immediately follows, one pointer + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + + // List pointer, no offset, inline composite, two words long + 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + + // Tag word, list has one element with two data words and no pointers + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + + // First data word + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + + // Second data word, all zero except most significant bit + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 5)}; + SegmentArrayMessageReader messageReader(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(messageReader.isCanonical()); + auto canonicalWords = canonicalize(messageReader.getRoot()); + + // At one point this failed because an off-by-one bug in canonicalization + // caused the second word of the data section to be truncated. + ASSERT_EQ(canonicalWords.asBytes(), kj::arrayPtr(segment.bytes, 5 * 8)); +} + +KJ_TEST("canonical non-null empty struct field") { + AlignedData<4> nonNullEmptyStruct = {{ + // Struct pointer, body immediately follows, two pointer fields, no data. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + + // First pointer field, struct, offset of 1, data size 1, no pointers. + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // Non-null pointer to empty struct. + 0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + + // Body of struct filled with non-zero data. + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(nonNullEmptyStruct.words, 4)}; + SegmentArrayMessageReader messageReader(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(messageReader.isCanonical()); +} + +KJ_TEST("for pointers to empty structs, preorder is not canonical") { + AlignedData<4> nonNullEmptyStruct = {{ + // Struct pointer, body immediately follows, two pointer fields, no data. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + + // First pointer field, struct, offset of 1, data size 1, no pointers. + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // Non-null pointer to empty struct. Offset puts it in "preorder". Would need to have + // an offset of -1 to be canonical. + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // Body of struct filled with non-zero data. + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(nonNullEmptyStruct.words, 4)}; + SegmentArrayMessageReader messageReader(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!messageReader.isCanonical()); +} + +KJ_TEST("isCanonical requires pointer preorder") { + AlignedData<5> misorderedSegment = {{ + //Struct pointer, data immediately follows, two pointer fields, no data + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + //Pointer field 1, pointing to the last entry, data size 1, no pointer + 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + //Pointer field 2, pointing to the next entry, data size 2, no pointer + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + //Data for field 2 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + //Data for field 1 + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(misorderedSegment.words, + 5)}; + SegmentArrayMessageReader outOfOrder(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!outOfOrder.isCanonical()); +} + +KJ_TEST("isCanonical requires dense packing") { + AlignedData<3> gapSegment = {{ + //Struct pointer, data after a gap + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + //The gap + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //Data for field 1 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(gapSegment.words, + 3)}; + SegmentArrayMessageReader gap(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!gap.isCanonical()); +} + +KJ_TEST("isCanonical rejects multi-segment messages") { + AlignedData<1> farPtr = {{ + //Far pointer to next segment + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + }}; + + AlignedData<2> farTarget = {{ + //Struct pointer (needed to make the far pointer legal) + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + //Dummy data + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }}; + + kj::ArrayPtr segments[2] = { + kj::arrayPtr(farPtr.words, 1), + kj::arrayPtr(farTarget.words, 2) + }; + + SegmentArrayMessageReader multiSegmentMessage(kj::arrayPtr(segments, 2)); + KJ_ASSERT(!multiSegmentMessage.isCanonical()); +} + +KJ_TEST("isCanonical rejects zero segment messages") { + SegmentArrayMessageReader zero(kj::arrayPtr((kj::ArrayPtr*)NULL, + 0)); + KJ_ASSERT(!zero.isCanonical()); +} + +KJ_TEST("isCanonical requires truncation of 0-valued struct fields") { + AlignedData<2> nonTruncatedSegment = {{ + //Struct pointer, data immediately follows + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + //Default data value, should have been truncated + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments[1] = { + kj::arrayPtr(nonTruncatedSegment.words, 3) + }; + SegmentArrayMessageReader nonTruncated(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!nonTruncated.isCanonical()); +} + +KJ_TEST("isCanonical rejects unused trailing words") { + AlignedData<3> segment = {{ + // Struct pointer, data in next word + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // Data section of struct + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + + // Trailing zero word + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 3)}; + SegmentArrayMessageReader message(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!message.isCanonical()); +} + +KJ_TEST("isCanonical accepts empty inline composite list of zero-sized structs") { + AlignedData<3> segment = {{ + // Struct pointer, pointer in next word + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + + // List pointer, inline composite, zero words long + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + + // Tag word + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 3)}; + SegmentArrayMessageReader message(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(message.isCanonical()); +} + +KJ_TEST("isCanonical rejects inline composite list with inaccurate word-length") { + AlignedData<6> segment = {{ + // Struct pointer, no offset, pointer section has two entries + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + + // List pointer, offset of one, inline composite, two words long + // (The list only needs to be one word long to hold its actual elements; + // therefore this message is not canonical.) + 0x05, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + + // Struct pointer, offset two, data section has one word + 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // Tag word, struct, one element, one word data section + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + + // Data section of struct element of list + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + + // Data section of struct field in top-level struct + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 6)}; + SegmentArrayMessageReader message(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!message.isCanonical()); +} + +KJ_TEST("upgraded lists can be canonicalized") { + AlignedData<7> upgradedList = {{ + //Struct pointer, data immediately follows, 4 pointer fields, no data + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + //Three words of default pointers to get to the int16 list + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //List pointer, 3 int16s. + 0x01, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + //First two elements + 0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, + //Last element + 0x07, 0x08, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00 + }}; + kj::ArrayPtr segments[1] = { + kj::arrayPtr(upgradedList.words, 7) + }; + SegmentArrayMessageReader upgraded(kj::arrayPtr(segments, 1)); + + auto root = upgraded.getRoot(); + canonicalize(root); +} + +KJ_TEST("isCanonical requires truncation of 0-valued struct fields in all list members") { + AlignedData<6> nonTruncatedList = {{ + //List pointer, composite, + 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + //Struct tag word, 2 structs, 2 data words per struct + 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + //Data word non-null + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + //Null trailing word + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //Data word non-null + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + //Null trailing word + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }}; + kj::ArrayPtr segments[1] = { + kj::arrayPtr(nonTruncatedList.words, 6) + }; + SegmentArrayMessageReader nonTruncated(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!nonTruncated.isCanonical()); +} + +KJ_TEST("primitive list with nonzero padding") { + AlignedData<3> segment = {{ + // Struct, one pointer field. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + + // List of three byte-sized elements. + 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + + // Fourth byte is non-zero! + 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 3)}; + SegmentArrayMessageReader message(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!message.isCanonical()); + + auto canonicalWords = canonicalize(message.getRoot()); + + AlignedData<3> canonicalSegment = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + + ASSERT_EQ(canonicalWords.asBytes(), kj::arrayPtr(canonicalSegment.bytes, 3 * 8)); +} + +KJ_TEST("bit list with nonzero padding") { + AlignedData<3> segment = {{ + // Struct, one pointer field. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + + // List of eleven bit-sized elements. + 0x01, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + + // Twelfth bit is non-zero! + 0xee, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(segment.words, 3)}; + SegmentArrayMessageReader message(kj::arrayPtr(segments, 1)); + + KJ_ASSERT(!message.isCanonical()); + + auto canonicalWords = canonicalize(message.getRoot()); + + AlignedData<3> canonicalSegment = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0xee, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }}; + + ASSERT_EQ(canonicalWords.asBytes(), kj::arrayPtr(canonicalSegment.bytes, 3 * 8)); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/capability-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/capability-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1025 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema.capnp.h" + +#ifdef CAPNP_CAPABILITY_H_ +#error "schema.capnp should not depend on capability.h, because it contains no interfaces." +#endif + +#include + +#ifndef CAPNP_CAPABILITY_H_ +#error "test.capnp did not include capability.h." +#endif + +#include "capability.h" +#include "test-util.h" +#include +#include + +namespace capnp { +namespace _ { +namespace { + +TEST(Capability, Basic) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + test::TestInterface::Client client(kj::heap(callCount)); + + auto request1 = client.fooRequest(); + request1.setI(123); + request1.setJ(true); + auto promise1 = request1.send(); + + auto request2 = client.bazRequest(); + initTestMessage(request2.initS()); + auto promise2 = request2.send(); + + bool barFailed = false; + auto request3 = client.barRequest(); + auto promise3 = request3.send().then( + [](Response&& response) { + ADD_FAILURE() << "Expected bar() call to fail."; + }, [&](kj::Exception&& e) { + EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); + barFailed = true; + }); + + EXPECT_EQ(0, callCount); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("foo", response1.getX()); + + auto response2 = promise2.wait(waitScope); + + promise3.wait(waitScope); + + EXPECT_EQ(2, callCount); + EXPECT_TRUE(barFailed); +} + +TEST(Capability, Inheritance) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + test::TestExtends::Client client1(kj::heap(callCount)); + test::TestInterface::Client client2 = client1; + auto client = client2.castAs(); + + auto request1 = client.fooRequest(); + request1.setI(321); + auto promise1 = request1.send(); + + auto request2 = client.graultRequest(); + auto promise2 = request2.send(); + + EXPECT_EQ(0, callCount); + + auto response2 = promise2.wait(waitScope); + + checkTestMessage(response2); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("bar", response1.getX()); + + EXPECT_EQ(2, callCount); +} + +TEST(Capability, Pipelining) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + int chainedCallCount = 0; + test::TestPipeline::Client client(kj::heap(callCount)); + + auto request = client.getCapRequest(); + request.setN(234); + request.setInCap(test::TestInterface::Client(kj::heap(chainedCallCount))); + + auto promise = request.send(); + + auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); + pipelineRequest.setI(321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = promise.getOutBox().getCap().castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, callCount); + EXPECT_EQ(0, chainedCallCount); + + auto response = pipelinePromise.wait(waitScope); + EXPECT_EQ("bar", response.getX()); + + auto response2 = pipelinePromise2.wait(waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, chainedCallCount); +} + +TEST(Capability, TailCall) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int calleeCallCount = 0; + int callerCallCount = 0; + + test::TestTailCallee::Client callee(kj::heap(calleeCallCount)); + test::TestTailCaller::Client caller(kj::heap(callerCallCount)); + + auto request = caller.fooRequest(); + request.setI(456); + request.setCallee(callee); + + auto promise = request.send(); + + auto dependentCall0 = promise.getC().getCallSequenceRequest().send(); + + auto response = promise.wait(waitScope); + EXPECT_EQ(456, response.getI()); + EXPECT_EQ(456, response.getI()); + + auto dependentCall1 = promise.getC().getCallSequenceRequest().send(); + + auto dependentCall2 = response.getC().getCallSequenceRequest().send(); + + EXPECT_EQ(0, dependentCall0.wait(waitScope).getN()); + EXPECT_EQ(1, dependentCall1.wait(waitScope).getN()); + EXPECT_EQ(2, dependentCall2.wait(waitScope).getN()); + + EXPECT_EQ(1, calleeCallCount); + EXPECT_EQ(1, callerCallCount); +} + +TEST(Capability, AsyncCancelation) { + // Tests allowCancellation(). + + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + auto paf = kj::newPromiseAndFulfiller(); + bool destroyed = false; + auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); + + int callCount = 0; + int handleCount = 0; + + test::TestMoreStuff::Client client(kj::heap(callCount, handleCount)); + + kj::Promise promise = nullptr; + + bool returned = false; + { + auto request = client.expectCancelRequest(); + request.setCap(test::TestInterface::Client(kj::heap(kj::mv(paf.fulfiller)))); + promise = request.send().then( + [&](Response&& response) { + returned = true; + }).eagerlyEvaluate(nullptr); + } + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + + // We can detect that the method was canceled because it will drop the cap. + EXPECT_FALSE(destroyed); + EXPECT_FALSE(returned); + + promise = nullptr; // request cancellation + destructionPromise.wait(waitScope); + + EXPECT_TRUE(destroyed); + EXPECT_FALSE(returned); +} + +// ======================================================================================= + +TEST(Capability, DynamicClient) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + DynamicCapability::Client client = + test::TestInterface::Client(kj::heap(callCount)); + + auto request1 = client.newRequest("foo"); + request1.set("i", 123); + request1.set("j", true); + auto promise1 = request1.send(); + + auto request2 = client.newRequest("baz"); + initDynamicTestMessage(request2.init("s").as()); + auto promise2 = request2.send(); + + bool barFailed = false; + auto request3 = client.newRequest("bar"); + auto promise3 = request3.send().then( + [](Response&& response) { + ADD_FAILURE() << "Expected bar() call to fail."; + }, [&](kj::Exception&& e) { + EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); + barFailed = true; + }); + + EXPECT_EQ(0, callCount); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("foo", response1.get("x").as()); + + auto response2 = promise2.wait(waitScope); + + promise3.wait(waitScope); + + EXPECT_EQ(2, callCount); + EXPECT_TRUE(barFailed); +} + +TEST(Capability, DynamicClientInheritance) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + + DynamicCapability::Client client1 = + test::TestExtends::Client(kj::heap(callCount)); + EXPECT_EQ(Schema::from(), client1.getSchema()); + EXPECT_NE(Schema::from(), client1.getSchema()); + + DynamicCapability::Client client2 = client1.upcast(Schema::from()); + EXPECT_EQ(Schema::from(), client2.getSchema()); + + EXPECT_ANY_THROW(client2.upcast(Schema::from())); + auto client = client2.castAs(Schema::from()); + + auto request1 = client.newRequest("foo"); + request1.set("i", 321); + auto promise1 = request1.send(); + + auto request2 = client.newRequest("grault"); + auto promise2 = request2.send(); + + EXPECT_EQ(0, callCount); + + auto response2 = promise2.wait(waitScope); + + checkDynamicTestMessage(response2.as()); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("bar", response1.get("x").as()); + + EXPECT_EQ(2, callCount); +} + +TEST(Capability, DynamicClientPipelining) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + int chainedCallCount = 0; + DynamicCapability::Client client = + test::TestPipeline::Client(kj::heap(callCount)); + + auto request = client.newRequest("getCap"); + request.set("n", 234); + request.set("inCap", test::TestInterface::Client(kj::heap(chainedCallCount))); + + auto promise = request.send(); + + auto outCap = promise.get("outBox").releaseAs() + .get("cap").releaseAs(); + auto pipelineRequest = outCap.newRequest("foo"); + pipelineRequest.set("i", 321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = outCap.castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, callCount); + EXPECT_EQ(0, chainedCallCount); + + auto response = pipelinePromise.wait(waitScope); + EXPECT_EQ("bar", response.get("x").as()); + + auto response2 = pipelinePromise2.wait(waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, chainedCallCount); +} + +TEST(Capability, DynamicClientPipelineAnyCap) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + int chainedCallCount = 0; + DynamicCapability::Client client = + test::TestPipeline::Client(kj::heap(callCount)); + + auto request = client.newRequest("getAnyCap"); + request.set("n", 234); + request.set("inCap", test::TestInterface::Client(kj::heap(chainedCallCount))); + + auto promise = request.send(); + + auto outAnyCap = promise.get("outBox").releaseAs() + .get("cap").releaseAs(); + + EXPECT_EQ(Schema::from(), outAnyCap.getSchema()); + auto outCap = outAnyCap.castAs(Schema::from()); + + auto pipelineRequest = outCap.newRequest("foo"); + pipelineRequest.set("i", 321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = outCap.castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, callCount); + EXPECT_EQ(0, chainedCallCount); + + auto response = pipelinePromise.wait(waitScope); + EXPECT_EQ("bar", response.get("x").as()); + + auto response2 = pipelinePromise2.wait(waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, chainedCallCount); +} + +// ======================================================================================= + +class TestInterfaceDynamicImpl final: public DynamicCapability::Server { +public: + TestInterfaceDynamicImpl(int& callCount) + : DynamicCapability::Server(Schema::from()), + callCount(callCount) {} + + int& callCount; + + kj::Promise call(InterfaceSchema::Method method, + CallContext context) { + auto methodName = method.getProto().getName(); + if (methodName == "foo") { + ++callCount; + auto params = context.getParams(); + EXPECT_EQ(123, params.get("i").as()); + EXPECT_TRUE(params.get("j").as()); + context.getResults().set("x", "foo"); + return kj::READY_NOW; + } else if (methodName == "baz") { + ++callCount; + auto params = context.getParams(); + checkDynamicTestMessage(params.get("s").as()); + context.releaseParams(); + EXPECT_ANY_THROW(context.getParams()); + return kj::READY_NOW; + } else { + KJ_UNIMPLEMENTED("Method not implemented", methodName) { break; } + return kj::READY_NOW; + } + } +}; + +TEST(Capability, DynamicServer) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + test::TestInterface::Client client = + DynamicCapability::Client(kj::heap(callCount)) + .castAs(); + + auto request1 = client.fooRequest(); + request1.setI(123); + request1.setJ(true); + auto promise1 = request1.send(); + + auto request2 = client.bazRequest(); + initTestMessage(request2.initS()); + auto promise2 = request2.send(); + + bool barFailed = false; + auto request3 = client.barRequest(); + auto promise3 = request3.send().then( + [](Response&& response) { + ADD_FAILURE() << "Expected bar() call to fail."; + }, [&](kj::Exception&& e) { + EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); + barFailed = true; + }); + + EXPECT_EQ(0, callCount); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("foo", response1.getX()); + + auto response2 = promise2.wait(waitScope); + + promise3.wait(waitScope); + + EXPECT_EQ(2, callCount); + EXPECT_TRUE(barFailed); +} + +class TestExtendsDynamicImpl final: public DynamicCapability::Server { +public: + TestExtendsDynamicImpl(int& callCount) + : DynamicCapability::Server(Schema::from()), + callCount(callCount) {} + + int& callCount; + + kj::Promise call(InterfaceSchema::Method method, + CallContext context) { + auto methodName = method.getProto().getName(); + if (methodName == "foo") { + ++callCount; + auto params = context.getParams(); + EXPECT_EQ(321, params.get("i").as()); + EXPECT_FALSE(params.get("j").as()); + context.getResults().set("x", "bar"); + return kj::READY_NOW; + } else if (methodName == "grault") { + ++callCount; + context.releaseParams(); + initDynamicTestMessage(context.getResults()); + return kj::READY_NOW; + } else { + KJ_FAIL_ASSERT("Method not implemented", methodName); + } + } +}; + +TEST(Capability, DynamicServerInheritance) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + test::TestExtends::Client client1 = + DynamicCapability::Client(kj::heap(callCount)) + .castAs(); + test::TestInterface::Client client2 = client1; + auto client = client2.castAs(); + + auto request1 = client.fooRequest(); + request1.setI(321); + auto promise1 = request1.send(); + + auto request2 = client.graultRequest(); + auto promise2 = request2.send(); + + EXPECT_EQ(0, callCount); + + auto response2 = promise2.wait(waitScope); + + checkTestMessage(response2); + + auto response1 = promise1.wait(waitScope); + + EXPECT_EQ("bar", response1.getX()); + + EXPECT_EQ(2, callCount); +} + +class TestPipelineDynamicImpl final: public DynamicCapability::Server { +public: + TestPipelineDynamicImpl(int& callCount) + : DynamicCapability::Server(Schema::from()), + callCount(callCount) {} + + int& callCount; + + kj::Promise call(InterfaceSchema::Method method, + CallContext context) { + auto methodName = method.getProto().getName(); + if (methodName == "getCap") { + ++callCount; + + auto params = context.getParams(); + EXPECT_EQ(234, params.get("n").as()); + + auto cap = params.get("inCap").as(); + context.releaseParams(); + + auto request = cap.newRequest("foo"); + request.set("i", 123); + request.set("j", true); + + return request.send().then( + [this,KJ_CPCAP(context)](capnp::Response&& response) mutable { + EXPECT_EQ("foo", response.get("x").as()); + + auto result = context.getResults(); + result.set("s", "bar"); + + auto box = result.init("outBox").as(); + + // Too lazy to write a whole separate test for each of these cases... so just make + // sure they both compile here, and only actually test the latter. + box.set("cap", kj::heap(callCount)); + box.set("cap", kj::heap(callCount)); + }); + } else { + KJ_FAIL_ASSERT("Method not implemented", methodName); + } + } +}; + +TEST(Capability, DynamicServerPipelining) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount = 0; + int chainedCallCount = 0; + test::TestPipeline::Client client = + DynamicCapability::Client(kj::heap(callCount)) + .castAs(); + + auto request = client.getCapRequest(); + request.setN(234); + request.setInCap(test::TestInterface::Client(kj::heap(chainedCallCount))); + + auto promise = request.send(); + + auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); + pipelineRequest.setI(321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = promise.getOutBox().getCap().castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, callCount); + EXPECT_EQ(0, chainedCallCount); + + auto response = pipelinePromise.wait(waitScope); + EXPECT_EQ("bar", response.getX()); + + auto response2 = pipelinePromise2.wait(waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, chainedCallCount); +} + +class TestTailCallerDynamicImpl final: public DynamicCapability::Server { +public: + TestTailCallerDynamicImpl(int& callCount) + : DynamicCapability::Server(Schema::from()), + callCount(callCount) {} + + int& callCount; + + kj::Promise call(InterfaceSchema::Method method, + CallContext context) { + auto methodName = method.getProto().getName(); + if (methodName == "foo") { + ++callCount; + + auto params = context.getParams(); + auto tailRequest = params.get("callee").as().newRequest("foo"); + tailRequest.set("i", params.get("i")); + tailRequest.set("t", "from TestTailCaller"); + return context.tailCall(kj::mv(tailRequest)); + } else { + KJ_FAIL_ASSERT("Method not implemented", methodName); + } + } +}; + +TEST(Capability, DynamicServerTailCall) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int calleeCallCount = 0; + int callerCallCount = 0; + + test::TestTailCallee::Client callee(kj::heap(calleeCallCount)); + test::TestTailCaller::Client caller = + DynamicCapability::Client(kj::heap(callerCallCount)) + .castAs(); + + auto request = caller.fooRequest(); + request.setI(456); + request.setCallee(callee); + + auto promise = request.send(); + + auto dependentCall0 = promise.getC().getCallSequenceRequest().send(); + + auto response = promise.wait(waitScope); + EXPECT_EQ(456, response.getI()); + EXPECT_EQ(456, response.getI()); + + auto dependentCall1 = promise.getC().getCallSequenceRequest().send(); + + auto dependentCall2 = response.getC().getCallSequenceRequest().send(); + + EXPECT_EQ(0, dependentCall0.wait(waitScope).getN()); + EXPECT_EQ(1, dependentCall1.wait(waitScope).getN()); + EXPECT_EQ(2, dependentCall2.wait(waitScope).getN()); + + EXPECT_EQ(1, calleeCallCount); + EXPECT_EQ(1, callerCallCount); +} + +// ======================================================================================= + +void verifyClient(test::TestInterface::Client client, const int& callCount, + kj::WaitScope& waitScope) { + int origCount = callCount; + auto request = client.fooRequest(); + request.setI(123); + request.setJ(true); + auto response = request.send().wait(waitScope); + EXPECT_EQ("foo", response.getX()); + EXPECT_EQ(origCount + 1, callCount); +} + +void verifyClient(DynamicCapability::Client client, const int& callCount, + kj::WaitScope& waitScope) { + int origCount = callCount; + auto request = client.newRequest("foo"); + request.set("i", 123); + request.set("j", true); + auto response = request.send().wait(waitScope); + EXPECT_EQ("foo", response.get("x").as()); + EXPECT_EQ(origCount + 1, callCount); +} + +TEST(Capability, AnyPointersAndOrphans) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount1 = 0; + int callCount2 = 0; + + // We use a TestPipeline instance here merely as a way to conveniently obtain an imbued message + // instance. + test::TestPipeline::Client baseClient(nullptr); + test::TestInterface::Client client1(kj::heap(callCount1)); + test::TestInterface::Client client2(kj::heap(callCount2)); + + auto request = baseClient.testPointersRequest(); + request.setCap(client1); + + EXPECT_TRUE(request.hasCap()); + + Orphan orphan = request.disownCap(); + EXPECT_FALSE(orphan == nullptr); + + EXPECT_FALSE(request.hasCap()); + + verifyClient(orphan.get(), callCount1, waitScope); + verifyClient(orphan.getReader(), callCount1, waitScope); + + request.getObj().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + + verifyClient(request.getObj().getAs(), callCount1, waitScope); + verifyClient(request.asReader().getObj().getAs(), callCount1, waitScope); + verifyClient(request.getObj().getAs( + Schema::from()), callCount1, waitScope); + verifyClient(request.asReader().getObj().getAs( + Schema::from()), callCount1, waitScope); + + request.getObj().clear(); + EXPECT_FALSE(request.hasObj()); + + request.getObj().setAs(client2); + verifyClient(request.getObj().getAs(), callCount2, waitScope); + + Orphan dynamicOrphan = request.getObj().disownAs( + Schema::from()); + verifyClient(dynamicOrphan.get(), callCount2, waitScope); + verifyClient(dynamicOrphan.getReader(), callCount2, waitScope); + + Orphan dynamicValueOrphan = kj::mv(dynamicOrphan); + verifyClient(dynamicValueOrphan.get().as(), callCount2, waitScope); + + orphan = dynamicValueOrphan.releaseAs(); + EXPECT_FALSE(orphan == nullptr); + verifyClient(orphan.get(), callCount2, waitScope); + + request.adoptCap(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + + verifyClient(request.getCap(), callCount2, waitScope); + + Orphan dynamicOrphan2 = request.disownCap(); + verifyClient(dynamicOrphan2.get(), callCount2, waitScope); + verifyClient(dynamicOrphan2.getReader(), callCount2, waitScope); +} + +TEST(Capability, Lists) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + int callCount1 = 0; + int callCount2 = 0; + int callCount3 = 0; + test::TestPipeline::Client baseClient(kj::heap(callCount1)); + test::TestInterface::Client client1(kj::heap(callCount1)); + test::TestInterface::Client client2(kj::heap(callCount2)); + test::TestInterface::Client client3(kj::heap(callCount3)); + + auto request = baseClient.testPointersRequest(); + + auto list = request.initList(3); + list.set(0, client1); + list.set(1, client2); + list.set(2, client3); + + verifyClient(list[0], callCount1, waitScope); + verifyClient(list[1], callCount2, waitScope); + verifyClient(list[2], callCount3, waitScope); + + auto listReader = request.asReader().getList(); + verifyClient(listReader[0], callCount1, waitScope); + verifyClient(listReader[1], callCount2, waitScope); + verifyClient(listReader[2], callCount3, waitScope); + + auto dynamicList = toDynamic(list); + verifyClient(dynamicList[0].as(), callCount1, waitScope); + verifyClient(dynamicList[1].as(), callCount2, waitScope); + verifyClient(dynamicList[2].as(), callCount3, waitScope); + + auto dynamicListReader = toDynamic(listReader); + verifyClient(dynamicListReader[0].as(), callCount1, waitScope); + verifyClient(dynamicListReader[1].as(), callCount2, waitScope); + verifyClient(dynamicListReader[2].as(), callCount3, waitScope); +} + +TEST(Capability, KeywordMethods) { + // Verify that keywords are only munged where necessary. + + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + bool called = false; + + class TestKeywordMethodsImpl final: public test::TestKeywordMethods::Server { + public: + TestKeywordMethodsImpl(bool& called): called(called) {} + + kj::Promise delete_(DeleteContext context) override { + called = true; + return kj::READY_NOW; + } + + private: + bool& called; + }; + + test::TestKeywordMethods::Client client = kj::heap(called); + client.deleteRequest().send().wait(waitScope); + + EXPECT_TRUE(called); +} + +TEST(Capability, Generics) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + typedef test::TestGenerics::Interface> Interface; + Interface::Client client = nullptr; + + auto request = client.callRequest(); + request.setBaz("hello"); + initTestMessage(request.initInnerBound().initFoo()); + initTestMessage(request.initInnerUnbound().getFoo().initAs()); + + auto promise = request.send().then([](capnp::Response&& response) { + // This doesn't actually execute; we're just checking that it compiles. + List::Reader qux = response.getQux(); + qux.size(); + checkTestMessage(response.getGen().getFoo()); + }, [](kj::Exception&& e) { + // Ignore exception (which we'll always get because we're calling a null capability). + }); + + promise.wait(waitScope); + + // Check that asGeneric<>() compiles. + test::TestGenerics::Interface<>::Client castClient = client.asGeneric<>(); + test::TestGenerics::Interface::Client castClient2 = + client.asGeneric(); + test::TestGenerics<>::Interface>::Client castClient3 = client.asTestGenericsGeneric<>(); +} + +TEST(Capability, Generics2) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + root.initCap().setFoo(test::TestInterface::Client(nullptr)); +} + +TEST(Capability, ImplicitParams) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + typedef test::TestImplicitMethodParams Interface; + Interface::Client client = nullptr; + + capnp::Request, + test::TestGenerics> request = + client.callRequest(); + request.setFoo("hello"); + initTestMessage(request.initBar()); + + auto promise = request.send() + .then([](capnp::Response>&& response) { + // This doesn't actually execute; we're just checking that it compiles. + Text::Reader text = response.getFoo(); + text.size(); + checkTestMessage(response.getRev().getFoo()); + }, [](kj::Exception&& e) {}); + + promise.wait(waitScope); +} + +TEST(Capability, CapabilityServerSet) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + CapabilityServerSet set1, set2; + + int callCount = 0; + test::TestInterface::Client clientStandalone(kj::heap(callCount)); + test::TestInterface::Client clientNull = nullptr; + + auto ownServer1 = kj::heap(callCount); + auto& server1 = *ownServer1; + test::TestInterface::Client client1 = set1.add(kj::mv(ownServer1)); + + auto ownServer2 = kj::heap(callCount); + auto& server2 = *ownServer2; + test::TestInterface::Client client2 = set2.add(kj::mv(ownServer2)); + + // Getting the local server using the correct set works. + EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(set1.getLocalServer(client1).wait(waitScope))); + EXPECT_EQ(&server2, &KJ_ASSERT_NONNULL(set2.getLocalServer(client2).wait(waitScope))); + + // Getting the local server using the wrong set doesn't work. + EXPECT_TRUE(set1.getLocalServer(client2).wait(waitScope) == nullptr); + EXPECT_TRUE(set2.getLocalServer(client1).wait(waitScope) == nullptr); + EXPECT_TRUE(set1.getLocalServer(clientStandalone).wait(waitScope) == nullptr); + EXPECT_TRUE(set1.getLocalServer(clientNull).wait(waitScope) == nullptr); + + // A promise client waits to be resolved. + auto paf = kj::newPromiseAndFulfiller(); + test::TestInterface::Client clientPromise = kj::mv(paf.promise); + + auto errorPaf = kj::newPromiseAndFulfiller(); + test::TestInterface::Client errorPromise = kj::mv(errorPaf.promise); + + bool resolved1 = false, resolved2 = false, resolved3 = false; + auto promise1 = set1.getLocalServer(clientPromise) + .then([&](kj::Maybe server) { + resolved1 = true; + EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(server)); + }); + auto promise2 = set2.getLocalServer(clientPromise) + .then([&](kj::Maybe server) { + resolved2 = true; + EXPECT_TRUE(server == nullptr); + }); + auto promise3 = set1.getLocalServer(errorPromise) + .then([&](kj::Maybe server) { + KJ_FAIL_EXPECT("getLocalServer() on error promise should have thrown"); + }, [&](kj::Exception&& e) { + resolved3 = true; + KJ_EXPECT(e.getDescription().endsWith("foo"), e.getDescription()); + }); + + kj::evalLater([](){}).wait(waitScope); + kj::evalLater([](){}).wait(waitScope); + kj::evalLater([](){}).wait(waitScope); + kj::evalLater([](){}).wait(waitScope); + + EXPECT_FALSE(resolved1); + EXPECT_FALSE(resolved2); + EXPECT_FALSE(resolved3); + + paf.fulfiller->fulfill(kj::cp(client1)); + errorPaf.fulfiller->reject(KJ_EXCEPTION(FAILED, "foo")); + + promise1.wait(waitScope); + promise2.wait(waitScope); + promise3.wait(waitScope); + + EXPECT_TRUE(resolved1); + EXPECT_TRUE(resolved2); + EXPECT_TRUE(resolved3); +} + +class TestThisCap final: public test::TestInterface::Server { +public: + TestThisCap(int& callCount): callCount(callCount) {} + ~TestThisCap() noexcept(false) { callCount = -1; } + + test::TestInterface::Client getSelf() { + return thisCap(); + } + +protected: + kj::Promise bar(BarContext context) { + ++callCount; + return kj::READY_NOW; + } + +private: + int& callCount; +}; + +TEST(Capability, ThisCap) { + int callCount = 0; + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + auto server = kj::heap(callCount); + TestThisCap* serverPtr = server; + + test::TestInterface::Client client = kj::mv(server); + client.barRequest().send().wait(waitScope); + EXPECT_EQ(1, callCount); + + test::TestInterface::Client client2 = serverPtr->getSelf(); + EXPECT_EQ(1, callCount); + client2.barRequest().send().wait(waitScope); + EXPECT_EQ(2, callCount); + + client = nullptr; + + EXPECT_EQ(2, callCount); + client2.barRequest().send().wait(waitScope); + EXPECT_EQ(3, callCount); + + client2 = nullptr; + + EXPECT_EQ(-1, callCount); +} + +TEST(Capability, TransferCap) { + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + + MallocMessageBuilder message; + auto root = message.initRoot(); + + auto orphan = message.getOrphanage().newOrphan(); + auto e = orphan.get(); + e.setText("foo"); + e.setCap(KJ_EXCEPTION(FAILED, "whatever")); + + root.initList(1).adoptWithCaveats(0, kj::mv(orphan)); + + // This line used to throw due to capability pointers being incorrectly transferred. + auto cap = root.getList()[0].getCap(); + + cap.whenResolved().then([]() { + KJ_FAIL_EXPECT("didn't throw?"); + }, [](kj::Exception&&) { + // success + }).wait(waitScope); +} + +} // namespace +} // namespace _ +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/capability.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/capability.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,733 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE + +#include "capability.h" +#include "message.h" +#include "arena.h" +#include +#include +#include +#include +#include "generated-header-support.h" + +namespace capnp { + +namespace _ { + +void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory); +// Defined in layout.c++. + +} // namespace _ + +namespace { + +static kj::Own newNullCap(); + +class BrokenCapFactoryImpl: public _::BrokenCapFactory { +public: + kj::Own newBrokenCap(kj::StringPtr description) override { + return capnp::newBrokenCap(description); + } + kj::Own newNullCap() override { + return capnp::newNullCap(); + } +}; + +static BrokenCapFactoryImpl brokenCapFactory; + +} // namespace + +ClientHook::ClientHook() { + setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory); +} + +void* ClientHook::getLocalServer(_::CapabilityServerSetBase& capServerSet) { + return nullptr; +} + +// ======================================================================================= + +Capability::Client::Client(decltype(nullptr)) + : hook(newNullCap()) {} + +Capability::Client::Client(kj::Exception&& exception) + : hook(newBrokenCap(kj::mv(exception))) {} + +kj::Promise Capability::Server::internalUnimplemented( + const char* actualInterfaceName, uint64_t requestedTypeId) { + return KJ_EXCEPTION(UNIMPLEMENTED, "Requested interface not implemented.", + actualInterfaceName, requestedTypeId); +} + +kj::Promise Capability::Server::internalUnimplemented( + const char* interfaceName, uint64_t typeId, uint16_t methodId) { + return KJ_EXCEPTION(UNIMPLEMENTED, "Method not implemented.", interfaceName, typeId, methodId); +} + +kj::Promise Capability::Server::internalUnimplemented( + const char* interfaceName, const char* methodName, uint64_t typeId, uint16_t methodId) { + return KJ_EXCEPTION(UNIMPLEMENTED, "Method not implemented.", interfaceName, + typeId, methodName, methodId); +} + +ResponseHook::~ResponseHook() noexcept(false) {} + +kj::Promise ClientHook::whenResolved() { + KJ_IF_MAYBE(promise, whenMoreResolved()) { + return promise->then([](kj::Own&& resolution) { + return resolution->whenResolved(); + }); + } else { + return kj::READY_NOW; + } +} + +// ======================================================================================= + +static inline uint firstSegmentSize(kj::Maybe sizeHint) { + KJ_IF_MAYBE(s, sizeHint) { + return s->wordCount; + } else { + return SUGGESTED_FIRST_SEGMENT_WORDS; + } +} + +class LocalResponse final: public ResponseHook, public kj::Refcounted { +public: + LocalResponse(kj::Maybe sizeHint) + : message(firstSegmentSize(sizeHint)) {} + + MallocMessageBuilder message; +}; + +class LocalCallContext final: public CallContextHook, public kj::Refcounted { +public: + LocalCallContext(kj::Own&& request, kj::Own clientRef, + kj::Own> cancelAllowedFulfiller) + : request(kj::mv(request)), clientRef(kj::mv(clientRef)), + cancelAllowedFulfiller(kj::mv(cancelAllowedFulfiller)) {} + + AnyPointer::Reader getParams() override { + KJ_IF_MAYBE(r, request) { + return r->get()->getRoot(); + } else { + KJ_FAIL_REQUIRE("Can't call getParams() after releaseParams()."); + } + } + void releaseParams() override { + request = nullptr; + } + AnyPointer::Builder getResults(kj::Maybe sizeHint) override { + if (response == nullptr) { + auto localResponse = kj::refcounted(sizeHint); + responseBuilder = localResponse->message.getRoot(); + response = Response(responseBuilder.asReader(), kj::mv(localResponse)); + } + return responseBuilder; + } + kj::Promise tailCall(kj::Own&& request) override { + auto result = directTailCall(kj::mv(request)); + KJ_IF_MAYBE(f, tailCallPipelineFulfiller) { + f->get()->fulfill(AnyPointer::Pipeline(kj::mv(result.pipeline))); + } + return kj::mv(result.promise); + } + ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) override { + KJ_REQUIRE(response == nullptr, "Can't call tailCall() after initializing the results struct."); + + auto promise = request->send(); + + auto voidPromise = promise.then([this](Response&& tailResponse) { + response = kj::mv(tailResponse); + }); + + return { kj::mv(voidPromise), PipelineHook::from(kj::mv(promise)) }; + } + kj::Promise onTailCall() override { + auto paf = kj::newPromiseAndFulfiller(); + tailCallPipelineFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); + } + void allowCancellation() override { + cancelAllowedFulfiller->fulfill(); + } + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Maybe> request; + kj::Maybe> response; + AnyPointer::Builder responseBuilder = nullptr; // only valid if `response` is non-null + kj::Own clientRef; + kj::Maybe>> tailCallPipelineFulfiller; + kj::Own> cancelAllowedFulfiller; +}; + +class LocalRequest final: public RequestHook { +public: + inline LocalRequest(uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint, kj::Own client) + : message(kj::heap(firstSegmentSize(sizeHint))), + interfaceId(interfaceId), methodId(methodId), client(kj::mv(client)) {} + + RemotePromise send() override { + KJ_REQUIRE(message.get() != nullptr, "Already called send() on this request."); + + // For the lambda capture. + uint64_t interfaceId = this->interfaceId; + uint16_t methodId = this->methodId; + + auto cancelPaf = kj::newPromiseAndFulfiller(); + + auto context = kj::refcounted( + kj::mv(message), client->addRef(), kj::mv(cancelPaf.fulfiller)); + auto promiseAndPipeline = client->call(interfaceId, methodId, kj::addRef(*context)); + + // We have to make sure the call is not canceled unless permitted. We need to fork the promise + // so that if the client drops their copy, the promise isn't necessarily canceled. + auto forked = promiseAndPipeline.promise.fork(); + + // We daemonize one branch, but only after joining it with the promise that fires if + // cancellation is allowed. + forked.addBranch() + .attach(kj::addRef(*context)) + .exclusiveJoin(kj::mv(cancelPaf.promise)) + .detach([](kj::Exception&&) {}); // ignore exceptions + + // Now the other branch returns the response from the context. + auto promise = forked.addBranch().then(kj::mvCapture(context, + [](kj::Own&& context) { + context->getResults(MessageSize { 0, 0 }); // force response allocation + return kj::mv(KJ_ASSERT_NONNULL(context->response)); + })); + + // We return the other branch. + return RemotePromise( + kj::mv(promise), AnyPointer::Pipeline(kj::mv(promiseAndPipeline.pipeline))); + } + + const void* getBrand() override { + return nullptr; + } + + kj::Own message; + +private: + uint64_t interfaceId; + uint16_t methodId; + kj::Own client; +}; + +// ======================================================================================= +// Call queues +// +// These classes handle pipelining in the case where calls need to be queued in-memory until some +// local operation completes. + +class QueuedPipeline final: public PipelineHook, public kj::Refcounted { + // A PipelineHook which simply queues calls while waiting for a PipelineHook to which to forward + // them. + +public: + QueuedPipeline(kj::Promise>&& promiseParam) + : promise(promiseParam.fork()), + selfResolutionOp(promise.addBranch().then([this](kj::Own&& inner) { + redirect = kj::mv(inner); + }, [this](kj::Exception&& exception) { + redirect = newBrokenPipeline(kj::mv(exception)); + }).eagerlyEvaluate(nullptr)) {} + + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) override { + auto copy = kj::heapArrayBuilder(ops.size()); + for (auto& op: ops) { + copy.add(op); + } + return getPipelinedCap(copy.finish()); + } + + kj::Own getPipelinedCap(kj::Array&& ops) override; + +private: + kj::ForkedPromise> promise; + + kj::Maybe> redirect; + // Once the promise resolves, this will become non-null and point to the underlying object. + + kj::Promise selfResolutionOp; + // Represents the operation which will set `redirect` when possible. +}; + +class QueuedClient final: public ClientHook, public kj::Refcounted { + // A ClientHook which simply queues calls while waiting for a ClientHook to which to forward + // them. + +public: + QueuedClient(kj::Promise>&& promiseParam) + : promise(promiseParam.fork()), + selfResolutionOp(promise.addBranch().then([this](kj::Own&& inner) { + redirect = kj::mv(inner); + }, [this](kj::Exception&& exception) { + redirect = newBrokenCap(kj::mv(exception)); + }).eagerlyEvaluate(nullptr)), + promiseForCallForwarding(promise.addBranch().fork()), + promiseForClientResolution(promise.addBranch().fork()) {} + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + auto hook = kj::heap( + interfaceId, methodId, sizeHint, kj::addRef(*this)); + auto root = hook->message->getRoot(); + return Request(root, kj::mv(hook)); + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + // This is a bit complicated. We need to initiate this call later on. When we initiate the + // call, we'll get a void promise for its completion and a pipeline object. Right now, we have + // to produce a similar void promise and pipeline that will eventually be chained to those. + // The problem is, these are two independent objects, but they both depend on the result of + // one future call. + // + // So, we need to set up a continuation that will initiate the call later, then we need to + // fork the promise for that continuation in order to send the completion promise and the + // pipeline to their respective places. + // + // TODO(perf): Too much reference counting? Can we do better? Maybe a way to fork + // Promise> into Tuple, Promise>? + + struct CallResultHolder: public kj::Refcounted { + // Essentially acts as a refcounted \VoidPromiseAndPipeline, so that we can create a promise + // for it and fork that promise. + + VoidPromiseAndPipeline content; + // One branch of the fork will use content.promise, the other branch will use + // content.pipeline. Neither branch will touch the other's piece. + + inline CallResultHolder(VoidPromiseAndPipeline&& content): content(kj::mv(content)) {} + + kj::Own addRef() { return kj::addRef(*this); } + }; + + // Create a promise for the call initiation. + kj::ForkedPromise> callResultPromise = + promiseForCallForwarding.addBranch().then(kj::mvCapture(context, + [=](kj::Own&& context, kj::Own&& client){ + return kj::refcounted( + client->call(interfaceId, methodId, kj::mv(context))); + })).fork(); + + // Create a promise that extracts the pipeline from the call initiation, and construct our + // QueuedPipeline to chain to it. + auto pipelinePromise = callResultPromise.addBranch().then( + [](kj::Own&& callResult){ + return kj::mv(callResult->content.pipeline); + }); + auto pipeline = kj::refcounted(kj::mv(pipelinePromise)); + + // Create a promise that simply chains to the void promise produced by the call initiation. + auto completionPromise = callResultPromise.addBranch().then( + [](kj::Own&& callResult){ + return kj::mv(callResult->content.promise); + }); + + // OK, now we can actually return our thing. + return VoidPromiseAndPipeline { kj::mv(completionPromise), kj::mv(pipeline) }; + } + + kj::Maybe getResolved() override { + KJ_IF_MAYBE(inner, redirect) { + return **inner; + } else { + return nullptr; + } + } + + kj::Maybe>> whenMoreResolved() override { + return promiseForClientResolution.addBranch(); + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + const void* getBrand() override { + return nullptr; + } + +private: + typedef kj::ForkedPromise> ClientHookPromiseFork; + + kj::Maybe> redirect; + // Once the promise resolves, this will become non-null and point to the underlying object. + + ClientHookPromiseFork promise; + // Promise that resolves when we have a new ClientHook to forward to. + // + // This fork shall only have three branches: `selfResolutionOp`, `promiseForCallForwarding`, and + // `promiseForClientResolution`, in that order. + + kj::Promise selfResolutionOp; + // Represents the operation which will set `redirect` when possible. + + ClientHookPromiseFork promiseForCallForwarding; + // When this promise resolves, each queued call will be forwarded to the real client. This needs + // to occur *before* any 'whenMoreResolved()' promises resolve, because we want to make sure + // previously-queued calls are delivered before any new calls made in response to the resolution. + + ClientHookPromiseFork promiseForClientResolution; + // whenMoreResolved() returns forks of this promise. These must resolve *after* queued calls + // have been initiated (so that any calls made in the whenMoreResolved() handler are correctly + // delivered after calls made earlier), but *before* any queued calls return (because it might + // confuse the application if a queued call returns before the capability on which it was made + // resolves). Luckily, we know that queued calls will involve, at the very least, an + // eventLoop.evalLater. +}; + +kj::Own QueuedPipeline::getPipelinedCap(kj::Array&& ops) { + KJ_IF_MAYBE(r, redirect) { + return r->get()->getPipelinedCap(kj::mv(ops)); + } else { + auto clientPromise = promise.addBranch().then(kj::mvCapture(ops, + [](kj::Array&& ops, kj::Own pipeline) { + return pipeline->getPipelinedCap(kj::mv(ops)); + })); + + return kj::refcounted(kj::mv(clientPromise)); + } +} + +// ======================================================================================= + +class LocalPipeline final: public PipelineHook, public kj::Refcounted { +public: + inline LocalPipeline(kj::Own&& contextParam) + : context(kj::mv(contextParam)), + results(context->getResults(MessageSize { 0, 0 })) {} + + kj::Own addRef() { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) { + return results.getPipelinedCap(ops); + } + +private: + kj::Own context; + AnyPointer::Reader results; +}; + +class LocalClient final: public ClientHook, public kj::Refcounted { +public: + LocalClient(kj::Own&& serverParam) + : server(kj::mv(serverParam)) { + server->thisHook = this; + } + LocalClient(kj::Own&& serverParam, + _::CapabilityServerSetBase& capServerSet, void* ptr) + : server(kj::mv(serverParam)), capServerSet(&capServerSet), ptr(ptr) { + server->thisHook = this; + } + + ~LocalClient() noexcept(false) { + server->thisHook = nullptr; + } + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + auto hook = kj::heap( + interfaceId, methodId, sizeHint, kj::addRef(*this)); + auto root = hook->message->getRoot(); + return Request(root, kj::mv(hook)); + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + auto contextPtr = context.get(); + + // We don't want to actually dispatch the call synchronously, because we don't want the callee + // to have any side effects before the promise is returned to the caller. This helps avoid + // race conditions. + // + // So, we do an evalLater() here. + // + // Note also that QueuedClient depends on this evalLater() to ensure that pipelined calls don't + // complete before 'whenMoreResolved()' promises resolve. + auto promise = kj::evalLater([this,interfaceId,methodId,contextPtr]() { + return server->dispatchCall(interfaceId, methodId, + CallContext(*contextPtr)); + }).attach(kj::addRef(*this)); + + // We have to fork this promise for the pipeline to receive a copy of the answer. + auto forked = promise.fork(); + + auto pipelinePromise = forked.addBranch().then(kj::mvCapture(context->addRef(), + [=](kj::Own&& context) -> kj::Own { + context->releaseParams(); + return kj::refcounted(kj::mv(context)); + })); + + auto tailPipelinePromise = context->onTailCall().then([](AnyPointer::Pipeline&& pipeline) { + return kj::mv(pipeline.hook); + }); + + pipelinePromise = pipelinePromise.exclusiveJoin(kj::mv(tailPipelinePromise)); + + auto completionPromise = forked.addBranch().attach(kj::mv(context)); + + return VoidPromiseAndPipeline { kj::mv(completionPromise), + kj::refcounted(kj::mv(pipelinePromise)) }; + } + + kj::Maybe getResolved() override { + return nullptr; + } + + kj::Maybe>> whenMoreResolved() override { + return nullptr; + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + const void* getBrand() override { + // We have no need to detect local objects. + return nullptr; + } + + void* getLocalServer(_::CapabilityServerSetBase& capServerSet) override { + if (this->capServerSet == &capServerSet) { + return ptr; + } else { + return nullptr; + } + } + +private: + kj::Own server; + _::CapabilityServerSetBase* capServerSet = nullptr; + void* ptr = nullptr; +}; + +kj::Own Capability::Client::makeLocalClient(kj::Own&& server) { + return kj::refcounted(kj::mv(server)); +} + +kj::Own newLocalPromiseClient(kj::Promise>&& promise) { + return kj::refcounted(kj::mv(promise)); +} + +kj::Own newLocalPromisePipeline(kj::Promise>&& promise) { + return kj::refcounted(kj::mv(promise)); +} + +// ======================================================================================= + +namespace { + +class BrokenPipeline final: public PipelineHook, public kj::Refcounted { +public: + BrokenPipeline(const kj::Exception& exception): exception(exception) {} + + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) override; + +private: + kj::Exception exception; +}; + +class BrokenRequest final: public RequestHook { +public: + BrokenRequest(const kj::Exception& exception, kj::Maybe sizeHint) + : exception(exception), message(firstSegmentSize(sizeHint)) {} + + RemotePromise send() override { + return RemotePromise(kj::cp(exception), + AnyPointer::Pipeline(kj::refcounted(exception))); + } + + const void* getBrand() override { + return nullptr; + } + + kj::Exception exception; + MallocMessageBuilder message; +}; + +class BrokenClient final: public ClientHook, public kj::Refcounted { +public: + BrokenClient(const kj::Exception& exception, bool resolved, const void* brand = nullptr) + : exception(exception), resolved(resolved), brand(brand) {} + BrokenClient(const kj::StringPtr description, bool resolved, const void* brand = nullptr) + : exception(kj::Exception::Type::FAILED, "", 0, kj::str(description)), + resolved(resolved), brand(brand) {} + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + return newBrokenRequest(kj::cp(exception), sizeHint); + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + return VoidPromiseAndPipeline { kj::cp(exception), kj::refcounted(exception) }; + } + + kj::Maybe getResolved() override { + return nullptr; + } + + kj::Maybe>> whenMoreResolved() override { + if (resolved) { + return nullptr; + } else { + return kj::Promise>(kj::cp(exception)); + } + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + const void* getBrand() override { + return brand; + } + +private: + kj::Exception exception; + bool resolved; + const void* brand; +}; + +kj::Own BrokenPipeline::getPipelinedCap(kj::ArrayPtr ops) { + return kj::refcounted(exception, false); +} + +kj::Own newNullCap() { + // A null capability, unlike other broken capabilities, is considered resolved. + return kj::refcounted("Called null capability.", true, + &ClientHook::NULL_CAPABILITY_BRAND); +} + +} // namespace + +kj::Own newBrokenCap(kj::StringPtr reason) { + return kj::refcounted(reason, false); +} + +kj::Own newBrokenCap(kj::Exception&& reason) { + return kj::refcounted(kj::mv(reason), false); +} + +kj::Own newBrokenPipeline(kj::Exception&& reason) { + return kj::refcounted(kj::mv(reason)); +} + +Request newBrokenRequest( + kj::Exception&& reason, kj::Maybe sizeHint) { + auto hook = kj::heap(kj::mv(reason), sizeHint); + auto root = hook->message.getRoot(); + return Request(root, kj::mv(hook)); +} + +// ======================================================================================= + +ReaderCapabilityTable::ReaderCapabilityTable( + kj::Array>> table) + : table(kj::mv(table)) { + setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory); +} + +kj::Maybe> ReaderCapabilityTable::extractCap(uint index) { + if (index < table.size()) { + return table[index].map([](kj::Own& cap) { return cap->addRef(); }); + } else { + return nullptr; + } +} + +BuilderCapabilityTable::BuilderCapabilityTable() { + setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory); +} + +kj::Maybe> BuilderCapabilityTable::extractCap(uint index) { + if (index < table.size()) { + return table[index].map([](kj::Own& cap) { return cap->addRef(); }); + } else { + return nullptr; + } +} + +uint BuilderCapabilityTable::injectCap(kj::Own&& cap) { + uint result = table.size(); + table.add(kj::mv(cap)); + return result; +} + +void BuilderCapabilityTable::dropCap(uint index) { + KJ_ASSERT(index < table.size(), "Invalid capability descriptor in message.") { + return; + } + table[index] = nullptr; +} + +// ======================================================================================= +// CapabilityServerSet + +namespace _ { // private + +Capability::Client CapabilityServerSetBase::addInternal( + kj::Own&& server, void* ptr) { + return Capability::Client(kj::refcounted(kj::mv(server), *this, ptr)); +} + +kj::Promise CapabilityServerSetBase::getLocalServerInternal(Capability::Client& client) { + ClientHook* hook = client.hook.get(); + + // Get the most-resolved-so-far version of the hook. + KJ_IF_MAYBE(h, hook->getResolved()) { + hook = h; + }; + + KJ_IF_MAYBE(p, hook->whenMoreResolved()) { + // This hook is an unresolved promise. We need to wait for it. + return p->attach(hook->addRef()) + .then([this](kj::Own&& resolved) { + Capability::Client client(kj::mv(resolved)); + return getLocalServerInternal(client); + }); + } else { + return hook->getLocalServer(*this); + } +} + +} // namespace _ (private) + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/capability.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/capability.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,884 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_CAPABILITY_H_ +#define CAPNP_CAPABILITY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#if CAPNP_LITE +#error "RPC APIs, including this header, are not available in lite mode." +#endif + +#include +#include +#include "raw-schema.h" +#include "any.h" +#include "pointer-helpers.h" + +namespace capnp { + +template +class Response; + +template +class RemotePromise: public kj::Promise>, public T::Pipeline { + // A Promise which supports pipelined calls. T is typically a struct type. T must declare + // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply + // multiply-inherits that type along with Promise>. T::Pipeline must be movable, + // but does not need to be copyable (i.e. just like Promise). + // + // The promise is for an owned pointer so that the RPC system can allocate the MessageReader + // itself. + +public: + inline RemotePromise(kj::Promise>&& promise, typename T::Pipeline&& pipeline) + : kj::Promise>(kj::mv(promise)), + T::Pipeline(kj::mv(pipeline)) {} + inline RemotePromise(decltype(nullptr)) + : kj::Promise>(nullptr), + T::Pipeline(nullptr) {} + KJ_DISALLOW_COPY(RemotePromise); + RemotePromise(RemotePromise&& other) = default; + RemotePromise& operator=(RemotePromise&& other) = default; +}; + +class LocalClient; +namespace _ { // private +extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++ +class CapabilityServerSetBase; +} // namespace _ (private) + +struct Capability { + // A capability without type-safe methods. Typed capability clients wrap `Client` and typed + // capability servers subclass `Server` to dispatch to the regular, typed methods. + + class Client; + class Server; + + struct _capnpPrivate { + struct IsInterface; + static constexpr uint64_t typeId = 0x3; + static constexpr Kind kind = Kind::INTERFACE; + static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA; + + static const _::RawBrandedSchema* brand() { + return &_::NULL_INTERFACE_SCHEMA.defaultBrand; + } + }; +}; + +// ======================================================================================= +// Capability clients + +class RequestHook; +class ResponseHook; +class PipelineHook; +class ClientHook; + +template +class Request: public Params::Builder { + // A call that hasn't been sent yet. This class extends a Builder for the call's "Params" + // structure with a method send() that actually sends it. + // + // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have + // a method `Request fooRequest()` (as well as a convenience method + // `RemotePromise foo(A::Reader a, B::Reader b)`). + +public: + inline Request(typename Params::Builder builder, kj::Own&& hook) + : Params::Builder(builder), hook(kj::mv(hook)) {} + inline Request(decltype(nullptr)): Params::Builder(nullptr) {} + + RemotePromise send() KJ_WARN_UNUSED_RESULT; + // Send the call and return a promise for the results. + +private: + kj::Own hook; + + friend class Capability::Client; + friend struct DynamicCapability; + template + friend class CallContext; + friend class RequestHook; +}; + +template +class Response: public Results::Reader { + // A completed call. This class extends a Reader for the call's answer structure. The Response + // is move-only -- once it goes out-of-scope, the underlying message will be freed. + +public: + inline Response(typename Results::Reader reader, kj::Own&& hook) + : Results::Reader(reader), hook(kj::mv(hook)) {} + +private: + kj::Own hook; + + template + friend class Request; + friend class ResponseHook; +}; + +class Capability::Client { + // Base type for capability clients. + +public: + typedef Capability Reads; + typedef Capability Calls; + + Client(decltype(nullptr)); + // If you need to declare a Client before you have anything to assign to it (perhaps because + // the assignment is going to occur in an if/else scope), you can start by initializing it to + // `nullptr`. The resulting client is not meant to be called and throws exceptions from all + // methods. + + template ()>> + Client(kj::Own&& server); + // Make a client capability that wraps the given server capability. The server's methods will + // only be executed in the given EventLoop, regardless of what thread calls the client's methods. + + template ()>> + Client(kj::Promise&& promise); + // Make a client from a promise for a future client. The resulting client queues calls until the + // promise resolves. + + Client(kj::Exception&& exception); + // Make a broken client that throws the given exception from all calls. + + Client(Client& other); + Client& operator=(Client& other); + // Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of + // the client must remain in one thread. + + Client(Client&&) = default; + Client& operator=(Client&&) = default; + // Move constructor avoids reference counting. + + explicit Client(kj::Own&& hook); + // For use by the RPC implementation: Wrap a ClientHook. + + template + typename T::Client castAs(); + // Reinterpret the capability as implementing the given interface. Note that no error will occur + // here if the capability does not actually implement this interface, but later method calls will + // fail. It's up to the application to decide how indicate that additional interfaces are + // supported. + // + // TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance. + + template + typename T::Client castAs(InterfaceSchema schema); + // Dynamic version. `T` must be `DynamicCapability`, and you must `#include `. + + kj::Promise whenResolved(); + // If the capability is actually only a promise, the returned promise resolves once the + // capability itself has resolved to its final destination (or propagates the exception if + // the capability promise is rejected). This is mainly useful for error-checking in the case + // where no calls are being made. There is no reason to wait for this before making calls; if + // the capability does not resolve, the call results will propagate the error. + + Request typelessRequest( + uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint); + // Make a request without knowing the types of the params or results. You specify the type ID + // and method number manually. + + // TODO(someday): method(s) for Join + +protected: + Client() = default; + + template + Request newCall(uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint); + +private: + kj::Own hook; + + static kj::Own makeLocalClient(kj::Own&& server); + + template + friend struct _::PointerHelpers; + friend struct DynamicCapability; + friend class Orphanage; + friend struct DynamicStruct; + friend struct DynamicList; + template + friend struct List; + friend class _::CapabilityServerSetBase; + friend class ClientHook; +}; + +// ======================================================================================= +// Capability servers + +class CallContextHook; + +template +class CallContext: public kj::DisallowConstCopy { + // Wrapper around CallContextHook with a specific return type. + // + // Methods of this class may only be called from within the server's event loop, not from other + // threads. + // + // The CallContext becomes invalid as soon as the call reports completion. + +public: + explicit CallContext(CallContextHook& hook); + + typename Params::Reader getParams(); + // Get the params payload. + + void releaseParams(); + // Release the params payload. getParams() will throw an exception after this is called. + // Releasing the params may allow the RPC system to free up buffer space to handle other + // requests. Long-running asynchronous methods should try to call this as early as is + // convenient. + + typename Results::Builder getResults(kj::Maybe sizeHint = nullptr); + typename Results::Builder initResults(kj::Maybe sizeHint = nullptr); + void setResults(typename Results::Reader value); + void adoptResults(Orphan&& value); + Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); + // Manipulate the results payload. The "Return" message (part of the RPC protocol) will + // typically be allocated the first time one of these is called. Some RPC systems may + // allocate these messages in a limited space (such as a shared memory segment), therefore the + // application should delay calling these as long as is convenient to do so (but don't delay + // if doing so would require extra copies later). + // + // `sizeHint` indicates a guess at the message size. This will usually be used to decide how + // much space to allocate for the first message segment (don't worry: only space that is actually + // used will be sent on the wire). If omitted, the system decides. The message root pointer + // should not be included in the size. So, if you are simply going to copy some existing message + // directly into the results, just call `.totalSize()` and pass that in. + + template + kj::Promise tailCall(Request&& tailRequest); + // Resolve the call by making a tail call. `tailRequest` is a request that has been filled in + // but not yet sent. The context will send the call, then fill in the results with the result + // of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called. + // + // The RPC implementation may be able to optimize a tail call to another machine such that the + // results never actually pass through this machine. Even if no such optimization is possible, + // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site. + // + // In general, this should be the last thing a method implementation calls, and the promise + // returned from `tailCall()` should then be returned by the method implementation. + + void allowCancellation(); + // Indicate that it is OK for the RPC system to discard its Promise for this call's result if + // the caller cancels the call, thereby transitively canceling any asynchronous operations the + // call implementation was performing. This is not done by default because it could represent a + // security risk: applications must be carefully written to ensure that they do not end up in + // a bad state if an operation is canceled at an arbitrary point. However, for long-running + // method calls that hold significant resources, prompt cancellation is often useful. + // + // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously + // executing on a local thread. The method must perform an asynchronous operation or call + // `EventLoop::current().evalLater()` to yield control. + // + // Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that + // provide notification when the caller cancels the request without forcefully killing off the + // promise chain. Unfortunately, this composes poorly with promise forking: the canceled + // path may be just one branch of a fork of the result promise. The other branches still want + // the call to continue. Promise forking is used within the Cap'n Proto implementation -- in + // particular each pipelined call forks the result promise. So, if a caller made a pipelined + // call and then dropped the original object, the call should not be canceled, but it would be + // excessively complicated for the framework to avoid notififying of cancellation as long as + // pipelined calls still exist. + +private: + CallContextHook* hook; + + friend class Capability::Server; + friend struct DynamicCapability; +}; + +class Capability::Server { + // Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects + // will instead subclass a typed Server interface which will take care of implementing + // dispatchCall(). + +public: + typedef Capability Serves; + + virtual kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + CallContext context) = 0; + // Call the given method. `params` is the input struct, and should be released as soon as it + // is no longer needed. `context` may be used to allocate the output struct and deal with + // cancellation. + + // TODO(someday): Method which can optionally be overridden to implement Join when the object is + // a proxy. + +protected: + inline Capability::Client thisCap(); + // Get a capability pointing to this object, much like the `this` keyword. + // + // The effect of this method is undefined if: + // - No capability client has been created pointing to this object. (This is always the case in + // the server's constructor.) + // - The capability client pointing at this object has been destroyed. (This is always the case + // in the server's destructor.) + // - Multiple capability clients have been created around the same server (possible if the server + // is refcounted, which is not recommended since the client itself provides refcounting). + + template + CallContext internalGetTypedContext( + CallContext typeless); + kj::Promise internalUnimplemented(const char* actualInterfaceName, + uint64_t requestedTypeId); + kj::Promise internalUnimplemented(const char* interfaceName, + uint64_t typeId, uint16_t methodId); + kj::Promise internalUnimplemented(const char* interfaceName, const char* methodName, + uint64_t typeId, uint16_t methodId); + +private: + ClientHook* thisHook = nullptr; + friend class LocalClient; +}; + +// ======================================================================================= + +class ReaderCapabilityTable: private _::CapTableReader { + // Class which imbues Readers with the ability to read capabilities. + // + // In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into + // an external table. Since these pointers fundamentally point outside the message, a + // MessageReader by default has no idea what they point at, and therefore reading capabilities + // from such a reader will throw exceptions. + // + // In order to be able to read capabilities, you must first attach a capability table, using + // this class. By "imbuing" a Reader, you get a new Reader which will interpret capability + // pointers by treating them as indexes into the ReaderCapabilityTable. + // + // Note that when using Cap'n Proto's RPC system, this is handled automatically. + +public: + explicit ReaderCapabilityTable(kj::Array>> table); + KJ_DISALLOW_COPY(ReaderCapabilityTable); + + template + T imbue(T reader); + // Return a reader equivalent to `reader` except that when reading capability-valued fields, + // the capabilities are looked up in this table. + +private: + kj::Array>> table; + + kj::Maybe> extractCap(uint index) override; +}; + +class BuilderCapabilityTable: private _::CapTableBuilder { + // Class which imbues Builders with the ability to read and write capabilities. + // + // This is much like ReaderCapabilityTable, except for builders. The table starts out empty, + // but capabilities can be added to it over time. + +public: + BuilderCapabilityTable(); + KJ_DISALLOW_COPY(BuilderCapabilityTable); + + inline kj::ArrayPtr>> getTable() { return table; } + + template + T imbue(T builder); + // Return a builder equivalent to `builder` except that when reading capability-valued fields, + // the capabilities are looked up in this table. + +private: + kj::Vector>> table; + + kj::Maybe> extractCap(uint index) override; + uint injectCap(kj::Own&& cap) override; + void dropCap(uint index) override; +}; + +// ======================================================================================= + +namespace _ { // private + +class CapabilityServerSetBase { +public: + Capability::Client addInternal(kj::Own&& server, void* ptr); + kj::Promise getLocalServerInternal(Capability::Client& client); +}; + +} // namespace _ (private) + +template +class CapabilityServerSet: private _::CapabilityServerSetBase { + // Allows a server to recognize its own capabilities when passed back to it, and obtain the + // underlying Server objects associated with them. + // + // All objects in the set must have the same interface type T. The objects may implement various + // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects), + // but note that if you compile with RTTI disabled then you will not be able to down-cast through + // virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI + // disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type, + // and you server class will need to be directly derived from that, so that you can use + // static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile + // with RTTI, then you can freely dynamic_cast and ignore this issue!) + +public: + CapabilityServerSet() = default; + KJ_DISALLOW_COPY(CapabilityServerSet); + + typename T::Client add(kj::Own&& server); + // Create a new capability Client for the given Server and also add this server to the set. + + kj::Promise> getLocalServer(typename T::Client& client); + // Given a Client pointing to a server previously passed to add(), return the corresponding + // Server. This returns a promise because if the input client is itself a promise, this must + // wait for it to resolve. Keep in mind that the server will be deleted when all clients are + // gone, so the caller should make sure to keep the client alive (hence why this method only + // accepts an lvalue input). +}; + +// ======================================================================================= +// Hook interfaces which must be implemented by the RPC system. Applications never call these +// directly; the RPC system implements them and the types defined earlier in this file wrap them. + +class RequestHook { + // Hook interface implemented by RPC system representing a request being built. + +public: + virtual RemotePromise send() = 0; + // Send the call and return a promise for the result. + + virtual const void* getBrand() = 0; + // Returns a void* that identifies who made this request. This can be used by an RPC adapter to + // discover when tail call is going to be sent over its own connection and therefore can be + // optimized into a remote tail call. + + template + inline static kj::Own from(Request&& request) { + return kj::mv(request.hook); + } +}; + +class ResponseHook { + // Hook interface implemented by RPC system representing a response. + // + // At present this class has no methods. It exists only for garbage collection -- when the + // ResponseHook is destroyed, the results can be freed. + +public: + virtual ~ResponseHook() noexcept(false); + // Just here to make sure the type is dynamic. + + template + inline static kj::Own from(Response&& response) { + return kj::mv(response.hook); + } +}; + +// class PipelineHook is declared in any.h because it is needed there. + +class ClientHook { +public: + ClientHook(); + + virtual Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) = 0; + // Start a new call, allowing the client to allocate request/response objects as it sees fit. + // This version is used when calls are made from application code in the local process. + + struct VoidPromiseAndPipeline { + kj::Promise promise; + kj::Own pipeline; + }; + + virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) = 0; + // Call the object, but the caller controls allocation of the request/response objects. If the + // callee insists on allocating these objects itself, it must make a copy. This version is used + // when calls come in over the network via an RPC system. Note that even if the returned + // `Promise` is discarded, the call may continue executing if any pipelined calls are + // waiting for it. + // + // Since the caller of this method chooses the CallContext implementation, it is the caller's + // responsibility to ensure that the returned promise is not canceled unless allowed via + // the context's `allowCancellation()`. + // + // The call must not begin synchronously; the callee must arrange for the call to begin in a + // later turn of the event loop. Otherwise, application code may call back and affect the + // callee's state in an unexpected way. + + virtual kj::Maybe getResolved() = 0; + // If this ClientHook is a promise that has already resolved, returns the inner, resolved version + // of the capability. The caller may permanently replace this client with the resolved one if + // desired. Returns null if the client isn't a promise or hasn't resolved yet -- use + // `whenMoreResolved()` to distinguish between them. + + virtual kj::Maybe>> whenMoreResolved() = 0; + // If this client is a settled reference (not a promise), return nullptr. Otherwise, return a + // promise that eventually resolves to a new client that is closer to being the final, settled + // client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly + // should eventually produce a settled client. + + kj::Promise whenResolved(); + // Repeatedly calls whenMoreResolved() until it returns nullptr. + + virtual kj::Own addRef() = 0; + // Return a new reference to the same capability. + + virtual const void* getBrand() = 0; + // Returns a void* that identifies who made this client. This can be used by an RPC adapter to + // discover when a capability it needs to marshal is one that it created in the first place, and + // therefore it can transfer the capability without proxying. + + static const uint NULL_CAPABILITY_BRAND; + // Value is irrelevant; used for pointer. + + inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; } + // Returns true if the capability was created as a result of assigning a Client to null or by + // reading a null pointer out of a Cap'n Proto message. + + virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet); + // If this is a local capability created through `capServerSet`, return the underlying Server. + // Otherwise, return nullptr. Default implementation (which everyone except LocalClient should + // use) always returns nullptr. + + static kj::Own from(Capability::Client client) { return kj::mv(client.hook); } +}; + +class CallContextHook { + // Hook interface implemented by RPC system to manage a call on the server side. See + // CallContext. + +public: + virtual AnyPointer::Reader getParams() = 0; + virtual void releaseParams() = 0; + virtual AnyPointer::Builder getResults(kj::Maybe sizeHint) = 0; + virtual kj::Promise tailCall(kj::Own&& request) = 0; + virtual void allowCancellation() = 0; + + virtual kj::Promise onTailCall() = 0; + // If `tailCall()` is called, resolves to the PipelineHook from the tail call. An + // implementation of `ClientHook::call()` is allowed to call this at most once. + + virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) = 0; + // Call this when you would otherwise call onTailCall() immediately followed by tailCall(). + // Implementations of tailCall() should typically call directTailCall() and then fulfill the + // promise fulfiller for onTailCall() with the returned pipeline. + + virtual kj::Own addRef() = 0; +}; + +kj::Own newLocalPromiseClient(kj::Promise>&& promise); +// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to +// the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the +// redirection to the eventual replacement client. + +kj::Own newLocalPromisePipeline(kj::Promise>&& promise); +// Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to +// the new pipeline. + +kj::Own newBrokenCap(kj::StringPtr reason); +kj::Own newBrokenCap(kj::Exception&& reason); +// Helper function that creates a capability which simply throws exceptions when called. + +kj::Own newBrokenPipeline(kj::Exception&& reason); +// Helper function that creates a pipeline which simply throws exceptions when called. + +Request newBrokenRequest( + kj::Exception&& reason, kj::Maybe sizeHint); +// Helper function that creates a Request object that simply throws exceptions when sent. + +// ======================================================================================= +// Extend PointerHelpers for interfaces + +namespace _ { // private + +template +struct PointerHelpers { + static inline typename T::Client get(PointerReader reader) { + return typename T::Client(reader.getCapability()); + } + static inline typename T::Client get(PointerBuilder builder) { + return typename T::Client(builder.getCapability()); + } + static inline void set(PointerBuilder builder, typename T::Client&& value) { + builder.setCapability(kj::mv(value.Capability::Client::hook)); + } + static inline void set(PointerBuilder builder, typename T::Client& value) { + builder.setCapability(value.Capability::Client::hook->addRef()); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +} // namespace _ (private) + +// ======================================================================================= +// Extend List for interfaces + +template +struct List { + List() = delete; + + class Reader { + public: + typedef List Reads; + + Reader() = default; + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Client operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename T::Client(reader.getPointerElement( + bounded(index) * ELEMENTS).getCapability()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + Builder() = delete; + inline Builder(decltype(nullptr)) {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Client operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename T::Client(builder.getPointerElement( + bounded(index) * ELEMENTS).getCapability()); + } + inline void set(uint index, typename T::Client value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(value.hook)); + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +// ======================================================================================= +// Inline implementation details + +template +RemotePromise Request::send() { + auto typelessPromise = hook->send(); + hook = nullptr; // prevent reuse + + // Convert the Promise to return the correct response type. + // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the + // Pipeline part of the RemotePromise. + auto typedPromise = kj::implicitCast>&>(typelessPromise) + .then([](Response&& response) -> Response { + return Response(response.getAs(), kj::mv(response.hook)); + }); + + // Wrap the typeless pipeline in a typed wrapper. + typename Results::Pipeline typedPipeline( + kj::mv(kj::implicitCast(typelessPromise))); + + return RemotePromise(kj::mv(typedPromise), kj::mv(typedPipeline)); +} + +inline Capability::Client::Client(kj::Own&& hook): hook(kj::mv(hook)) {} +template +inline Capability::Client::Client(kj::Own&& server) + : hook(makeLocalClient(kj::mv(server))) {} +template +inline Capability::Client::Client(kj::Promise&& promise) + : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {} +inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {} +inline Capability::Client& Capability::Client::operator=(Client& other) { + hook = other.hook->addRef(); + return *this; +} +template +inline typename T::Client Capability::Client::castAs() { + return typename T::Client(hook->addRef()); +} +inline kj::Promise Capability::Client::whenResolved() { + return hook->whenResolved(); +} +inline Request Capability::Client::typelessRequest( + uint64_t interfaceId, uint16_t methodId, + kj::Maybe sizeHint) { + return newCall(interfaceId, methodId, sizeHint); +} +template +inline Request Capability::Client::newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) { + auto typeless = hook->newCall(interfaceId, methodId, sizeHint); + return Request(typeless.template getAs(), kj::mv(typeless.hook)); +} + +template +inline CallContext::CallContext(CallContextHook& hook): hook(&hook) {} +template +inline typename Params::Reader CallContext::getParams() { + return hook->getParams().template getAs(); +} +template +inline void CallContext::releaseParams() { + hook->releaseParams(); +} +template +inline typename Results::Builder CallContext::getResults( + kj::Maybe sizeHint) { + // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 + return hook->getResults(sizeHint).template getAs(); +} +template +inline typename Results::Builder CallContext::initResults( + kj::Maybe sizeHint) { + // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 + return hook->getResults(sizeHint).template initAs(); +} +template +inline void CallContext::setResults(typename Results::Reader value) { + hook->getResults(value.totalSize()).template setAs(value); +} +template +inline void CallContext::adoptResults(Orphan&& value) { + hook->getResults(nullptr).adopt(kj::mv(value)); +} +template +inline Orphanage CallContext::getResultsOrphanage( + kj::Maybe sizeHint) { + return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); +} +template +template +inline kj::Promise CallContext::tailCall( + Request&& tailRequest) { + return hook->tailCall(kj::mv(tailRequest.hook)); +} +template +inline void CallContext::allowCancellation() { + hook->allowCancellation(); +} + +template +CallContext Capability::Server::internalGetTypedContext( + CallContext typeless) { + return CallContext(*typeless.hook); +} + +Capability::Client Capability::Server::thisCap() { + return Client(thisHook->addRef()); +} + +template +T ReaderCapabilityTable::imbue(T reader) { + return T(_::PointerHelpers>::getInternalReader(reader).imbue(this)); +} + +template +T BuilderCapabilityTable::imbue(T builder) { + return T(_::PointerHelpers>::getInternalBuilder(kj::mv(builder)).imbue(this)); +} + +template +typename T::Client CapabilityServerSet::add(kj::Own&& server) { + void* ptr = reinterpret_cast(server.get()); + // Clang insists that `castAs` is a template-dependent member and therefore we need the + // `template` keyword here, but AFAICT this is wrong: addImpl() is not a template. + return addInternal(kj::mv(server), ptr).template castAs(); +} + +template +kj::Promise> CapabilityServerSet::getLocalServer( + typename T::Client& client) { + return getLocalServerInternal(client) + .then([](void* server) -> kj::Maybe { + if (server == nullptr) { + return nullptr; + } else { + return *reinterpret_cast(server); + } + }); +} + +template +struct Orphanage::GetInnerReader { + static inline kj::Own apply(typename T::Client t) { + return ClientHook::from(kj::mv(t)); + } +}; + +} // namespace capnp + +#endif // CAPNP_CAPABILITY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/capnpc.ekam-rule --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/capnpc.ekam-rule Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,71 @@ +#! /bin/sh + +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +set -eu + +if test $# = 0; then + echo trigger filetype:.capnp + exit 0 +fi + +INPUT=$1 + +case "$INPUT" in + *capnp/c++.capnp | \ + *capnp/schema.capnp | \ + *capnp/rpc.capnp | \ + *capnp/rpc-twoparty.capnp | \ + *capnp/persistent.capnp | \ + *capnp/compiler/lexer.capnp | \ + *capnp/compiler/grammar.capnp | \ + *capnp/compat/json.capnp ) + exit 0 + ;; +esac + +echo findProvider special:ekam-interceptor +read INTERCEPTOR + +if test "$INTERCEPTOR" = ""; then + echo "error: couldn't find intercept.so." >&2 + exit 1 +fi + +echo findProvider file:compiler/capnp +read CAPNP + +if test "$CAPNP" = ""; then + echo "error: couldn't find capnp." >&2 + exit 1 +fi + +echo findProvider file:capnpc-c++ +read CAPNPC_CXX + +if test "$CAPNPC_CXX" = ""; then + echo "error: couldn't find capnpc-c++." >&2 + exit 1 +fi + +LD_PRELOAD=$INTERCEPTOR DYLD_FORCE_FLAT_NAMESPACE= DYLD_INSERT_LIBRARIES=$INTERCEPTOR \ +$CAPNP compile -I. -o$CAPNPC_CXX "$INPUT" 3>&1 4<&0 >&2 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/common-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/common-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,87 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "common.h" +#include +#include +#include +#include + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +namespace capnp { +namespace { + +TEST(Common, Version) { +#ifdef VERSION + auto expectedVersion = + kj::str(CAPNP_VERSION_MAJOR, '.', CAPNP_VERSION_MINOR, '.', CAPNP_VERSION_MICRO); + auto devVersion = + kj::str(CAPNP_VERSION_MAJOR, '.', CAPNP_VERSION_MINOR, "-dev"); + kj::StringPtr actualVersion = VERSION; + KJ_ASSERT(actualVersion == expectedVersion || + actualVersion.startsWith(kj::str(expectedVersion, '-')) || + actualVersion.startsWith(kj::str(expectedVersion, '.')) || + (actualVersion == devVersion && CAPNP_VERSION_MICRO == 0), + expectedVersion, actualVersion); +#endif +} + +struct ExampleStruct { + struct _capnpPrivate { + struct IsStruct; + }; +}; +struct ExampleInterface { + struct _capnpPrivate { + struct IsInterface; + }; +}; + +static_assert(_::Kind_::kind == Kind::STRUCT, "Kind SFINAE failed."); +static_assert(_::Kind_::kind == Kind::INTERFACE, "Kind SFINAE failed."); + +// Test FromAnay<> +template +struct EqualTypes_ { static constexpr bool value = false; }; + +template +struct EqualTypes_ { static constexpr bool value = true; }; + +template +inline constexpr bool equalTypes() { return EqualTypes_::value; } + +using capnproto_test::capnp::test::TestAllTypes; +using capnproto_test::capnp::test::TestInterface; + +static_assert(equalTypes, int>(), ""); +static_assert(equalTypes, TestAllTypes>(), ""); +static_assert(equalTypes, TestAllTypes>(), ""); +#if !CAPNP_LITE +static_assert(equalTypes, TestAllTypes>(), ""); +static_assert(equalTypes, TestInterface>(), ""); +static_assert(equalTypes>, TestInterface>(), ""); +#endif + +} // namespace +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,719 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains types which are intended to help detect incorrect usage at compile +// time, but should then be optimized down to basic primitives (usually, integers) by the +// compiler. + +#ifndef CAPNP_COMMON_H_ +#define CAPNP_COMMON_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include + +#if CAPNP_DEBUG_TYPES +#include +#endif + +namespace capnp { + +#define CAPNP_VERSION_MAJOR 0 +#define CAPNP_VERSION_MINOR 6 +#define CAPNP_VERSION_MICRO 0 + +#define CAPNP_VERSION \ + (CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO) + +#ifndef CAPNP_LITE +#define CAPNP_LITE 0 +#endif + +typedef unsigned int uint; + +struct Void { + // Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves + // differently from other types. + + inline constexpr bool operator==(Void other) const { return true; } + inline constexpr bool operator!=(Void other) const { return false; } +}; + +static constexpr Void VOID = Void(); +// Constant value for `Void`, which is an empty struct. + +inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; } + +struct Text; +struct Data; + +enum class Kind: uint8_t { + PRIMITIVE, + BLOB, + ENUM, + STRUCT, + UNION, + INTERFACE, + LIST, + + OTHER + // Some other type which is often a type parameter to Cap'n Proto templates, but which needs + // special handling. This includes types like AnyPointer, Dynamic*, etc. +}; + +enum class Style: uint8_t { + PRIMITIVE, + POINTER, // other than struct + STRUCT, + CAPABILITY +}; + +enum class ElementSize: uint8_t { + // Size of a list element. + + VOID = 0, + BIT = 1, + BYTE = 2, + TWO_BYTES = 3, + FOUR_BYTES = 4, + EIGHT_BYTES = 5, + + POINTER = 6, + + INLINE_COMPOSITE = 7 +}; + +enum class PointerType { + // Various wire types a pointer field can take + + NULL_, + // Should be NULL, but that's #defined in stddef.h + + STRUCT, + LIST, + CAPABILITY +}; + +namespace schemas { + +template +struct EnumInfo; + +} // namespace schemas + +namespace _ { // private + +template struct Kind_; + +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::PRIMITIVE; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::BLOB; }; + +template struct Kind_> { + static constexpr Kind kind = Kind::STRUCT; +}; +template struct Kind_> { + static constexpr Kind kind = Kind::INTERFACE; +}; +template struct Kind_::IsEnum>> { + static constexpr Kind kind = Kind::ENUM; +}; + +} // namespace _ (private) + +template ::kind> +inline constexpr Kind kind() { + // This overload of kind() matches types which have a Kind_ specialization. + + return k; +} + +#if CAPNP_LITE + +#define CAPNP_KIND(T) ::capnp::_::Kind_::kind +// Avoid constexpr methods in lite mode (MSVC is bad at constexpr). + +#else // CAPNP_LITE + +#define CAPNP_KIND(T) ::capnp::kind() +// Use this macro rather than kind() in any code which must work in lite mode. + +template ()> +inline constexpr Style style() { + return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE + : k == Kind::STRUCT ? Style::STRUCT + : k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER; +} + +#endif // CAPNP_LITE, else + +template +struct List; + +#if _MSC_VER + +template +struct List {}; +// For some reason, without this declaration, MSVC will error out on some uses of List +// claiming that "T" -- as used in the default initializer for the second template param, "k" -- +// is not defined. I do not understand this error, but adding this empty default declaration fixes +// it. + +#endif + +template struct ListElementType_; +template struct ListElementType_> { typedef T Type; }; +template using ListElementType = typename ListElementType_::Type; + +namespace _ { // private +template struct Kind_> { + static constexpr Kind kind = Kind::LIST; +}; +} // namespace _ (private) + +template struct ReaderFor_ { typedef typename T::Reader Type; }; +template struct ReaderFor_ { typedef T Type; }; +template struct ReaderFor_ { typedef T Type; }; +template struct ReaderFor_ { typedef typename T::Client Type; }; +template using ReaderFor = typename ReaderFor_::Type; +// The type returned by List::Reader::operator[]. + +template struct BuilderFor_ { typedef typename T::Builder Type; }; +template struct BuilderFor_ { typedef T Type; }; +template struct BuilderFor_ { typedef T Type; }; +template struct BuilderFor_ { typedef typename T::Client Type; }; +template using BuilderFor = typename BuilderFor_::Type; +// The type returned by List::Builder::operator[]. + +template struct PipelineFor_ { typedef typename T::Pipeline Type;}; +template struct PipelineFor_ { typedef typename T::Client Type; }; +template using PipelineFor = typename PipelineFor_::Type; + +template struct TypeIfEnum_; +template struct TypeIfEnum_ { typedef T Type; }; + +template +using TypeIfEnum = typename TypeIfEnum_>::Type; + +template +using FromReader = typename kj::Decay::Reads; +// FromReader = MyType (for any Cap'n Proto type). + +template +using FromBuilder = typename kj::Decay::Builds; +// FromBuilder = MyType (for any Cap'n Proto type). + +template +using FromPipeline = typename kj::Decay::Pipelines; +// FromBuilder = MyType (for any Cap'n Proto type). + +template +using FromClient = typename kj::Decay::Calls; +// FromReader = MyType (for any Cap'n Proto interface type). + +template +using FromServer = typename kj::Decay::Serves; +// FromBuilder = MyType (for any Cap'n Proto interface type). + +template +struct FromAny_; + +template +struct FromAny_>> { + using Type = FromReader; +}; + +template +struct FromAny_>> { + using Type = FromBuilder; +}; + +template +struct FromAny_>> { + using Type = FromPipeline; +}; + +// Note that T::Client is covered by FromReader + +template +struct FromAny_, kj::VoidSfinae>> { + using Type = FromServer; +}; + +template +struct FromAny_::kind == Kind::PRIMITIVE || _::Kind_::kind == Kind::ENUM>> { + // TODO(msvc): Ideally the EnableIf condition would be `style() == Style::PRIMITIVE`, but MSVC + // cannot yet use style() in this constexpr context. + + using Type = kj::Decay; +}; + +template +using FromAny = typename FromAny_::Type; +// Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is: +// +// Foo::Reader -> Foo +// Foo::Builder -> Foo +// Foo::Pipeline -> Foo +// Foo::Client -> Foo +// Own -> Foo +// uint32_t -> uint32_t + +namespace _ { // private + +template +struct PointerHelpers; + +#if _MSC_VER + +template +struct PointerHelpers {}; +// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers +// claiming that "T" -- as used in the default initializer for the second template param, "k" -- +// is not defined. I do not understand this error, but adding this empty default declaration fixes +// it. + +#endif + +} // namespace _ (private) + +struct MessageSize { + // Size of a message. Every struct type has a method `.totalSize()` that returns this. + uint64_t wordCount; + uint capCount; +}; + +// ======================================================================================= +// Raw memory types and measures + +using kj::byte; + +class word { uint64_t content KJ_UNUSED_MEMBER; KJ_DISALLOW_COPY(word); public: word() = default; }; +// word is an opaque type with size of 64 bits. This type is useful only to make pointer +// arithmetic clearer. Since the contents are private, the only way to access them is to first +// reinterpret_cast to some other pointer type. +// +// Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of +// aliasing rules. +// +// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as +// that type. + +static_assert(sizeof(byte) == 1, "uint8_t is not one byte?"); +static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?"); + +#if CAPNP_DEBUG_TYPES +// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are +// used. All the code should still operate exactly the same, we just lose compile-time checking. +// Note that this will also change symbol names, so it's important that the library and any clients +// be compiled with the same setting here. +// +// We disable this by default to reduce symbol name size and avoid any possibility of the compiler +// failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this +// during development and testing. + +namespace _ { class BitLabel; class ElementLabel; struct WirePointer; } + +template +using BitCountN = kj::Quantity(), T>, _::BitLabel>; +template +using ByteCountN = kj::Quantity(), T>, byte>; +template +using WordCountN = kj::Quantity(), T>, word>; +template +using ElementCountN = kj::Quantity(), T>, _::ElementLabel>; +template +using WirePointerCountN = kj::Quantity(), T>, _::WirePointer>; + +typedef BitCountN<8, uint8_t> BitCount8; +typedef BitCountN<16, uint16_t> BitCount16; +typedef BitCountN<32, uint32_t> BitCount32; +typedef BitCountN<64, uint64_t> BitCount64; +typedef BitCountN BitCount; + +typedef ByteCountN<8, uint8_t> ByteCount8; +typedef ByteCountN<16, uint16_t> ByteCount16; +typedef ByteCountN<32, uint32_t> ByteCount32; +typedef ByteCountN<64, uint64_t> ByteCount64; +typedef ByteCountN ByteCount; + +typedef WordCountN<8, uint8_t> WordCount8; +typedef WordCountN<16, uint16_t> WordCount16; +typedef WordCountN<32, uint32_t> WordCount32; +typedef WordCountN<64, uint64_t> WordCount64; +typedef WordCountN WordCount; + +typedef ElementCountN<8, uint8_t> ElementCount8; +typedef ElementCountN<16, uint16_t> ElementCount16; +typedef ElementCountN<32, uint32_t> ElementCount32; +typedef ElementCountN<64, uint64_t> ElementCount64; +typedef ElementCountN ElementCount; + +typedef WirePointerCountN<8, uint8_t> WirePointerCount8; +typedef WirePointerCountN<16, uint16_t> WirePointerCount16; +typedef WirePointerCountN<32, uint32_t> WirePointerCount32; +typedef WirePointerCountN<64, uint64_t> WirePointerCount64; +typedef WirePointerCountN WirePointerCount; + +template +using BitsPerElementN = decltype(BitCountN() / ElementCountN()); +template +using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); +template +using WordsPerElementN = decltype(WordCountN() / ElementCountN()); +template +using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); + +using kj::bounded; +using kj::unbound; +using kj::unboundAs; +using kj::unboundMax; +using kj::unboundMaxBits; +using kj::assertMax; +using kj::assertMaxBits; +using kj::upgradeBound; +using kj::ThrowOverflow; +using kj::assumeBits; +using kj::assumeMax; +using kj::subtractChecked; +using kj::trySubtract; + +template +inline constexpr U* operator+(U* ptr, kj::Quantity offset) { + return ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator+(const U* ptr, kj::Quantity offset) { + return ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr U* operator+=(U*& ptr, kj::Quantity offset) { + return ptr = ptr + unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator+=(const U*& ptr, kj::Quantity offset) { + return ptr = ptr + unbound(offset / kj::unit>()); +} + +template +inline constexpr U* operator-(U* ptr, kj::Quantity offset) { + return ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator-(const U* ptr, kj::Quantity offset) { + return ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr U* operator-=(U*& ptr, kj::Quantity offset) { + return ptr = ptr - unbound(offset / kj::unit>()); +} +template +inline constexpr const U* operator-=(const U*& ptr, kj::Quantity offset) { + return ptr = ptr - unbound(offset / kj::unit>()); +} + +constexpr auto BITS = kj::unit>(); +constexpr auto BYTES = kj::unit>(); +constexpr auto WORDS = kj::unit>(); +constexpr auto ELEMENTS = kj::unit>(); +constexpr auto POINTERS = kj::unit>(); + +constexpr auto ZERO = kj::bounded<0>(); +constexpr auto ONE = kj::bounded<1>(); + +// GCC 4.7 actually gives unused warnings on these constants in opt mode... +constexpr auto BITS_PER_BYTE KJ_UNUSED = bounded<8>() * BITS / BYTES; +constexpr auto BITS_PER_WORD KJ_UNUSED = bounded<64>() * BITS / WORDS; +constexpr auto BYTES_PER_WORD KJ_UNUSED = bounded<8>() * BYTES / WORDS; + +constexpr auto BITS_PER_POINTER KJ_UNUSED = bounded<64>() * BITS / POINTERS; +constexpr auto BYTES_PER_POINTER KJ_UNUSED = bounded<8>() * BYTES / POINTERS; +constexpr auto WORDS_PER_POINTER KJ_UNUSED = ONE * WORDS / POINTERS; + +constexpr auto POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; + +constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. +constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. +constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. +constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. +constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. + +typedef WordCountN SegmentWordCount; +typedef ElementCountN ListElementCount; +typedef WordCountN StructDataWordCount; +typedef WirePointerCountN StructPointerCount; +typedef ByteCountN BlobSize; + +constexpr auto MAX_SEGMENT_WORDS = + bounded()>() * WORDS; +constexpr auto MAX_LIST_ELEMENTS = + bounded()>() * ELEMENTS; +constexpr auto MAX_STUCT_DATA_WORDS = + bounded()>() * WORDS; +constexpr auto MAX_STRUCT_POINTER_COUNT = + bounded()>() * POINTERS; + +using StructDataBitCount = decltype(WordCountN() * BITS_PER_WORD); +// Number of bits in a Struct data segment (should come out to BitCountN<22>). + +using StructDataOffset = decltype(StructDataBitCount() * (ONE * ELEMENTS / BITS)); +using StructPointerOffset = StructPointerCount; +// Type of a field offset. + +inline StructDataOffset assumeDataOffset(uint32_t offset) { + return assumeMax(MAX_STUCT_DATA_WORDS * BITS_PER_WORD * (ONE * ELEMENTS / BITS), + bounded(offset) * ELEMENTS); +} + +inline StructPointerOffset assumePointerOffset(uint32_t offset) { + return assumeMax(MAX_STRUCT_POINTER_COUNT, bounded(offset) * POINTERS); +} + +constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; +typedef kj::Quantity, byte> TextSize; +// Not including NUL terminator. + +template +inline KJ_CONSTEXPR() decltype(bounded() * BYTES / ELEMENTS) bytesPerElement() { + return bounded() * BYTES / ELEMENTS; +} + +template +inline KJ_CONSTEXPR() decltype(bounded() * BITS / ELEMENTS) bitsPerElement() { + return bounded() * BITS / ELEMENTS; +} + +template +inline constexpr kj::Quantity, T> +intervalLength(const T* a, const T* b, kj::Quantity, T>) { + return kj::assumeMax(b - a) * kj::unit, T>>(); +} + +template +inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, kj::Quantity size) { + return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); +} +template +inline constexpr kj::ArrayPtr arrayPtr(U* ptr, kj::Quantity size) { + return kj::ArrayPtr(ptr, unbound(size / kj::unit>())); +} + +#else + +template +using BitCountN = T; +template +using ByteCountN = T; +template +using WordCountN = T; +template +using ElementCountN = T; +template +using WirePointerCountN = T; + + +// XXX +typedef BitCountN<8, uint8_t> BitCount8; +typedef BitCountN<16, uint16_t> BitCount16; +typedef BitCountN<32, uint32_t> BitCount32; +typedef BitCountN<64, uint64_t> BitCount64; +typedef BitCountN BitCount; + +typedef ByteCountN<8, uint8_t> ByteCount8; +typedef ByteCountN<16, uint16_t> ByteCount16; +typedef ByteCountN<32, uint32_t> ByteCount32; +typedef ByteCountN<64, uint64_t> ByteCount64; +typedef ByteCountN ByteCount; + +typedef WordCountN<8, uint8_t> WordCount8; +typedef WordCountN<16, uint16_t> WordCount16; +typedef WordCountN<32, uint32_t> WordCount32; +typedef WordCountN<64, uint64_t> WordCount64; +typedef WordCountN WordCount; + +typedef ElementCountN<8, uint8_t> ElementCount8; +typedef ElementCountN<16, uint16_t> ElementCount16; +typedef ElementCountN<32, uint32_t> ElementCount32; +typedef ElementCountN<64, uint64_t> ElementCount64; +typedef ElementCountN ElementCount; + +typedef WirePointerCountN<8, uint8_t> WirePointerCount8; +typedef WirePointerCountN<16, uint16_t> WirePointerCount16; +typedef WirePointerCountN<32, uint32_t> WirePointerCount32; +typedef WirePointerCountN<64, uint64_t> WirePointerCount64; +typedef WirePointerCountN WirePointerCount; + +template +using BitsPerElementN = decltype(BitCountN() / ElementCountN()); +template +using BytesPerElementN = decltype(ByteCountN() / ElementCountN()); +template +using WordsPerElementN = decltype(WordCountN() / ElementCountN()); +template +using PointersPerElementN = decltype(WirePointerCountN() / ElementCountN()); + +using kj::ThrowOverflow; +// YYY + +template inline constexpr uint bounded() { return i; } +template inline constexpr T bounded(T i) { return i; } +template inline constexpr T unbound(T i) { return i; } + +template inline constexpr T unboundAs(U i) { return i; } + +template inline constexpr uint unboundMax(T i) { return i; } +template inline constexpr uint unboundMaxBits(T i) { return i; } + +template +inline T assertMax(T value, ErrorFunc&& func) { + if (KJ_UNLIKELY(value > newMax)) func(); + return value; +} + +template +inline T assertMax(uint newMax, T value, ErrorFunc&& func) { + if (KJ_UNLIKELY(value > newMax)) func(); + return value; +} + +template +inline T assertMaxBits(T value, ErrorFunc&& func = ErrorFunc()) { + if (KJ_UNLIKELY(value > kj::maxValueForBits())) func(); + return value; +} + +template +inline T assertMaxBits(uint bits, T value, ErrorFunc&& func = ErrorFunc()) { + if (KJ_UNLIKELY(value > (1ull << bits) - 1)) func(); + return value; +} + +template inline constexpr T upgradeBound(U i) { return i; } + +template inline constexpr T assumeBits(T i) { return i; } +template inline constexpr T assumeMax(T i) { return i; } + +template +inline auto subtractChecked(T a, U b, ErrorFunc&& errorFunc = ErrorFunc()) + -> decltype(a - b) { + if (b > a) errorFunc(); + return a - b; +} + +template +inline auto trySubtract(T a, U b) -> kj::Maybe { + if (b > a) { + return nullptr; + } else { + return a - b; + } +} + +constexpr uint BITS = 1; +constexpr uint BYTES = 1; +constexpr uint WORDS = 1; +constexpr uint ELEMENTS = 1; +constexpr uint POINTERS = 1; + +constexpr uint ZERO = 0; +constexpr uint ONE = 1; + +// GCC 4.7 actually gives unused warnings on these constants in opt mode... +constexpr uint BITS_PER_BYTE KJ_UNUSED = 8; +constexpr uint BITS_PER_WORD KJ_UNUSED = 64; +constexpr uint BYTES_PER_WORD KJ_UNUSED = 8; + +constexpr uint BITS_PER_POINTER KJ_UNUSED = 64; +constexpr uint BYTES_PER_POINTER KJ_UNUSED = 8; +constexpr uint WORDS_PER_POINTER KJ_UNUSED = 1; + +// XXX +constexpr uint POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER; + +constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment. +constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list. +constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section. +constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section. +constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob. + +typedef WordCountN SegmentWordCount; +typedef ElementCountN ListElementCount; +typedef WordCountN StructDataWordCount; +typedef WirePointerCountN StructPointerCount; +typedef ByteCountN BlobSize; +// YYY + +constexpr auto MAX_SEGMENT_WORDS = kj::maxValueForBits(); +constexpr auto MAX_LIST_ELEMENTS = kj::maxValueForBits(); +constexpr auto MAX_STUCT_DATA_WORDS = kj::maxValueForBits(); +constexpr auto MAX_STRUCT_POINTER_COUNT = kj::maxValueForBits(); + +typedef uint StructDataBitCount; +typedef uint StructDataOffset; +typedef uint StructPointerOffset; + +inline StructDataOffset assumeDataOffset(uint32_t offset) { return offset; } +inline StructPointerOffset assumePointerOffset(uint32_t offset) { return offset; } + +constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits() - 1; +typedef uint TextSize; + +template +inline KJ_CONSTEXPR() size_t bytesPerElement() { return sizeof(T); } + +template +inline KJ_CONSTEXPR() size_t bitsPerElement() { return sizeof(T) * 8; } + +template +inline constexpr ptrdiff_t intervalLength(const T* a, const T* b, uint) { + return b - a; +} + +template +inline constexpr kj::ArrayPtr arrayPtr(const U* ptr, T size) { + return kj::arrayPtr(ptr, size); +} +template +inline constexpr kj::ArrayPtr arrayPtr(U* ptr, T size) { + return kj::arrayPtr(ptr, size); +} + +#endif + +} // namespace capnp + +#endif // CAPNP_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,731 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "json.h" +#include +#include +#include +#include +#include + +namespace capnp { +namespace _ { // private +namespace { + +KJ_TEST("basic json encoding") { + JsonCodec json; + + KJ_EXPECT(json.encode(VOID) == "null"); + KJ_EXPECT(json.encode(true) == "true"); + KJ_EXPECT(json.encode(false) == "false"); + KJ_EXPECT(json.encode(123) == "123"); + KJ_EXPECT(json.encode(-5.5) == "-5.5"); + KJ_EXPECT(json.encode(Text::Reader("foo")) == "\"foo\""); + KJ_EXPECT(json.encode(Text::Reader("ab\"cd\\ef\x03")) == "\"ab\\\"cd\\\\ef\\u0003\""); + KJ_EXPECT(json.encode(test::TestEnum::CORGE) == "\"corge\""); + + byte bytes[] = {12, 34, 56}; + KJ_EXPECT(json.encode(Data::Reader(bytes, 3)) == "[12,34,56]"); + + json.setPrettyPrint(true); + KJ_EXPECT(json.encode(Data::Reader(bytes, 3)) == "[12, 34, 56]"); +} + +const char ALL_TYPES_JSON[] = + "{ \"voidField\": null,\n" + " \"boolField\": true,\n" + " \"int8Field\": -123,\n" + " \"int16Field\": -12345,\n" + " \"int32Field\": -12345678,\n" + " \"int64Field\": \"-123456789012345\",\n" + " \"uInt8Field\": 234,\n" + " \"uInt16Field\": 45678,\n" + " \"uInt32Field\": 3456789012,\n" + " \"uInt64Field\": \"12345678901234567890\",\n" + " \"float32Field\": 1234.5,\n" + " \"float64Field\": -1.23e47,\n" + " \"textField\": \"foo\",\n" + " \"dataField\": [98, 97, 114],\n" + " \"structField\": {\n" + " \"voidField\": null,\n" + " \"boolField\": true,\n" + " \"int8Field\": -12,\n" + " \"int16Field\": 3456,\n" + " \"int32Field\": -78901234,\n" + " \"int64Field\": \"56789012345678\",\n" + " \"uInt8Field\": 90,\n" + " \"uInt16Field\": 1234,\n" + " \"uInt32Field\": 56789012,\n" + " \"uInt64Field\": \"345678901234567890\",\n" + " \"float32Field\": -1.2499999646475857e-10,\n" + " \"float64Field\": 345,\n" + " \"textField\": \"baz\",\n" + " \"dataField\": [113, 117, 120],\n" + " \"structField\": {\n" + " \"voidField\": null,\n" + " \"boolField\": false,\n" + " \"int8Field\": 0,\n" + " \"int16Field\": 0,\n" + " \"int32Field\": 0,\n" + " \"int64Field\": \"0\",\n" + " \"uInt8Field\": 0,\n" + " \"uInt16Field\": 0,\n" + " \"uInt32Field\": 0,\n" + " \"uInt64Field\": \"0\",\n" + " \"float32Field\": 0,\n" + " \"float64Field\": 0,\n" + " \"textField\": \"nested\",\n" + " \"structField\": {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"really nested\", \"enumField\": \"foo\", \"interfaceField\": null},\n" + " \"enumField\": \"foo\",\n" + " \"interfaceField\": null },\n" + " \"enumField\": \"baz\",\n" + " \"interfaceField\": null,\n" + " \"voidList\": [null, null, null],\n" + " \"boolList\": [false, true, false, true, true],\n" + " \"int8List\": [12, -34, -128, 127],\n" + " \"int16List\": [1234, -5678, -32768, 32767],\n" + " \"int32List\": [12345678, -90123456, -2147483648, 2147483647],\n" + " \"int64List\": [\"123456789012345\", \"-678901234567890\", \"-9223372036854775808\", \"9223372036854775807\"],\n" + " \"uInt8List\": [12, 34, 0, 255],\n" + " \"uInt16List\": [1234, 5678, 0, 65535],\n" + " \"uInt32List\": [12345678, 90123456, 0, 4294967295],\n" + " \"uInt64List\": [\"123456789012345\", \"678901234567890\", \"0\", \"18446744073709551615\"],\n" + " \"float32List\": [0, 1234567, 9.9999999338158125e36, -9.9999999338158125e36, 9.99999991097579e-38, -9.99999991097579e-38],\n" + " \"float64List\": [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306],\n" + " \"textList\": [\"quux\", \"corge\", \"grault\"],\n" + " \"dataList\": [[103, 97, 114, 112, 108, 121], [119, 97, 108, 100, 111], [102, 114, 101, 100]],\n" + " \"structList\": [\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 1\", \"enumField\": \"foo\", \"interfaceField\": null},\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 2\", \"enumField\": \"foo\", \"interfaceField\": null},\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 3\", \"enumField\": \"foo\", \"interfaceField\": null} ],\n" + " \"enumList\": [\"qux\", \"bar\", \"grault\"] },\n" + " \"enumField\": \"corge\",\n" + " \"interfaceField\": null,\n" + " \"voidList\": [null, null, null, null, null, null],\n" + " \"boolList\": [true, false, false, true],\n" + " \"int8List\": [111, -111],\n" + " \"int16List\": [11111, -11111],\n" + " \"int32List\": [111111111, -111111111],\n" + " \"int64List\": [\"1111111111111111111\", \"-1111111111111111111\"],\n" + " \"uInt8List\": [111, 222],\n" + " \"uInt16List\": [33333, 44444],\n" + " \"uInt32List\": [3333333333],\n" + " \"uInt64List\": [\"11111111111111111111\"],\n" + " \"float32List\": [5555.5, \"Infinity\", \"-Infinity\", \"NaN\"],\n" + " \"float64List\": [7777.75, \"Infinity\", \"-Infinity\", \"NaN\"],\n" + " \"textList\": [\"plugh\", \"xyzzy\", \"thud\"],\n" + " \"dataList\": [[111, 111, 112, 115], [101, 120, 104, 97, 117, 115, 116, 101, 100], [114, 102, 99, 51, 48, 57, 50]],\n" + " \"structList\": [\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 1\", \"enumField\": \"foo\", \"interfaceField\": null},\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 2\", \"enumField\": \"foo\", \"interfaceField\": null},\n" + " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 3\", \"enumField\": \"foo\", \"interfaceField\": null} ],\n" + " \"enumList\": [\"foo\", \"garply\"] }"; + +KJ_TEST("encode all types") { + MallocMessageBuilder message; + auto root = message.getRoot(); + initTestMessage(root); + + JsonCodec json; + json.setPrettyPrint(true); + KJ_EXPECT(json.encode(root) == ALL_TYPES_JSON); + + // Verify that if we strip out the non-string spaces, we get the non-pretty-print version. + kj::Vector chars; + bool inQuotes = false; + for (char c: ALL_TYPES_JSON) { + if (c == '\"') inQuotes = !inQuotes; + + if ((c == '\n' || c == ' ') && !inQuotes) { + // skip space + } else { + chars.add(c); + } + } + kj::String nospaces(chars.releaseAsArray()); + + json.setPrettyPrint(false); + KJ_EXPECT(json.encode(root) == nospaces); +} + +KJ_TEST("encode union") { + MallocMessageBuilder message; + auto root = message.getRoot(); + + root.setBefore("a"); + root.setMiddle(44); + root.setAfter("c"); + + JsonCodec json; + + root.setFoo(123); + KJ_EXPECT(json.encode(root) == "{\"before\":\"a\",\"foo\":123,\"middle\":44,\"after\":\"c\"}"); + + root.setBar(321); + KJ_EXPECT(json.encode(root) == "{\"before\":\"a\",\"middle\":44,\"bar\":321,\"after\":\"c\"}"); +} + +KJ_TEST("decode all types") { + JsonCodec json; +#define CASE(s, f) \ + { \ + MallocMessageBuilder message; \ + auto root = message.initRoot(); \ + json.decode(s, root); \ + KJ_EXPECT((f)) \ + } +#define CASE_THROW(s, errorMessage) \ + { \ + MallocMessageBuilder message; \ + auto root = message.initRoot(); \ + KJ_EXPECT_THROW_MESSAGE(errorMessage, json.decode(s, root)); \ + } +#define CASE_THROW_RECOVERABLE(s, errorMessage) \ + { \ + MallocMessageBuilder message; \ + auto root = message.initRoot(); \ + KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(errorMessage, json.decode(s, root)); \ + } + + CASE(R"({})", root.getBoolField() == false); + CASE(R"({"unknownField":7})", root.getBoolField() == false); + CASE(R"({"boolField":true})", root.getBoolField() == true); + CASE(R"({"int8Field":-128})", root.getInt8Field() == -128); + CASE(R"({"int8Field":"127"})", root.getInt8Field() == 127); + CASE_THROW_RECOVERABLE(R"({"int8Field":"-129"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"int8Field":128})", "Value out-of-range"); + CASE(R"({"int16Field":-32768})", root.getInt16Field() == -32768); + CASE(R"({"int16Field":"32767"})", root.getInt16Field() == 32767); + CASE_THROW_RECOVERABLE(R"({"int16Field":"-32769"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"int16Field":32768})", "Value out-of-range"); + CASE(R"({"int32Field":-2147483648})", root.getInt32Field() == -2147483648); + CASE(R"({"int32Field":"2147483647"})", root.getInt32Field() == 2147483647); + CASE(R"({"int64Field":-9007199254740992})", root.getInt64Field() == -9007199254740992LL); + CASE(R"({"int64Field":9007199254740991})", root.getInt64Field() == 9007199254740991LL); + CASE(R"({"int64Field":"-9223372036854775808"})", root.getInt64Field() == -9223372036854775808ULL); + CASE(R"({"int64Field":"9223372036854775807"})", root.getInt64Field() == 9223372036854775807LL); + CASE_THROW_RECOVERABLE(R"({"int64Field":"-9223372036854775809"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"int64Field":"9223372036854775808"})", "Value out-of-range"); + CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255); + CASE(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0); + CASE_THROW_RECOVERABLE(R"({"uInt8Field":"256"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"uInt8Field":-1})", "Value out-of-range"); + CASE(R"({"uInt16Field":65535})", root.getUInt16Field() == 65535); + CASE(R"({"uInt16Field":"0"})", root.getUInt16Field() == 0); + CASE_THROW_RECOVERABLE(R"({"uInt16Field":"655356"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"uInt16Field":-1})", "Value out-of-range"); + CASE(R"({"uInt32Field":4294967295})", root.getUInt32Field() == 4294967295); + CASE(R"({"uInt32Field":"0"})", root.getUInt32Field() == 0); + CASE_THROW_RECOVERABLE(R"({"uInt32Field":"42949672956"})", "Value out-of-range"); + CASE_THROW_RECOVERABLE(R"({"uInt32Field":-1})", "Value out-of-range"); + CASE(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL); + CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL); + CASE(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0); + CASE_THROW_RECOVERABLE(R"({"uInt64Field":"18446744073709551616"})", "Value out-of-range"); + CASE(R"({"float32Field":0})", root.getFloat32Field() == 0); + CASE(R"({"float32Field":4.5})", root.getFloat32Field() == 4.5); + CASE(R"({"float32Field":null})", kj::isNaN(root.getFloat32Field())); + CASE(R"({"float32Field":"nan"})", kj::isNaN(root.getFloat32Field())); + CASE(R"({"float32Field":"nan"})", kj::isNaN(root.getFloat32Field())); + CASE(R"({"float32Field":"Infinity"})", root.getFloat32Field() == kj::inf()); + CASE(R"({"float32Field":"-Infinity"})", root.getFloat32Field() == -kj::inf()); + CASE(R"({"float64Field":0})", root.getFloat64Field() == 0); + CASE(R"({"float64Field":4.5})", root.getFloat64Field() == 4.5); + CASE(R"({"float64Field":null})", kj::isNaN(root.getFloat64Field())); + CASE(R"({"float64Field":"nan"})", kj::isNaN(root.getFloat64Field())); + CASE(R"({"float64Field":"nan"})", kj::isNaN(root.getFloat64Field())); + CASE(R"({"float64Field":"Infinity"})", root.getFloat64Field() == kj::inf()); + CASE(R"({"float64Field":"-Infinity"})", root.getFloat64Field() == -kj::inf()); + CASE(R"({"textField":"hello"})", kj::str("hello") == root.getTextField()); + CASE(R"({"dataField":[7,0,122]})", + kj::heapArray({7,0,122}).asPtr() == root.getDataField()); + CASE(R"({"structField":null})", root.hasStructField() == false); + CASE(R"({"structField":{}})", root.hasStructField() == true); + CASE(R"({"structField":{}})", root.getStructField().getBoolField() == false); + CASE(R"({"structField":{"boolField":false}})", root.getStructField().getBoolField() == false); + CASE(R"({"structField":{"boolField":true}})", root.getStructField().getBoolField() == true); + CASE(R"({"enumField":"bar"})", root.getEnumField() == TestEnum::BAR); + + CASE_THROW_RECOVERABLE(R"({"int64Field":"177a"})", "String does not contain valid"); + CASE_THROW_RECOVERABLE(R"({"uInt64Field":"177a"})", "String does not contain valid"); + CASE_THROW_RECOVERABLE(R"({"float64Field":"177a"})", "String does not contain valid"); + + CASE(R"({})", root.hasBoolList() == false); + CASE(R"({"boolList":null})", root.hasBoolList() == false); + CASE(R"({"boolList":[]})", root.hasBoolList() == true); + CASE(R"({"boolList":[]})", root.getBoolList().size() == 0); + CASE(R"({"boolList":[false]})", root.getBoolList().size() == 1); + CASE(R"({"boolList":[false]})", root.getBoolList()[0] == false); + CASE(R"({"boolList":[true]})", root.getBoolList()[0] == true); + CASE(R"({"int8List":[7]})", root.getInt8List()[0] == 7); + CASE(R"({"int8List":["7"]})", root.getInt8List()[0] == 7); + CASE(R"({"int16List":[7]})", root.getInt16List()[0] == 7); + CASE(R"({"int16List":["7"]})", root.getInt16List()[0] == 7); + CASE(R"({"int32List":[7]})", root.getInt32List()[0] == 7); + CASE(R"({"int32List":["7"]})", root.getInt32List()[0] == 7); + CASE(R"({"int64List":[7]})", root.getInt64List()[0] == 7); + CASE(R"({"int64List":["7"]})", root.getInt64List()[0] == 7); + CASE(R"({"uInt8List":[7]})", root.getUInt8List()[0] == 7); + CASE(R"({"uInt8List":["7"]})", root.getUInt8List()[0] == 7); + CASE(R"({"uInt16List":[7]})", root.getUInt16List()[0] == 7); + CASE(R"({"uInt16List":["7"]})", root.getUInt16List()[0] == 7); + CASE(R"({"uInt32List":[7]})", root.getUInt32List()[0] == 7); + CASE(R"({"uInt32List":["7"]})", root.getUInt32List()[0] == 7); + CASE(R"({"uInt64List":[7]})", root.getUInt64List()[0] == 7); + CASE(R"({"uInt64List":["7"]})", root.getUInt64List()[0] == 7); + CASE(R"({"float32List":[4.5]})", root.getFloat32List()[0] == 4.5); + CASE(R"({"float32List":["4.5"]})", root.getFloat32List()[0] == 4.5); + CASE(R"({"float32List":[null]})", kj::isNaN(root.getFloat32List()[0])); + CASE(R"({"float32List":["nan"]})", kj::isNaN(root.getFloat32List()[0])); + CASE(R"({"float32List":["infinity"]})", root.getFloat32List()[0] == kj::inf()); + CASE(R"({"float32List":["-infinity"]})", root.getFloat32List()[0] == -kj::inf()); + CASE(R"({"float64List":[4.5]})", root.getFloat64List()[0] == 4.5); + CASE(R"({"float64List":["4.5"]})", root.getFloat64List()[0] == 4.5); + CASE(R"({"float64List":[null]})", kj::isNaN(root.getFloat64List()[0])); + CASE(R"({"float64List":["nan"]})", kj::isNaN(root.getFloat64List()[0])); + CASE(R"({"float64List":["infinity"]})", root.getFloat64List()[0] == kj::inf()); + CASE(R"({"float64List":["-infinity"]})", root.getFloat64List()[0] == -kj::inf()); + CASE(R"({"textList":["hello"]})", kj::str("hello") == root.getTextList()[0]); + CASE(R"({"dataList":[[7,0,122]]})", + kj::heapArray({7,0,122}).asPtr() == root.getDataList()[0]); + CASE(R"({"structList":null})", root.hasStructList() == false); + CASE(R"({"structList":[null]})", root.hasStructList() == true); + CASE(R"({"structList":[null]})", root.getStructList()[0].getBoolField() == false); + CASE(R"({"structList":[{}]})", root.getStructList()[0].getBoolField() == false); + CASE(R"({"structList":[{"boolField":false}]})", root.getStructList()[0].getBoolField() == false); + CASE(R"({"structList":[{"boolField":true}]})", root.getStructList()[0].getBoolField() == true); + CASE(R"({"enumList":["bar"]})", root.getEnumList()[0] == TestEnum::BAR); +#undef CASE +#undef CASE_THROW +#undef CASE_THROW_RECOVERABLE +} + +KJ_TEST("decode test message") { + MallocMessageBuilder message; + auto root = message.getRoot(); + initTestMessage(root); + + JsonCodec json; + auto encoded = json.encode(root); + + MallocMessageBuilder decodedMessage; + auto decodedRoot = decodedMessage.initRoot(); + json.decode(encoded, decodedRoot); + + KJ_EXPECT(root.toString().flatten() == decodedRoot.toString().flatten()); +} + +KJ_TEST("basic json decoding") { + // TODO(cleanup): this test is a mess! + JsonCodec json; + { + MallocMessageBuilder message; + auto root = message.initRoot(); + json.decodeRaw("null", root); + + KJ_EXPECT(root.which() == JsonValue::NULL_); + KJ_EXPECT(root.getNull() == VOID); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("false", root); + KJ_EXPECT(root.which() == JsonValue::BOOLEAN); + KJ_EXPECT(root.getBoolean() == false); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("true", root); + KJ_EXPECT(root.which() == JsonValue::BOOLEAN); + KJ_EXPECT(root.getBoolean() == true); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("\"foo\"", root); + KJ_EXPECT(root.which() == JsonValue::STRING); + KJ_EXPECT(kj::str("foo") == root.getString()); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(R"("\"")", root); + KJ_EXPECT(root.which() == JsonValue::STRING); + KJ_EXPECT(kj::str("\"") == root.getString()); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(R"("\\abc\"d\\e")", root); + KJ_EXPECT(root.which() == JsonValue::STRING); + KJ_EXPECT(kj::str("\\abc\"d\\e") == root.getString()); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(R"("\"\\\/\b\f\n\r\t\u0003abc\u0064\u0065f")", root); + KJ_EXPECT(root.which() == JsonValue::STRING); + KJ_EXPECT(kj::str("\"\\/\b\f\n\r\t\x03""abcdef") == root.getString(), root.getString()); + } + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("[]", root); + KJ_EXPECT(root.which() == JsonValue::ARRAY, (uint)root.which()); + KJ_EXPECT(root.getArray().size() == 0); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("[true]", root); + KJ_EXPECT(root.which() == JsonValue::ARRAY); + auto array = root.getArray(); + KJ_EXPECT(array.size() == 1, array.size()); + KJ_EXPECT(root.getArray()[0].which() == JsonValue::BOOLEAN); + KJ_EXPECT(root.getArray()[0].getBoolean() == true); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(" [ true , false\t\n , null]", root); + KJ_EXPECT(root.which() == JsonValue::ARRAY); + auto array = root.getArray(); + KJ_EXPECT(array.size() == 3); + KJ_EXPECT(array[0].which() == JsonValue::BOOLEAN); + KJ_EXPECT(array[0].getBoolean() == true); + KJ_EXPECT(array[1].which() == JsonValue::BOOLEAN); + KJ_EXPECT(array[1].getBoolean() == false); + KJ_EXPECT(array[2].which() == JsonValue::NULL_); + KJ_EXPECT(array[2].getNull() == VOID); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("{}", root); + KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); + KJ_EXPECT(root.getObject().size() == 0); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("\r\n\t {\r\n\t }\r\n\t ", root); + KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); + KJ_EXPECT(root.getObject().size() == 0); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(R"({"some": null})", root); + KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); + auto object = root.getObject(); + KJ_EXPECT(object.size() == 1); + KJ_EXPECT(kj::str("some") == object[0].getName()); + KJ_EXPECT(object[0].getValue().which() == JsonValue::NULL_); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(R"({"foo\n\tbaz": "a val", "bar": ["a", -5.5e11, { "z": {}}]})", root); + KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); + auto object = root.getObject(); + KJ_EXPECT(object.size() == 2); + KJ_EXPECT(kj::str("foo\n\tbaz") == object[0].getName()); + KJ_EXPECT(object[0].getValue().which() == JsonValue::STRING); + KJ_EXPECT(kj::str("a val") == object[0].getValue().getString()); + + KJ_EXPECT(kj::str("bar") == object[1].getName()); + KJ_EXPECT(object[1].getValue().which() == JsonValue::ARRAY); + auto array = object[1].getValue().getArray(); + KJ_EXPECT(array.size() == 3, array.size()); + KJ_EXPECT(array[0].which() == JsonValue::STRING); + KJ_EXPECT(kj::str("a") == array[0].getString()); + KJ_EXPECT(array[1].which() == JsonValue::NUMBER); + KJ_EXPECT(array[1].getNumber() == -5.5e11); + KJ_EXPECT(array[2].which() == JsonValue::OBJECT); + KJ_EXPECT(array[2].getObject().size() == 1); + KJ_EXPECT(array[2].getObject()[0].getValue().which() == JsonValue::OBJECT); + KJ_EXPECT(array[2].getObject()[0].getValue().getObject().size() == 0); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("123", root); + KJ_EXPECT(root.which() == JsonValue::NUMBER); + KJ_EXPECT(root.getNumber() == 123); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("input", json.decodeRaw("z", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + // Leading + not allowed in numbers. + KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("+123", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("Overflow", json.decodeRaw("1e1024", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("Underflow", json.decodeRaw("1e-1023", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("[00]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("[01]", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("-", root)); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("-5", root); + KJ_EXPECT(root.which() == JsonValue::NUMBER); + KJ_EXPECT(root.getNumber() == -5); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw("-5.5", root); + KJ_EXPECT(root.which() == JsonValue::NUMBER); + KJ_EXPECT(root.getNumber() == -5.5); + } + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("a", root)); + KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("[", root)); + KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("{", root)); + KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("\"\\u\"", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[}", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[}]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1, , ]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[,]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[true,]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[, 1]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1\"\"]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1,, \"\"]", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{\"a\"1: 0}", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw(R"({"some": null,})", root)); + KJ_EXPECT_THROW_MESSAGE("Input remains", json.decodeRaw("11a", root)); + KJ_EXPECT_THROW_MESSAGE("Invalid escape", json.decodeRaw(R"("\z")", root)); + KJ_EXPECT_THROW_MESSAGE("Invalid escape", json.decodeRaw(R"("\z")", root)); + { + // TODO(msvc): This raw string literal currently confuses MSVC's preprocessor, so I hoisted + // it outside the macro. + auto f = [&] { json.decodeRaw(R"(["\n\", 3])", root); }; + KJ_EXPECT_THROW_MESSAGE("ends prematurely", f()); + } + KJ_EXPECT_THROW_MESSAGE("Invalid hex", json.decodeRaw(R"("\u12zz")", root)); + KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("-", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("--", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("\f{}", root)); + KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{\v}", root)); + } +} + +KJ_TEST("maximum nesting depth") { + JsonCodec json; + auto input = kj::str(R"({"foo": "a", "bar": ["b", { "baz": [-5.5e11] }, [ [ 1 ], { "z": 2 }]]})"); + // `input` has a maximum nesting depth of 4, reached 3 times. + + { + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(input, root); + } + + { + json.setMaxNestingDepth(0); + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("nest", + json.decodeRaw(input, root)); + } + + { + json.setMaxNestingDepth(3); + MallocMessageBuilder message; + auto root = message.initRoot(); + + KJ_EXPECT_THROW_MESSAGE("nest", + json.decodeRaw(input, root)); + } + + { + json.setMaxNestingDepth(4); + MallocMessageBuilder message; + auto root = message.initRoot(); + + json.decodeRaw(input, root); + } +} + +class TestHandler: public JsonCodec::Handler { +public: + void encode(const JsonCodec& codec, Text::Reader input, + JsonValue::Builder output) const override { + auto call = output.initCall(); + call.setFunction("Frob"); + auto params = call.initParams(2); + params[0].setNumber(123); + params[1].setString(input); + } + + Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + Orphanage orphanage) const override { + KJ_UNIMPLEMENTED("TestHandler::decode"); + } +}; + +KJ_TEST("register handler") { + MallocMessageBuilder message; + auto root = message.getRoot(); + + TestHandler handler; + JsonCodec json; + json.addTypeHandler(handler); + + root.setOld1(123); + root.setOld2("foo"); + KJ_EXPECT(json.encode(root) == "{\"old1\":\"123\",\"old2\":Frob(123,\"foo\")}"); +} + +KJ_TEST("register field handler") { + MallocMessageBuilder message; + auto root = message.getRoot(); + + TestHandler handler; + JsonCodec json; + json.addFieldHandler(StructSchema::from().getFieldByName("corge"), + handler); + + root.setBaz("abcd"); + root.setCorge("efg"); + KJ_EXPECT(json.encode(root) == "{\"corge\":Frob(123,\"efg\"),\"baz\":\"abcd\"}"); +} + +class TestCapabilityHandler: public JsonCodec::Handler { +public: + void encode(const JsonCodec& codec, test::TestInterface::Client input, + JsonValue::Builder output) const override { + KJ_UNIMPLEMENTED("TestCapabilityHandler::encode"); + } + + test::TestInterface::Client decode( + const JsonCodec& codec, JsonValue::Reader input) const override { + return nullptr; + } +}; + +KJ_TEST("register capability handler") { + // This test currently only checks that this compiles, which at one point wasn't the caes. + // TODO(test): Actually run some code here. + + TestCapabilityHandler handler; + JsonCodec json; + json.addTypeHandler(handler); +} + +class TestDynamicStructHandler: public JsonCodec::Handler { +public: + void encode(const JsonCodec& codec, DynamicStruct::Reader input, + JsonValue::Builder output) const override { + KJ_UNIMPLEMENTED("TestDynamicStructHandler::encode"); + } + + void decode(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const override { + KJ_UNIMPLEMENTED("TestDynamicStructHandler::decode"); + } +}; + + +KJ_TEST("register DynamicStruct handler") { + // This test currently only checks that this compiles, which at one point wasn't the caes. + // TODO(test): Actually run some code here. + + TestDynamicStructHandler handler; + JsonCodec json; + json.addTypeHandler(Schema::from(), handler); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,931 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "json.h" +#include // for HUGEVAL to check for overflow in strtod +#include // strtod +#include // for strtod errors +#include +#include +#include +#include +#include + +namespace capnp { + +namespace { + +struct TypeHash { + size_t operator()(const Type& type) const { + return type.hashCode(); + } +}; + +struct FieldHash { + size_t operator()(const StructSchema::Field& field) const { + return field.getIndex() ^ field.getContainingStruct().getProto().getId(); + } +}; + +} // namespace + +struct JsonCodec::Impl { + bool prettyPrint = false; + size_t maxNestingDepth = 64; + + std::unordered_map typeHandlers; + std::unordered_map fieldHandlers; + + kj::StringTree encodeRaw(JsonValue::Reader value, uint indent, bool& multiline, + bool hasPrefix) const { + switch (value.which()) { + case JsonValue::NULL_: + return kj::strTree("null"); + case JsonValue::BOOLEAN: + return kj::strTree(value.getBoolean()); + case JsonValue::NUMBER: + return kj::strTree(value.getNumber()); + + case JsonValue::STRING: + return kj::strTree(encodeString(value.getString())); + + case JsonValue::ARRAY: { + auto array = value.getArray(); + uint subIndent = indent + (array.size() > 1); + bool childMultiline = false; + auto encodedElements = KJ_MAP(element, array) { + return encodeRaw(element, subIndent, childMultiline, false); + }; + + return kj::strTree('[', encodeList( + kj::mv(encodedElements), childMultiline, indent, multiline, hasPrefix), ']'); + } + + case JsonValue::OBJECT: { + auto object = value.getObject(); + uint subIndent = indent + (object.size() > 1); + bool childMultiline = false; + kj::StringPtr colon = prettyPrint ? ": " : ":"; + auto encodedElements = KJ_MAP(field, object) { + return kj::strTree( + encodeString(field.getName()), colon, + encodeRaw(field.getValue(), subIndent, childMultiline, true)); + }; + + return kj::strTree('{', encodeList( + kj::mv(encodedElements), childMultiline, indent, multiline, hasPrefix), '}'); + } + + case JsonValue::CALL: { + auto call = value.getCall(); + auto params = call.getParams(); + uint subIndent = indent + (params.size() > 1); + bool childMultiline = false; + auto encodedElements = KJ_MAP(element, params) { + return encodeRaw(element, subIndent, childMultiline, false); + }; + + return kj::strTree(call.getFunction(), '(', encodeList( + kj::mv(encodedElements), childMultiline, indent, multiline, true), ')'); + } + } + + KJ_FAIL_ASSERT("unknown JsonValue type", static_cast(value.which())); + } + + kj::String encodeString(kj::StringPtr chars) const { + static const char HEXDIGITS[] = "0123456789abcdef"; + kj::Vector escaped(chars.size() + 3); + + escaped.add('"'); + for (char c: chars) { + switch (c) { + case '\"': escaped.addAll(kj::StringPtr("\\\"")); break; + case '\\': escaped.addAll(kj::StringPtr("\\\\")); break; + case '/' : escaped.addAll(kj::StringPtr("\\/" )); break; + case '\b': escaped.addAll(kj::StringPtr("\\b")); break; + case '\f': escaped.addAll(kj::StringPtr("\\f")); break; + case '\n': escaped.addAll(kj::StringPtr("\\n")); break; + case '\r': escaped.addAll(kj::StringPtr("\\r")); break; + case '\t': escaped.addAll(kj::StringPtr("\\t")); break; + default: + if (c >= 0 && c < 0x20) { + escaped.addAll(kj::StringPtr("\\u00")); + uint8_t c2 = c; + escaped.add(HEXDIGITS[c2 / 16]); + escaped.add(HEXDIGITS[c2 % 16]); + } else { + escaped.add(c); + } + break; + } + } + escaped.add('"'); + escaped.add('\0'); + + return kj::String(escaped.releaseAsArray()); + } + + kj::StringTree encodeList(kj::Array elements, + bool hasMultilineElement, uint indent, bool& multiline, + bool hasPrefix) const { + size_t maxChildSize = 0; + for (auto& e: elements) maxChildSize = kj::max(maxChildSize, e.size()); + + kj::StringPtr prefix; + kj::StringPtr delim; + kj::StringPtr suffix; + kj::String ownPrefix; + kj::String ownDelim; + if (!prettyPrint) { + // No whitespace. + delim = ","; + prefix = ""; + suffix = ""; + } else if ((elements.size() > 1) && (hasMultilineElement || maxChildSize > 50)) { + // If the array contained any multi-line elements, OR it contained sufficiently long + // elements, then put each element on its own line. + auto indentSpace = kj::repeat(' ', (indent + 1) * 2); + delim = ownDelim = kj::str(",\n", indentSpace); + multiline = true; + if (hasPrefix) { + // We're producing a multi-line list, and the first line has some garbage in front of it. + // Therefore, move the first element to the next line. + prefix = ownPrefix = kj::str("\n", indentSpace); + } else { + prefix = " "; + } + suffix = " "; + } else { + // Put everything on one line, but add spacing between elements for legibility. + delim = ", "; + prefix = ""; + suffix = ""; + } + + return kj::strTree(prefix, kj::StringTree(kj::mv(elements), delim), suffix); + } +}; + +JsonCodec::JsonCodec() + : impl(kj::heap()) {} +JsonCodec::~JsonCodec() noexcept(false) {} + +void JsonCodec::setPrettyPrint(bool enabled) { impl->prettyPrint = enabled; } + +void JsonCodec::setMaxNestingDepth(size_t maxNestingDepth) { + impl->maxNestingDepth = maxNestingDepth; +} + +kj::String JsonCodec::encode(DynamicValue::Reader value, Type type) const { + MallocMessageBuilder message; + auto json = message.getRoot(); + encode(value, type, json); + return encodeRaw(json); +} + +void JsonCodec::decode(kj::ArrayPtr input, DynamicStruct::Builder output) const { + MallocMessageBuilder message; + auto json = message.getRoot(); + decodeRaw(input, json); + decode(json, output); +} + +Orphan JsonCodec::decode( + kj::ArrayPtr input, Type type, Orphanage orphanage) const { + MallocMessageBuilder message; + auto json = message.getRoot(); + decodeRaw(input, json); + return decode(json, type, orphanage); +} + +kj::String JsonCodec::encodeRaw(JsonValue::Reader value) const { + bool multiline = false; + return impl->encodeRaw(value, 0, multiline, false).flatten(); +} + +void JsonCodec::encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const { + // TODO(0.7): For interfaces, check for handlers on superclasses, per documentation... + // TODO(0.7): For branded types, should we check for handlers on the generic? + // TODO(someday): Allow registering handlers for "all structs", "all lists", etc? + auto iter = impl->typeHandlers.find(type); + if (iter != impl->typeHandlers.end()) { + iter->second->encodeBase(*this, input, output); + return; + } + + switch (type.which()) { + case schema::Type::VOID: + output.setNull(); + break; + case schema::Type::BOOL: + output.setBoolean(input.as()); + break; + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + output.setNumber(input.as()); + break; + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + { + double value = input.as(); + // Inf, -inf and NaN are not allowed in the JSON spec. Storing into string. + if (kj::inf() == value) { + output.setString("Infinity"); + } else if (-kj::inf() == value) { + output.setString("-Infinity"); + } else if (kj::isNaN(value)) { + output.setString("NaN"); + } else { + output.setNumber(value); + } + } + break; + case schema::Type::INT64: + output.setString(kj::str(input.as())); + break; + case schema::Type::UINT64: + output.setString(kj::str(input.as())); + break; + case schema::Type::TEXT: + output.setString(kj::str(input.as())); + break; + case schema::Type::DATA: { + // Turn into array of byte values. Yep, this is pretty ugly. People really need to override + // this with a handler. + auto bytes = input.as(); + auto array = output.initArray(bytes.size()); + for (auto i: kj::indices(bytes)) { + array[i].setNumber(bytes[i]); + } + break; + } + case schema::Type::LIST: { + auto list = input.as(); + auto elementType = type.asList().getElementType(); + auto array = output.initArray(list.size()); + for (auto i: kj::indices(list)) { + encode(list[i], elementType, array[i]); + } + break; + } + case schema::Type::ENUM: { + auto e = input.as(); + KJ_IF_MAYBE(symbol, e.getEnumerant()) { + output.setString(symbol->getProto().getName()); + } else { + output.setNumber(e.getRaw()); + } + break; + } + case schema::Type::STRUCT: { + auto structValue = input.as(); + auto nonUnionFields = structValue.getSchema().getNonUnionFields(); + + KJ_STACK_ARRAY(bool, hasField, nonUnionFields.size(), 32, 128); + + uint fieldCount = 0; + for (auto i: kj::indices(nonUnionFields)) { + fieldCount += (hasField[i] = structValue.has(nonUnionFields[i])); + } + + // We try to write the union field, if any, in proper order with the rest. + auto which = structValue.which(); + bool unionFieldIsNull = false; + + KJ_IF_MAYBE(field, which) { + // Even if the union field is null, if it is not the default field of the union then we + // have to print it anyway. + unionFieldIsNull = !structValue.has(*field); + if (field->getProto().getDiscriminantValue() != 0 || !unionFieldIsNull) { + ++fieldCount; + } else { + which = nullptr; + } + } + + auto object = output.initObject(fieldCount); + + size_t pos = 0; + for (auto i: kj::indices(nonUnionFields)) { + auto field = nonUnionFields[i]; + KJ_IF_MAYBE(unionField, which) { + if (unionField->getIndex() < field.getIndex()) { + auto outField = object[pos++]; + outField.setName(unionField->getProto().getName()); + if (unionFieldIsNull) { + outField.initValue().setNull(); + } else { + encodeField(*unionField, structValue.get(*unionField), outField.initValue()); + } + which = nullptr; + } + } + if (hasField[i]) { + auto outField = object[pos++]; + outField.setName(field.getProto().getName()); + encodeField(field, structValue.get(field), outField.initValue()); + } + } + if (which != nullptr) { + // Union field not printed yet; must be last. + auto unionField = KJ_ASSERT_NONNULL(which); + auto outField = object[pos++]; + outField.setName(unionField.getProto().getName()); + if (unionFieldIsNull) { + outField.initValue().setNull(); + } else { + encodeField(unionField, structValue.get(unionField), outField.initValue()); + } + } + KJ_ASSERT(pos == fieldCount); + break; + } + case schema::Type::INTERFACE: + KJ_FAIL_REQUIRE("don't know how to JSON-encode capabilities; " + "please register a JsonCodec::Handler for this"); + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("don't know how to JSON-encode AnyPointer; " + "please register a JsonCodec::Handler for this"); + } +} + +void JsonCodec::encodeField(StructSchema::Field field, DynamicValue::Reader input, + JsonValue::Builder output) const { + auto iter = impl->fieldHandlers.find(field); + if (iter != impl->fieldHandlers.end()) { + iter->second->encodeBase(*this, input, output); + return; + } + + encode(input, field.getType(), output); +} + +namespace { + +template +void decodeField(Type type, JsonValue::Reader value, SetFn setFn, DecodeArrayFn decodeArrayFn, + DecodeObjectFn decodeObjectFn) { + // This code relies on conversions in DynamicValue::Reader::as. + switch(type.which()) { + case schema::Type::VOID: + break; + case schema::Type::BOOL: + switch (value.which()) { + case JsonValue::BOOLEAN: + setFn(value.getBoolean()); + break; + default: + KJ_FAIL_REQUIRE("Expected boolean value"); + } + break; + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + // Relies on range check in DynamicValue::Reader::as + switch (value.which()) { + case JsonValue::NUMBER: + setFn(value.getNumber()); + break; + case JsonValue::STRING: + setFn(value.getString().parseAs()); + break; + default: + KJ_FAIL_REQUIRE("Expected integer value"); + } + break; + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + // Relies on range check in DynamicValue::Reader::as + switch (value.which()) { + case JsonValue::NUMBER: + setFn(value.getNumber()); + break; + case JsonValue::STRING: + setFn(value.getString().parseAs()); + break; + default: + KJ_FAIL_REQUIRE("Expected integer value"); + } + break; + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + switch (value.which()) { + case JsonValue::NULL_: + setFn(kj::nan()); + break; + case JsonValue::NUMBER: + setFn(value.getNumber()); + break; + case JsonValue::STRING: + setFn(value.getString().parseAs()); + break; + default: + KJ_FAIL_REQUIRE("Expected float value"); + } + break; + case schema::Type::TEXT: + switch (value.which()) { + case JsonValue::STRING: + setFn(value.getString()); + break; + default: + KJ_FAIL_REQUIRE("Expected text value"); + } + break; + case schema::Type::DATA: + switch (value.which()) { + case JsonValue::ARRAY: { + auto array = value.getArray(); + kj::Vector data(array.size()); + for (auto arrayObject : array) { + auto x = arrayObject.getNumber(); + KJ_REQUIRE(byte(x) == x, "Number in byte array is not an integer in [0, 255]"); + data.add(byte(x)); + } + setFn(Data::Reader(data.asPtr())); + break; + } + default: + KJ_FAIL_REQUIRE("Expected data value"); + } + break; + case schema::Type::LIST: + switch (value.which()) { + case JsonValue::NULL_: + // nothing to do + break; + case JsonValue::ARRAY: + decodeArrayFn(value.getArray()); + break; + default: + KJ_FAIL_REQUIRE("Expected list value"); + } + break; + case schema::Type::ENUM: + switch (value.which()) { + case JsonValue::STRING: + setFn(value.getString()); + break; + default: + KJ_FAIL_REQUIRE("Expected enum value"); + } + break; + case schema::Type::STRUCT: + switch (value.which()) { + case JsonValue::NULL_: + // nothing to do + break; + case JsonValue::OBJECT: + decodeObjectFn(value.getObject()); + break; + default: + KJ_FAIL_REQUIRE("Expected object value"); + } + break; + case schema::Type::INTERFACE: + KJ_FAIL_REQUIRE("don't know how to JSON-decode capabilities; " + "JsonCodec::Handler not implemented yet :("); + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("don't know how to JSON-decode AnyPointer; " + "JsonCodec::Handler not implemented yet :("); + } +} +} // namespace + +void JsonCodec::decodeArray(List::Reader input, DynamicList::Builder output) const { + KJ_ASSERT(input.size() == output.size(), "Builder was not initialized to input size"); + auto type = output.getSchema().getElementType(); + for (auto i = 0; i < input.size(); i++) { + decodeField(type, input[i], + [&](DynamicValue::Reader value) { output.set(i, value); }, + [&](List::Reader array) { + decodeArray(array, output.init(i, array.size()).as()); + }, + [&](List::Reader object) { + decodeObject(object, output[i].as()); + }); + } +} + +void JsonCodec::decodeObject(List::Reader input, DynamicStruct::Builder output) + const { + for (auto field : input) { + KJ_IF_MAYBE(fieldSchema, output.getSchema().findFieldByName(field.getName())) { + decodeField((*fieldSchema).getType(), field.getValue(), + [&](DynamicValue::Reader value) { output.set(*fieldSchema, value); }, + [&](List::Reader array) { + decodeArray(array, output.init(*fieldSchema, array.size()).as()); + }, + [&](List::Reader object) { + decodeObject(object, output.init(*fieldSchema).as()); + }); + } else { + // Unknown json fields are ignored to allow schema evolution + } + } +} + +void JsonCodec::decode(JsonValue::Reader input, DynamicStruct::Builder output) const { + // TODO(0.7): type and field handlers + switch (input.which()) { + case JsonValue::OBJECT: + decodeObject(input.getObject(), output); + break; + default: + KJ_FAIL_REQUIRE("Top level json value must be object"); + }; +} + +Orphan JsonCodec::decode( + JsonValue::Reader input, Type type, Orphanage orphanage) const { + // TODO(0.7) + KJ_FAIL_ASSERT("JSON decode into orphanage not implement yet. :("); +} + +// ----------------------------------------------------------------------------- + +namespace { + +class Input { +public: + Input(kj::ArrayPtr input) : wrapped(input) {} + + bool exhausted() { + return wrapped.size() == 0 || wrapped.front() == '\0'; + } + + char nextChar() { + KJ_REQUIRE(!exhausted(), "JSON message ends prematurely."); + return wrapped.front(); + } + + void advance(size_t numBytes = 1) { + KJ_REQUIRE(numBytes <= wrapped.size(), "JSON message ends prematurely."); + wrapped = kj::arrayPtr(wrapped.begin() + numBytes, wrapped.end()); + } + + void advanceTo(const char *newPos) { + KJ_REQUIRE(wrapped.begin() <= newPos && newPos < wrapped.end(), + "JSON message ends prematurely."); + wrapped = kj::arrayPtr(newPos, wrapped.end()); + } + + kj::ArrayPtr consume(size_t numBytes = 1) { + auto originalPos = wrapped.begin(); + advance(numBytes); + + return kj::arrayPtr(originalPos, wrapped.begin()); + } + + void consume(char expected) { + char current = nextChar(); + KJ_REQUIRE(current == expected, "Unexpected input in JSON message."); + + advance(); + } + + void consume(kj::ArrayPtr expected) { + KJ_REQUIRE(wrapped.size() >= expected.size()); + + auto prefix = wrapped.slice(0, expected.size()); + KJ_REQUIRE(prefix == expected, "Unexpected input in JSON message."); + + advance(expected.size()); + } + + bool tryConsume(char expected) { + bool found = !exhausted() && nextChar() == expected; + if (found) { advance(); } + + return found; + } + + template + void consumeOne(Predicate&& predicate) { + char current = nextChar(); + KJ_REQUIRE(predicate(current), "Unexpected input in JSON message."); + + advance(); + } + + template + kj::ArrayPtr consumeWhile(Predicate&& predicate) { + auto originalPos = wrapped.begin(); + while (!exhausted() && predicate(nextChar())) { advance(); } + + return kj::arrayPtr(originalPos, wrapped.begin()); + } + + template // Function + kj::ArrayPtr consumeCustom(F&& f) { + // Allows consuming in a custom manner without exposing the wrapped ArrayPtr. + auto originalPos = wrapped.begin(); + f(*this); + + return kj::arrayPtr(originalPos, wrapped.begin()); + } + + void consumeWhitespace() { + consumeWhile([](char chr) { + return ( + chr == ' ' || + chr == '\n' || + chr == '\r' || + chr == '\t' + ); + }); + } + + +private: + kj::ArrayPtr wrapped; + +}; // class Input + +class Parser { +public: + Parser(size_t maxNestingDepth, kj::ArrayPtr input) : + maxNestingDepth(maxNestingDepth), input(input), nestingDepth(0) {} + + void parseValue(JsonValue::Builder& output) { + input.consumeWhitespace(); + KJ_DEFER(input.consumeWhitespace()); + + KJ_REQUIRE(!input.exhausted(), "JSON message ends prematurely."); + + switch (input.nextChar()) { + case 'n': input.consume(kj::StringPtr("null")); output.setNull(); break; + case 'f': input.consume(kj::StringPtr("false")); output.setBoolean(false); break; + case 't': input.consume(kj::StringPtr("true")); output.setBoolean(true); break; + case '"': parseString(output); break; + case '[': parseArray(output); break; + case '{': parseObject(output); break; + case '-': case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': case '8': + case '9': parseNumber(output); break; + default: KJ_FAIL_REQUIRE("Unexpected input in JSON message."); + } + } + + void parseNumber(JsonValue::Builder& output) { + auto numberStr = consumeNumber(); + char *endPtr; + + errno = 0; + double value = strtod(numberStr.begin(), &endPtr); + + KJ_ASSERT(endPtr != numberStr.begin(), "strtod should not fail! Is consumeNumber wrong?"); + KJ_REQUIRE((value != HUGE_VAL && value != -HUGE_VAL) || errno != ERANGE, + "Overflow in JSON number."); + KJ_REQUIRE(value != 0.0 || errno != ERANGE, + "Underflow in JSON number."); + + output.setNumber(value); + } + + void parseString(JsonValue::Builder& output) { + output.setString(consumeQuotedString()); + } + + void parseArray(JsonValue::Builder& output) { + // TODO(perf): Using orphans leaves holes in the message. It's expected + // that a JsonValue is used for interop, and won't be sent or written as a + // Cap'n Proto message. This also applies to parseObject below. + kj::Vector> values; + auto orphanage = Orphanage::getForMessageContaining(output); + bool expectComma = false; + + input.consume('['); + KJ_REQUIRE(++nestingDepth <= maxNestingDepth, "JSON message nested too deeply."); + KJ_DEFER(--nestingDepth); + + while (input.consumeWhitespace(), input.nextChar() != ']') { + auto orphan = orphanage.newOrphan(); + auto builder = orphan.get(); + + if (expectComma) { + input.consumeWhitespace(); + input.consume(','); + input.consumeWhitespace(); + } + + parseValue(builder); + values.add(kj::mv(orphan)); + + expectComma = true; + } + + output.initArray(values.size()); + auto array = output.getArray(); + + for (auto i : kj::indices(values)) { + array.adoptWithCaveats(i, kj::mv(values[i])); + } + + input.consume(']'); + } + + void parseObject(JsonValue::Builder& output) { + kj::Vector> fields; + auto orphanage = Orphanage::getForMessageContaining(output); + bool expectComma = false; + + input.consume('{'); + KJ_REQUIRE(++nestingDepth <= maxNestingDepth, "JSON message nested too deeply."); + KJ_DEFER(--nestingDepth); + + while (input.consumeWhitespace(), input.nextChar() != '}') { + auto orphan = orphanage.newOrphan(); + auto builder = orphan.get(); + + if (expectComma) { + input.consumeWhitespace(); + input.consume(','); + input.consumeWhitespace(); + } + + builder.setName(consumeQuotedString()); + + input.consumeWhitespace(); + input.consume(':'); + input.consumeWhitespace(); + + auto valueBuilder = builder.getValue(); + parseValue(valueBuilder); + + fields.add(kj::mv(orphan)); + + expectComma = true; + } + + output.initObject(fields.size()); + auto object = output.getObject(); + + for (auto i : kj::indices(fields)) { + object.adoptWithCaveats(i, kj::mv(fields[i])); + } + + input.consume('}'); + } + + bool inputExhausted() { return input.exhausted(); } + +private: + kj::String consumeQuotedString() { + input.consume('"'); + // TODO(perf): Avoid copy / alloc if no escapes encoutered. + // TODO(perf): Get statistics on string size and preallocate? + kj::Vector decoded; + + do { + auto stringValue = input.consumeWhile([](const char chr) { + return chr != '"' && chr != '\\'; + }); + + decoded.addAll(stringValue); + + if (input.nextChar() == '\\') { // handle escapes. + input.advance(); + switch(input.nextChar()) { + case '"' : decoded.add('"' ); input.advance(); break; + case '\\': decoded.add('\\'); input.advance(); break; + case '/' : decoded.add('/' ); input.advance(); break; + case 'b' : decoded.add('\b'); input.advance(); break; + case 'f' : decoded.add('\f'); input.advance(); break; + case 'n' : decoded.add('\n'); input.advance(); break; + case 'r' : decoded.add('\r'); input.advance(); break; + case 't' : decoded.add('\t'); input.advance(); break; + case 'u' : + input.consume('u'); + unescapeAndAppend(input.consume(size_t(4)), decoded); + break; + default: KJ_FAIL_REQUIRE("Invalid escape in JSON string."); break; + } + } + + } while(input.nextChar() != '"'); + + input.consume('"'); + decoded.add('\0'); + + // TODO(perf): This copy can be eliminated, but I can't find the kj::wayToDoIt(); + return kj::String(decoded.releaseAsArray()); + } + + kj::String consumeNumber() { + auto numArrayPtr = input.consumeCustom([](Input& input) { + input.tryConsume('-'); + if (!input.tryConsume('0')) { + input.consumeOne([](char c) { return '1' <= c && c <= '9'; }); + input.consumeWhile([](char c) { return '0' <= c && c <= '9'; }); + } + + if (input.tryConsume('.')) { + input.consumeWhile([](char c) { return '0' <= c && c <= '9'; }); + } + + if (input.tryConsume('e') || input.tryConsume('E')) { + input.tryConsume('+') || input.tryConsume('-'); + input.consumeWhile([](char c) { return '0' <= c && c <= '9'; }); + } + }); + + KJ_REQUIRE(numArrayPtr.size() > 0, "Expected number in JSON input."); + + kj::Vector number; + number.addAll(numArrayPtr); + number.add('\0'); + + return kj::String(number.releaseAsArray()); + } + + // TODO(someday): This "interface" is ugly, and won't work if/when surrogates are handled. + void unescapeAndAppend(kj::ArrayPtr hex, kj::Vector& target) { + KJ_REQUIRE(hex.size() == 4); + int codePoint = 0; + + for (int i = 0; i < 4; ++i) { + char c = hex[i]; + codePoint <<= 4; + + if ('0' <= c && c <= '9') { + codePoint |= c - '0'; + } else if ('a' <= c && c <= 'f') { + codePoint |= c - 'a'; + } else if ('A' <= c && c <= 'F') { + codePoint |= c - 'A'; + } else { + KJ_FAIL_REQUIRE("Invalid hex digit in unicode escape.", c); + } + } + + // TODO(0.7): Support at least basic multi-lingual plane, ie ignore surrogates. + KJ_REQUIRE(codePoint < 128, "non-ASCII unicode escapes are not supported (yet!)"); + target.add(0x7f & static_cast(codePoint)); + } + + const size_t maxNestingDepth; + Input input; + size_t nestingDepth; + + +}; // class Parser + +} // namespace + + +void JsonCodec::decodeRaw(kj::ArrayPtr input, JsonValue::Builder output) const { + Parser parser(impl->maxNestingDepth, input); + parser.parseValue(output); + + KJ_REQUIRE(parser.inputExhausted(), "Input remains after parsing JSON."); +} + +// ----------------------------------------------------------------------------- + +Orphan JsonCodec::HandlerBase::decodeBase( + const JsonCodec& codec, JsonValue::Reader input, Type type, Orphanage orphanage) const { + KJ_FAIL_ASSERT("JSON decoder handler type / value type mismatch"); +} +void JsonCodec::HandlerBase::decodeStructBase( + const JsonCodec& codec, JsonValue::Reader input, DynamicStruct::Builder output) const { + KJ_FAIL_ASSERT("JSON decoder handler type / value type mismatch"); +} + +void JsonCodec::addTypeHandlerImpl(Type type, HandlerBase& handler) { + impl->typeHandlers[type] = &handler; +} + +void JsonCodec::addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler) { + KJ_REQUIRE(type == field.getType(), + "handler type did not match field type for addFieldHandler()"); + impl->fieldHandlers[field] = &handler; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,58 @@ +# Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0x8ef99297a43a5e34; + +$import "/capnp/c++.capnp".namespace("capnp"); + +struct JsonValue { + union { + null @0 :Void; + boolean @1 :Bool; + number @2 :Float64; + string @3 :Text; + array @4 :List(JsonValue); + object @5 :List(Field); + # Standard JSON values. + + call @6 :Call; + # Non-standard: A "function call", applying a named function (named by a single identifier) + # to a parameter list. Examples: + # + # BinData(0, "Zm9vCg==") + # ISODate("2015-04-15T08:44:50.218Z") + # + # Mongo DB users will recognize the above as exactly the syntax Mongo uses to represent BSON + # "binary" and "date" types in text, since JSON has no analog of these. This is basically the + # reason this extension exists. We do NOT recommend using `call` unless you specifically need + # to be compatible with some silly format that uses this syntax. + } + + struct Field { + name @0 :Text; + value @1 :JsonValue; + } + + struct Call { + function @0 :Text; + params @1 :List(JsonValue); + } +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,326 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: json.capnp + +#include "json.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<138> b_8825ffaa852cda72 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 24, 0, 0, 0, 1, 0, 2, 0, + 52, 94, 58, 164, 151, 146, 249, 142, + 1, 0, 7, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 37, 0, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 143, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 97, 116, 47, 106, 115, 111, + 110, 46, 99, 97, 112, 110, 112, 58, + 74, 115, 111, 110, 86, 97, 108, 117, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 204, 55, 169, 83, 216, 85, 120, 194, + 9, 0, 0, 0, 50, 0, 0, 0, + 96, 187, 212, 61, 21, 132, 191, 155, + 5, 0, 0, 0, 42, 0, 0, 0, + 70, 105, 101, 108, 100, 0, 0, 0, + 67, 97, 108, 108, 0, 0, 0, 0, + 28, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 0, 0, 0, 3, 0, 1, 0, + 188, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 16, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 0, 0, 0, 3, 0, 1, 0, + 192, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 0, 0, 0, 3, 0, 1, 0, + 196, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 188, 0, 0, 0, 3, 0, 1, 0, + 200, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 3, 0, 1, 0, + 220, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 217, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 212, 0, 0, 0, 3, 0, 1, 0, + 240, 0, 0, 0, 2, 0, 1, 0, + 6, 0, 249, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 237, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 232, 0, 0, 0, 3, 0, 1, 0, + 244, 0, 0, 0, 2, 0, 1, 0, + 110, 117, 108, 108, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 111, 111, 108, 101, 97, 110, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 117, 109, 98, 101, 114, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 105, 110, 103, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 114, 114, 97, 121, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 98, 106, 101, 99, 116, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 204, 55, 169, 83, 216, 85, 120, 194, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 108, 108, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 187, 212, 61, 21, 132, 191, 155, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_8825ffaa852cda72 = b_8825ffaa852cda72.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_8825ffaa852cda72[] = { + &s_8825ffaa852cda72, + &s_9bbf84153dd4bb60, + &s_c27855d853a937cc, +}; +static const uint16_t m_8825ffaa852cda72[] = {4, 1, 6, 0, 2, 5, 3}; +static const uint16_t i_8825ffaa852cda72[] = {0, 1, 2, 3, 4, 5, 6}; +const ::capnp::_::RawSchema s_8825ffaa852cda72 = { + 0x8825ffaa852cda72, b_8825ffaa852cda72.words, 138, d_8825ffaa852cda72, m_8825ffaa852cda72, + 3, 7, i_8825ffaa852cda72, nullptr, nullptr, { &s_8825ffaa852cda72, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_c27855d853a937cc = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 204, 55, 169, 83, 216, 85, 120, 194, + 34, 0, 0, 0, 1, 0, 0, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 97, 116, 47, 106, 115, 111, + 110, 46, 99, 97, 112, 110, 112, 58, + 74, 115, 111, 110, 86, 97, 108, 117, + 101, 46, 70, 105, 101, 108, 100, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c27855d853a937cc = b_c27855d853a937cc.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c27855d853a937cc[] = { + &s_8825ffaa852cda72, +}; +static const uint16_t m_c27855d853a937cc[] = {0, 1}; +static const uint16_t i_c27855d853a937cc[] = {0, 1}; +const ::capnp::_::RawSchema s_c27855d853a937cc = { + 0xc27855d853a937cc, b_c27855d853a937cc.words, 49, d_c27855d853a937cc, m_c27855d853a937cc, + 1, 2, i_c27855d853a937cc, nullptr, nullptr, { &s_c27855d853a937cc, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<54> b_9bbf84153dd4bb60 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 96, 187, 212, 61, 21, 132, 191, 155, + 34, 0, 0, 0, 1, 0, 0, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 58, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 97, 116, 47, 106, 115, 111, + 110, 46, 99, 97, 112, 110, 112, 58, + 74, 115, 111, 110, 86, 97, 108, 117, + 101, 46, 67, 97, 108, 108, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 72, 0, 0, 0, 2, 0, 1, 0, + 102, 117, 110, 99, 116, 105, 111, 110, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 114, 218, 44, 133, 170, 255, 37, 136, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9bbf84153dd4bb60 = b_9bbf84153dd4bb60.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9bbf84153dd4bb60[] = { + &s_8825ffaa852cda72, +}; +static const uint16_t m_9bbf84153dd4bb60[] = {0, 1}; +static const uint16_t i_9bbf84153dd4bb60[] = {0, 1}; +const ::capnp::_::RawSchema s_9bbf84153dd4bb60 = { + 0x9bbf84153dd4bb60, b_9bbf84153dd4bb60.words, 54, d_9bbf84153dd4bb60, m_9bbf84153dd4bb60, + 1, 2, i_9bbf84153dd4bb60, nullptr, nullptr, { &s_9bbf84153dd4bb60, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { + +// JsonValue +constexpr uint16_t JsonValue::_capnpPrivate::dataWordSize; +constexpr uint16_t JsonValue::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind JsonValue::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* JsonValue::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// JsonValue::Field +constexpr uint16_t JsonValue::Field::_capnpPrivate::dataWordSize; +constexpr uint16_t JsonValue::Field::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind JsonValue::Field::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* JsonValue::Field::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// JsonValue::Call +constexpr uint16_t JsonValue::Call::_capnpPrivate::dataWordSize; +constexpr uint16_t JsonValue::Call::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind JsonValue::Call::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* JsonValue::Call::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,860 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: json.capnp + +#ifndef CAPNP_INCLUDED_8ef99297a43a5e34_ +#define CAPNP_INCLUDED_8ef99297a43a5e34_ + +#include +#if !CAPNP_LITE +#include +#endif // !CAPNP_LITE + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(8825ffaa852cda72); +CAPNP_DECLARE_SCHEMA(c27855d853a937cc); +CAPNP_DECLARE_SCHEMA(9bbf84153dd4bb60); + +} // namespace schemas +} // namespace capnp + +namespace capnp { + +struct JsonValue { + JsonValue() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NULL_, + BOOLEAN, + NUMBER, + STRING, + ARRAY, + OBJECT, + CALL, + }; + struct Field; + struct Call; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8825ffaa852cda72, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JsonValue::Field { + Field() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c27855d853a937cc, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JsonValue::Call { + Call() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9bbf84153dd4bb60, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class JsonValue::Reader { +public: + typedef JsonValue Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNull() const; + inline ::capnp::Void getNull() const; + + inline bool isBoolean() const; + inline bool getBoolean() const; + + inline bool isNumber() const; + inline double getNumber() const; + + inline bool isString() const; + inline bool hasString() const; + inline ::capnp::Text::Reader getString() const; + + inline bool isArray() const; + inline bool hasArray() const; + inline ::capnp::List< ::capnp::JsonValue>::Reader getArray() const; + + inline bool isObject() const; + inline bool hasObject() const; + inline ::capnp::List< ::capnp::JsonValue::Field>::Reader getObject() const; + + inline bool isCall() const; + inline bool hasCall() const; + inline ::capnp::JsonValue::Call::Reader getCall() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Builder { +public: + typedef JsonValue Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNull(); + inline ::capnp::Void getNull(); + inline void setNull( ::capnp::Void value = ::capnp::VOID); + + inline bool isBoolean(); + inline bool getBoolean(); + inline void setBoolean(bool value); + + inline bool isNumber(); + inline double getNumber(); + inline void setNumber(double value); + + inline bool isString(); + inline bool hasString(); + inline ::capnp::Text::Builder getString(); + inline void setString( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initString(unsigned int size); + inline void adoptString(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownString(); + + inline bool isArray(); + inline bool hasArray(); + inline ::capnp::List< ::capnp::JsonValue>::Builder getArray(); + inline void setArray( ::capnp::List< ::capnp::JsonValue>::Reader value); + inline ::capnp::List< ::capnp::JsonValue>::Builder initArray(unsigned int size); + inline void adoptArray(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownArray(); + + inline bool isObject(); + inline bool hasObject(); + inline ::capnp::List< ::capnp::JsonValue::Field>::Builder getObject(); + inline void setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value); + inline ::capnp::List< ::capnp::JsonValue::Field>::Builder initObject(unsigned int size); + inline void adoptObject(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> disownObject(); + + inline bool isCall(); + inline bool hasCall(); + inline ::capnp::JsonValue::Call::Builder getCall(); + inline void setCall( ::capnp::JsonValue::Call::Reader value); + inline ::capnp::JsonValue::Call::Builder initCall(); + inline void adoptCall(::capnp::Orphan< ::capnp::JsonValue::Call>&& value); + inline ::capnp::Orphan< ::capnp::JsonValue::Call> disownCall(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Pipeline { +public: + typedef JsonValue Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JsonValue::Field::Reader { +public: + typedef Field Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline bool hasValue() const; + inline ::capnp::JsonValue::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Field::Builder { +public: + typedef Field Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline bool hasValue(); + inline ::capnp::JsonValue::Builder getValue(); + inline void setValue( ::capnp::JsonValue::Reader value); + inline ::capnp::JsonValue::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::JsonValue>&& value); + inline ::capnp::Orphan< ::capnp::JsonValue> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Field::Pipeline { +public: + typedef Field Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::JsonValue::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JsonValue::Call::Reader { +public: + typedef Call Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasFunction() const; + inline ::capnp::Text::Reader getFunction() const; + + inline bool hasParams() const; + inline ::capnp::List< ::capnp::JsonValue>::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JsonValue::Call::Builder { +public: + typedef Call Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasFunction(); + inline ::capnp::Text::Builder getFunction(); + inline void setFunction( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initFunction(unsigned int size); + inline void adoptFunction(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownFunction(); + + inline bool hasParams(); + inline ::capnp::List< ::capnp::JsonValue>::Builder getParams(); + inline void setParams( ::capnp::List< ::capnp::JsonValue>::Reader value); + inline ::capnp::List< ::capnp::JsonValue>::Builder initParams(unsigned int size); + inline void adoptParams(::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JsonValue::Call::Pipeline { +public: + typedef Call Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::JsonValue::Which JsonValue::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::JsonValue::Which JsonValue::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool JsonValue::Reader::isNull() const { + return which() == JsonValue::NULL_; +} +inline bool JsonValue::Builder::isNull() { + return which() == JsonValue::NULL_; +} +inline ::capnp::Void JsonValue::Reader::getNull() const { + KJ_IREQUIRE((which() == JsonValue::NULL_), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void JsonValue::Builder::getNull() { + KJ_IREQUIRE((which() == JsonValue::NULL_), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setNull( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NULL_); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isBoolean() const { + return which() == JsonValue::BOOLEAN; +} +inline bool JsonValue::Builder::isBoolean() { + return which() == JsonValue::BOOLEAN; +} +inline bool JsonValue::Reader::getBoolean() const { + KJ_IREQUIRE((which() == JsonValue::BOOLEAN), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} + +inline bool JsonValue::Builder::getBoolean() { + KJ_IREQUIRE((which() == JsonValue::BOOLEAN), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setBoolean(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::BOOLEAN); + _builder.setDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isNumber() const { + return which() == JsonValue::NUMBER; +} +inline bool JsonValue::Builder::isNumber() { + return which() == JsonValue::NUMBER; +} +inline double JsonValue::Reader::getNumber() const { + KJ_IREQUIRE((which() == JsonValue::NUMBER), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double JsonValue::Builder::getNumber() { + KJ_IREQUIRE((which() == JsonValue::NUMBER), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void JsonValue::Builder::setNumber(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::NUMBER); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool JsonValue::Reader::isString() const { + return which() == JsonValue::STRING; +} +inline bool JsonValue::Builder::isString() { + return which() == JsonValue::STRING; +} +inline bool JsonValue::Reader::hasString() const { + if (which() != JsonValue::STRING) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasString() { + if (which() != JsonValue::STRING) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Reader::getString() const { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Builder::getString() { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setString( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Builder::initString(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptString( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Builder::disownString() { + KJ_IREQUIRE((which() == JsonValue::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isArray() const { + return which() == JsonValue::ARRAY; +} +inline bool JsonValue::Builder::isArray() { + return which() == JsonValue::ARRAY; +} +inline bool JsonValue::Reader::hasArray() const { + if (which() != JsonValue::ARRAY) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasArray() { + if (which() != JsonValue::ARRAY) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Reader::getArray() const { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::getArray() { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setArray( ::capnp::List< ::capnp::JsonValue>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Builder::initArray(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptArray( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::ARRAY); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Builder::disownArray() { + KJ_IREQUIRE((which() == JsonValue::ARRAY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isObject() const { + return which() == JsonValue::OBJECT; +} +inline bool JsonValue::Builder::isObject() { + return which() == JsonValue::OBJECT; +} +inline bool JsonValue::Reader::hasObject() const { + if (which() != JsonValue::OBJECT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasObject() { + if (which() != JsonValue::OBJECT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Reader JsonValue::Reader::getObject() const { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::getObject() { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setObject( ::capnp::List< ::capnp::JsonValue::Field>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue::Field>::Builder JsonValue::Builder::initObject(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Builder::adoptObject( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::OBJECT); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue::Field>> JsonValue::Builder::disownObject() { + KJ_IREQUIRE((which() == JsonValue::OBJECT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue::Field>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Reader::isCall() const { + return which() == JsonValue::CALL; +} +inline bool JsonValue::Builder::isCall() { + return which() == JsonValue::CALL; +} +inline bool JsonValue::Reader::hasCall() const { + if (which() != JsonValue::CALL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Builder::hasCall() { + if (which() != JsonValue::CALL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::JsonValue::Call::Reader JsonValue::Reader::getCall() const { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::getCall() { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::setCall( ::capnp::JsonValue::Call::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::JsonValue::Call::Builder JsonValue::Builder::initCall() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Builder::adoptCall( + ::capnp::Orphan< ::capnp::JsonValue::Call>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, JsonValue::CALL); + ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::JsonValue::Call> JsonValue::Builder::disownCall() { + KJ_IREQUIRE((which() == JsonValue::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::JsonValue::Call>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Field::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Field::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Field::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Field::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Field::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Field::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Field::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Field::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Field::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Field::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::JsonValue::Reader JsonValue::Field::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::JsonValue::Pipeline JsonValue::Field::Pipeline::getValue() { + return ::capnp::JsonValue::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void JsonValue::Field::Builder::setValue( ::capnp::JsonValue::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::JsonValue>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::JsonValue::Builder JsonValue::Field::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void JsonValue::Field::Builder::adoptValue( + ::capnp::Orphan< ::capnp::JsonValue>&& value) { + ::capnp::_::PointerHelpers< ::capnp::JsonValue>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::JsonValue> JsonValue::Field::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::JsonValue>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Call::Reader::hasFunction() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Call::Builder::hasFunction() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader JsonValue::Call::Reader::getFunction() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder JsonValue::Call::Builder::getFunction() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void JsonValue::Call::Builder::setFunction( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder JsonValue::Call::Builder::initFunction(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Call::Builder::adoptFunction( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> JsonValue::Call::Builder::disownFunction() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool JsonValue::Call::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool JsonValue::Call::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::JsonValue>::Reader JsonValue::Call::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void JsonValue::Call::Builder::setParams( ::capnp::List< ::capnp::JsonValue>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::JsonValue>::Builder JsonValue::Call::Builder::initParams(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void JsonValue::Call::Builder::adoptParams( + ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::JsonValue>> JsonValue::Call::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::JsonValue>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +} // namespace + +#endif // CAPNP_INCLUDED_8ef99297a43a5e34_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compat/json.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compat/json.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,462 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPAT_JSON_H_ +#define CAPNP_COMPAT_JSON_H_ + +#include +#include +#include + +namespace capnp { + +class JsonCodec { + // Flexible class for encoding Cap'n Proto types as JSON, and decoding JSON back to Cap'n Proto. + // + // Typical usage: + // + // JsonCodec json; + // + // // encode + // kj::String encoded = json.encode(someStructReader); + // + // // decode + // json.decode(encoded, someStructBuilder); + // + // Advanced users can do fancy things like override the way certain types or fields are + // represented in JSON by registering handlers. See the unit test for an example. + // + // Notes: + // - When encoding, all primitive fields are always encoded, even if default-valued. Pointer + // fields are only encoded if they are non-null. + // - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating + // points which cannot store a 64-bit integer without losing data. + // - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded + // as null. This matches the behavior of `JSON.stringify` in at least Firefox and Chrome. + // - Data is encoded as an array of numbers in the range [0,255]. You probably want to register + // a handler that does something better, like maybe base64 encoding, but there are a zillion + // different ways people do this. + // - Encoding/decoding capabilities and AnyPointers requires registering a Handler, since there's + // no obvious default behavior. + // - When decoding, unrecognized field names are ignored. Note: This means that JSON is NOT a + // good format for receiving input from a human. Consider `capnp eval` or the SchemaParser + // library for human input. + +public: + JsonCodec(); + ~JsonCodec() noexcept(false); + + // --------------------------------------------------------------------------- + // standard API + + void setPrettyPrint(bool enabled); + // Enable to insert newlines, indentation, and other extra spacing into the output. The default + // is to use minimal whitespace. + + void setMaxNestingDepth(size_t maxNestingDepth); + // Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing + // the call stack. The default is 64. + + template + kj::String encode(T&& value); + // Encode any Cap'n Proto value to JSON, including primitives and + // Dynamic{Enum,Struct,List,Capability}, but not DynamicValue (see below). + + kj::String encode(DynamicValue::Reader value, Type type) const; + // Encode a DynamicValue to JSON. `type` is needed because `DynamicValue` itself does + // not distinguish between e.g. int32 and int64, which in JSON are handled differently. Most + // of the time, though, you can use the single-argument templated version of `encode()` instead. + + void decode(kj::ArrayPtr input, DynamicStruct::Builder output) const; + // Decode JSON text directly into a struct builder. This only works for structs since lists + // need to be allocated with the correct size in advance. + // + // (Remember that any Cap'n Proto struct reader type can be implicitly cast to + // DynamicStruct::Reader.) + + template + Orphan decode(kj::ArrayPtr input, Orphanage orphanage) const; + // Decode JSON text to any Cap'n Proto object (pointer value), allocated using the given + // orphanage. T must be specified explicitly and cannot be dynamic, e.g.: + // + // Orphan orphan = json.decode(text, orphanage); + + template + ReaderFor decode(kj::ArrayPtr input) const; + // Decode JSON text into a primitive or capability value. T must be specified explicitly and + // cannot be dynamic, e.g.: + // + // uint32_t n = json.decode(text); + + Orphan decode(kj::ArrayPtr input, Type type, Orphanage orphanage) const; + Orphan decode( + kj::ArrayPtr input, ListSchema type, Orphanage orphanage) const; + Orphan decode( + kj::ArrayPtr input, StructSchema type, Orphanage orphanage) const; + DynamicCapability::Client decode(kj::ArrayPtr input, InterfaceSchema type) const; + DynamicEnum decode(kj::ArrayPtr input, EnumSchema type) const; + // Decode to a dynamic value, specifying the type schema. + + // --------------------------------------------------------------------------- + // layered API + // + // You can separate text <-> JsonValue from JsonValue <-> T. These are particularly useful + // for calling from Handler implementations. + + kj::String encodeRaw(JsonValue::Reader value) const; + void decodeRaw(kj::ArrayPtr input, JsonValue::Builder output) const; + // Translate JsonValue <-> text. + + template + void encode(T&& value, JsonValue::Builder output); + void encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const; + void decode(JsonValue::Reader input, DynamicStruct::Builder output) const; + template + Orphan decode(JsonValue::Reader input, Orphanage orphanage) const; + template + ReaderFor decode(JsonValue::Reader input) const; + + Orphan decode(JsonValue::Reader input, Type type, Orphanage orphanage) const; + Orphan decode(JsonValue::Reader input, ListSchema type, Orphanage orphanage) const; + Orphan decode( + JsonValue::Reader input, StructSchema type, Orphanage orphanage) const; + DynamicCapability::Client decode(JsonValue::Reader input, InterfaceSchema type) const; + DynamicEnum decode(JsonValue::Reader input, EnumSchema type) const; + + // --------------------------------------------------------------------------- + // specializing particular types + + template ()> + class Handler; + // Implement this interface to specify a special encoding for a particular type or field. + // + // The templates are a bit ugly, but subclasses of this type essentially implement two methods, + // one to encode values of this type and one to decode values of this type. `encode()` is simple: + // + // void encode(const JsonCodec& codec, ReaderFor input, JsonValue::Builder output) const; + // + // `decode()` is a bit trickier. When T is a struct (including DynamicStruct), it is: + // + // void decode(const JsonCodec& codec, JsonValue::Reader input, BuilderFor output) const; + // + // However, when T is a primitive, decode() is: + // + // T decode(const JsonCodec& codec, JsonValue::Reader input) const; + // + // Or when T is any non-struct object (list, blob), decode() is: + // + // Orphan decode(const JsonCodec& codec, JsonValue::Reader input, Orphanage orphanage) const; + // + // Or when T is an interface: + // + // T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const; + // + // Additionally, when T is a struct you can *optionally* also implement the orphan-returning form + // of decode(), but it will only be called when the struct would be allocated as an individual + // object, not as part of a list. This allows you to return "nullptr" in these cases to say that + // the pointer value should be null. This does not apply to list elements because struct list + // elements cannot ever be null (since Cap'n Proto encodes struct lists as a flat list rather + // than list-of-pointers). + + template + void addTypeHandler(Handler& handler); + void addTypeHandler(Type type, Handler& handler); + void addTypeHandler(EnumSchema type, Handler& handler); + void addTypeHandler(StructSchema type, Handler& handler); + void addTypeHandler(ListSchema type, Handler& handler); + void addTypeHandler(InterfaceSchema type, Handler& handler); + // Arrange that whenever the type T appears in the message, your handler will be used to + // encode/decode it. + // + // Note that if you register a handler for a capability type, it will also apply to subtypes. + // Thus Handler handles all capabilities. + + template + void addFieldHandler(StructSchema::Field field, Handler& handler); + // Matches only the specific field. T can be a dynamic type. T must match the field's type. + +private: + class HandlerBase; + struct Impl; + + kj::Own impl; + + void encodeField(StructSchema::Field field, DynamicValue::Reader input, + JsonValue::Builder output) const; + void decodeArray(List::Reader input, DynamicList::Builder output) const; + void decodeObject(List::Reader input, DynamicStruct::Builder output) const; + void addTypeHandlerImpl(Type type, HandlerBase& handler); + void addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler); +}; + +// ======================================================================================= +// inline implementation details + +template +kj::String JsonCodec::encode(T&& value) { + typedef FromAny> Base; + return encode(DynamicValue::Reader(ReaderFor(kj::fwd(value))), Type::from()); +} + +template +inline Orphan JsonCodec::decode(kj::ArrayPtr input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +template +inline ReaderFor JsonCodec::decode(kj::ArrayPtr input) const { + static_assert(style() == Style::PRIMITIVE || style() == Style::CAPABILITY, + "must specify an orphanage to decode an object type"); + return decode(input, Type::from(), Orphanage()).getReader().template as(); +} + +inline Orphan JsonCodec::decode( + kj::ArrayPtr input, ListSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline Orphan JsonCodec::decode( + kj::ArrayPtr input, StructSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline DynamicCapability::Client JsonCodec::decode( + kj::ArrayPtr input, InterfaceSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} +inline DynamicEnum JsonCodec::decode(kj::ArrayPtr input, EnumSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} + +// ----------------------------------------------------------------------------- + +template +void JsonCodec::encode(T&& value, JsonValue::Builder output) { + typedef FromAny> Base; + encode(DynamicValue::Reader(ReaderFor(kj::fwd(value))), Type::from(), output); +} + +template +inline Orphan JsonCodec::decode(JsonValue::Reader input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +template +inline ReaderFor JsonCodec::decode(JsonValue::Reader input) const { + static_assert(style() == Style::PRIMITIVE || style() == Style::CAPABILITY, + "must specify an orphanage to decode an object type"); + return decode(input, Type::from(), Orphanage()).getReader().template as(); +} + +inline Orphan JsonCodec::decode( + JsonValue::Reader input, ListSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline Orphan JsonCodec::decode( + JsonValue::Reader input, StructSchema type, Orphanage orphanage) const { + return decode(input, Type(type), orphanage).releaseAs(); +} +inline DynamicCapability::Client JsonCodec::decode( + JsonValue::Reader input, InterfaceSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} +inline DynamicEnum JsonCodec::decode(JsonValue::Reader input, EnumSchema type) const { + return decode(input, Type(type), Orphanage()).getReader().as(); +} + +// ----------------------------------------------------------------------------- + +class JsonCodec::HandlerBase { + // Internal helper; ignore. +public: + virtual void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const = 0; + virtual Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const; + virtual void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, ReaderFor input, + JsonValue::Builder output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + Orphanage orphanage) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, orphanage); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, ReaderFor input, + JsonValue::Builder output) const = 0; + virtual void decode(const JsonCodec& codec, JsonValue::Reader input, + BuilderFor output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + Orphanage orphanage) const { + // If subclass does not override, fall back to regular version. + auto result = orphanage.newOrphan(); + decode(codec, input, result.get()); + return result; + } + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, orphanage); + } + void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const override final { + decode(codec, input, output.as()); + } + friend class JsonCodec; +}; + +template <> +class JsonCodec::Handler: private JsonCodec::HandlerBase { + // Almost identical to Style::STRUCT except that we pass the struct type to decode(). + +public: + virtual void encode(const JsonCodec& codec, DynamicStruct::Reader input, + JsonValue::Builder output) const = 0; + virtual void decode(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const = 0; + virtual Orphan decode(const JsonCodec& codec, JsonValue::Reader input, + StructSchema type, Orphanage orphanage) const { + // If subclass does not override, fall back to regular version. + auto result = orphanage.newOrphan(type); + decode(codec, input, result.get()); + return result; + } + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input, type.asStruct(), orphanage); + } + void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input, + DynamicStruct::Builder output) const override final { + decode(codec, input, output.as()); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, T input, JsonValue::Builder output) const = 0; + virtual T decode(const JsonCodec& codec, JsonValue::Reader input) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return decode(codec, input); + } + friend class JsonCodec; +}; + +template +class JsonCodec::Handler: private JsonCodec::HandlerBase { +public: + virtual void encode(const JsonCodec& codec, typename T::Client input, + JsonValue::Builder output) const = 0; + virtual typename T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const = 0; + +private: + void encodeBase(const JsonCodec& codec, DynamicValue::Reader input, + JsonValue::Builder output) const override final { + encode(codec, input.as(), output); + } + Orphan decodeBase(const JsonCodec& codec, JsonValue::Reader input, + Type type, Orphanage orphanage) const override final { + return orphanage.newOrphanCopy(decode(codec, input)); + } + friend class JsonCodec; +}; + +template +inline void JsonCodec::addTypeHandler(Handler& handler) { + addTypeHandlerImpl(Type::from(), handler); +} +inline void JsonCodec::addTypeHandler(Type type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(EnumSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(StructSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(ListSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} +inline void JsonCodec::addTypeHandler(InterfaceSchema type, Handler& handler) { + addTypeHandlerImpl(type, handler); +} + +template +inline void JsonCodec::addFieldHandler(StructSchema::Field field, Handler& handler) { + addFieldHandlerImpl(field, Type::from(), handler); +} + +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +template <> void JsonCodec::addTypeHandler(Handler& handler) + KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; " + "try specifying a specific type schema as the first parameter"); +// TODO(someday): Implement support for registering handlers that cover thinsg like "all structs" +// or "all lists". Currently you can only target a specific struct or list type. + +} // namespace capnp + +#endif // CAPNP_COMPAT_JSON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnp-test.ekam-rule --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnp-test.ekam-rule Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,52 @@ +#! /bin/sh + +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a one-off test rule. + +set -eu + +echo findProvider file:capnp +read CAPNP +export CAPNP + +echo findProvider file:capnp/compiler/capnp-test.sh +read CAPNP_TEST + +# Register our interest in the testdata files. +echo findProvider file:capnp/testdata/binary; read JUNK +echo findProvider file:capnp/testdata/flat; read JUNK +echo findProvider file:capnp/testdata/packed; read JUNK +echo findProvider file:capnp/testdata/segmented; read JUNK +echo findProvider file:capnp/testdata/segmented-packed; read JUNK +echo findProvider file:capnp/testdata/pretty.txt; read JUNK +echo findProvider file:capnp/testdata/short.txt; read JUNK +echo findProvider file:capnp/testdata/errors.capnp.nobuild; read JUNK +echo findProvider file:capnp/testdata/errors.txt; read JUNK + +# Register our interest in the schema files. +echo findProvider file:capnp/c++.capnp +echo findProvider file:capnp/test.capnp + +$CAPNP_TEST >&2 + +echo passed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnp-test.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnp-test.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,71 @@ +#! /bin/sh +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Tests the `capnp` tool's various commands, other than `compile`. + +set -eu + +fail() { + echo "FAILED: $@" >&2 + exit 1 +} + +if test -f ./capnp; then + CAPNP=${CAPNP:-./capnp} +elif test -f ./capnp.exe; then + CAPNP=${CAPNP:-./capnp.exe} +else + CAPNP=${CAPNP:-capnp} +fi + +SCHEMA=`dirname "$0"`/../test.capnp +TESTDATA=`dirname "$0"`/../testdata + +$CAPNP encode $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/binary - || fail encode +$CAPNP encode --flat $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/flat - || fail encode flat +$CAPNP encode --packed $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/packed - || fail encode packed +$CAPNP encode --packed --flat $SCHEMA TestAllTypes < $TESTDATA/short.txt | cmp $TESTDATA/packedflat - || fail encode packedflat +$CAPNP encode $SCHEMA TestAllTypes < $TESTDATA/pretty.txt | cmp $TESTDATA/binary - || fail parse pretty + +$CAPNP decode $SCHEMA TestAllTypes < $TESTDATA/binary | cmp $TESTDATA/pretty.txt - || fail decode +$CAPNP decode --flat $SCHEMA TestAllTypes < $TESTDATA/flat | cmp $TESTDATA/pretty.txt - || fail decode flat +$CAPNP decode --packed $SCHEMA TestAllTypes < $TESTDATA/packed | cmp $TESTDATA/pretty.txt - || fail decode packed +$CAPNP decode --packed --flat $SCHEMA TestAllTypes < $TESTDATA/packedflat | cmp $TESTDATA/pretty.txt - || fail decode packedflat +$CAPNP decode --short $SCHEMA TestAllTypes < $TESTDATA/binary | cmp $TESTDATA/short.txt - || fail decode short + +$CAPNP decode $SCHEMA TestAllTypes < $TESTDATA/segmented | cmp $TESTDATA/pretty.txt - || fail decode segmented +$CAPNP decode --packed $SCHEMA TestAllTypes < $TESTDATA/segmented-packed | cmp $TESTDATA/pretty.txt - || fail decode segmented-packed + +test_eval() { + test "x`$CAPNP eval $SCHEMA $1 | tr -d '\r'`" = "x$2" || fail eval "$1 == $2" +} + +test_eval TestDefaults.uInt32Field 3456789012 +test_eval TestDefaults.structField.textField '"baz"' +test_eval TestDefaults.int8List "[111, -111]" +test_eval 'TestDefaults.structList[1].textField' '"structlist 2"' +test_eval globalPrintableStruct '(someText = "foo")' +test_eval TestConstants.enumConst corge +test_eval 'TestListDefaults.lists.int32ListList[2][0]' 12341234 + +$CAPNP compile -ofoo $TESTDATA/errors.capnp.nobuild 2>&1 | sed -e "s,^.*/errors[.]capnp[.]nobuild,file,g" | tr -d '\r' | + cmp $TESTDATA/errors.txt - || fail error output diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1574 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "lexer.h" +#include "parser.h" +#include "compiler.h" +#include "module-loader.h" +#include "node-translator.h" +#include +#include +#include +#include +#include +#include +#include "../message.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#endif + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef VERSION +#define VERSION "(unknown)" +#endif + +namespace capnp { +namespace compiler { + +static const char VERSION_STRING[] = "Cap'n Proto version " VERSION; + +class CompilerMain final: public GlobalErrorReporter { +public: + explicit CompilerMain(kj::ProcessContext& context) + : context(context), loader(*this) {} + + kj::MainFunc getMain() { + if (context.getProgramName().endsWith("capnpc")) { + kj::MainBuilder builder(context, VERSION_STRING, + "Compiles Cap'n Proto schema files and generates corresponding source code in one or " + "more languages."); + addGlobalOptions(builder); + addCompileOptions(builder); + builder.addOption({'i', "generate-id"}, KJ_BIND_METHOD(*this, generateId), + "Generate a new 64-bit unique ID for use in a Cap'n Proto schema."); + return builder.build(); + } else { + kj::MainBuilder builder(context, VERSION_STRING, + "Command-line tool for Cap'n Proto development and debugging."); + builder.addSubCommand("compile", KJ_BIND_METHOD(*this, getCompileMain), + "Generate source code from schema files.") + .addSubCommand("id", KJ_BIND_METHOD(*this, getGenIdMain), + "Generate a new unique ID.") + .addSubCommand("decode", KJ_BIND_METHOD(*this, getDecodeMain), + "Decode binary Cap'n Proto message to text.") + .addSubCommand("encode", KJ_BIND_METHOD(*this, getEncodeMain), + "Encode text Cap'n Proto message to binary.") + .addSubCommand("eval", KJ_BIND_METHOD(*this, getEvalMain), + "Evaluate a const from a schema file."); + addGlobalOptions(builder); + return builder.build(); + } + } + + kj::MainFunc getCompileMain() { + kj::MainBuilder builder(context, VERSION_STRING, + "Compiles Cap'n Proto schema files and generates corresponding source code in one or " + "more languages."); + addGlobalOptions(builder); + addCompileOptions(builder); + return builder.build(); + } + + kj::MainFunc getGenIdMain() { + return kj::MainBuilder(context, VERSION_STRING, + "Generates a new 64-bit unique ID for use in a Cap'n Proto schema.") + .callAfterParsing(KJ_BIND_METHOD(*this, generateId)) + .build(); + } + + kj::MainFunc getDecodeMain() { + // Only parse the schemas we actually need for decoding. + compileEagerness = Compiler::NODE; + + // Drop annotations since we don't need them. This avoids importing files like c++.capnp. + annotationFlag = Compiler::DROP_ANNOTATIONS; + + kj::MainBuilder builder(context, VERSION_STRING, + "Decodes one or more encoded Cap'n Proto messages as text. The messages have root " + "type defined in . Messages are read from standard input and " + "by default are expected to be in standard Cap'n Proto serialization format."); + addGlobalOptions(builder); + builder.addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat), + "Interpret the input as one large single-segment message rather than a " + "stream in standard serialization format. (Rarely used.)") + .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked), + "Expect the input to be packed using standard Cap'n Proto packing, which " + "deflates zero-valued bytes. (This reads messages written with " + "capnp::writePackedMessage*() from . Do not use " + "this for messages written with capnp::writeMessage*() from " + ".)") + .addOption({"short"}, KJ_BIND_METHOD(*this, printShort), + "Print in short (non-pretty) format. Each message will be printed on one " + "line, without using whitespace to improve readability.") + .addOption({"quiet"}, KJ_BIND_METHOD(*this, setQuiet), + "Do not print warning messages about the input being in the wrong format. " + "Use this if you find the warnings are wrong (but also let us know so " + "we can improve them).") + .expectArg("", KJ_BIND_METHOD(*this, addSource)) + .expectArg("", KJ_BIND_METHOD(*this, setRootType)) + .callAfterParsing(KJ_BIND_METHOD(*this, decode)); + return builder.build(); + } + + kj::MainFunc getEncodeMain() { + // Only parse the schemas we actually need for decoding. + compileEagerness = Compiler::NODE; + + // Drop annotations since we don't need them. This avoids importing files like c++.capnp. + annotationFlag = Compiler::DROP_ANNOTATIONS; + + kj::MainBuilder builder(context, VERSION_STRING, + "Encodes one or more textual Cap'n Proto messages to binary. The messages have root " + "type defined in . Messages are read from standard input. Each " + "mesage is a parenthesized struct literal, like the format used to specify constants " + "and default values of struct type in the schema language. For example:\n" + " (foo = 123, bar = \"hello\", baz = [true, false, true])\n" + "The input may contain any number of such values; each will be encoded as a separate " + "message.", + + "Note that the current implementation reads the entire input into memory before " + "beginning to encode. A better implementation would read and encode one message at " + "a time."); + addGlobalOptions(builder); + builder.addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat), + "Expect only one input value, serializing it as a single-segment message " + "with no framing.") + .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked), + "Pack the output message with standard Cap'n Proto packing, which " + "deflates zero-valued bytes. (This writes messages using " + "capnp::writePackedMessage() from . Without " + "this, capnp::writeMessage() from is used.)") + .addOptionWithArg({"segment-size"}, KJ_BIND_METHOD(*this, setSegmentSize), "", + "Sets the preferred segment size on the MallocMessageBuilder to " + "words and turns off heuristic growth. This flag is mainly useful " + "for testing. Without it, each message will be written as a single " + "segment.") + .expectArg("", KJ_BIND_METHOD(*this, addSource)) + .expectArg("", KJ_BIND_METHOD(*this, setRootType)) + .callAfterParsing(KJ_BIND_METHOD(*this, encode)); + return builder.build(); + } + + kj::MainFunc getEvalMain() { + // Only parse the schemas we actually need for decoding. + compileEagerness = Compiler::NODE; + + // Drop annotations since we don't need them. This avoids importing files like c++.capnp. + annotationFlag = Compiler::DROP_ANNOTATIONS; + + kj::MainBuilder builder(context, VERSION_STRING, + "Prints (or encodes) the value of , which must be defined in . " + " must refer to a const declaration, a field of a struct type (prints the default " + "value), or a field or list element nested within some other value. Examples:\n" + " capnp eval myschema.capnp MyType.someField\n" + " capnp eval myschema.capnp someConstant\n" + " capnp eval myschema.capnp someConstant.someField\n" + " capnp eval myschema.capnp someConstant.someList[4]\n" + " capnp eval myschema.capnp someConstant.someList[4].anotherField[1][2][3]\n" + "Since consts can have complex struct types, and since you can define a const using " + "import and variable substitution, this can be a convenient way to write text-format " + "config files which are compiled to binary before deployment.", + + "By default the value is written in text format and can have any type. The -b, -p, " + "and --flat flags specify binary output, in which case the const must be of struct " + "type."); + addGlobalOptions(builder); + builder.addOption({'b', "binary"}, KJ_BIND_METHOD(*this, codeBinary), + "Write the output as binary instead of text, using standard Cap'n Proto " + "serialization. (This writes the message using capnp::writeMessage() " + "from .)") + .addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat), + "Write the output as a flat single-segment binary message, with no framing.") + .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked), + "Write the output as packed binary instead of text, using standard Cap'n " + "Proto packing, which deflates zero-valued bytes. (This writes the " + "message using capnp::writePackedMessage() from " + ".)") + .addOption({"short"}, KJ_BIND_METHOD(*this, printShort), + "Print in short (non-pretty) text format. The message will be printed on " + "one line, without using whitespace to improve readability.") + .expectArg("", KJ_BIND_METHOD(*this, addSource)) + .expectArg("", KJ_BIND_METHOD(*this, evalConst)); + return builder.build(); + } + + void addGlobalOptions(kj::MainBuilder& builder) { + builder.addOptionWithArg({'I', "import-path"}, KJ_BIND_METHOD(*this, addImportPath), "", + "Add to the list of directories searched for non-relative " + "imports (ones that start with a '/').") + .addOption({"no-standard-import"}, KJ_BIND_METHOD(*this, noStandardImport), + "Do not add any default import paths; use only those specified by -I. " + "Otherwise, typically /usr/include and /usr/local/include are added by " + "default."); + } + + void addCompileOptions(kj::MainBuilder& builder) { + builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, addOutput), "[:]", + "Generate source code for language in directory " + "(default: current directory). actually specifies a plugin " + "to use. If is a simple word, the compiler searches for a plugin " + "called 'capnpc-' in $PATH. If is a file path " + "containing slashes, it is interpreted as the exact plugin " + "executable file name, and $PATH is not searched. If is '-', " + "the compiler dumps the request to standard output.") + .addOptionWithArg({"src-prefix"}, KJ_BIND_METHOD(*this, addSourcePrefix), "", + "If a file specified for compilation starts with , remove " + "the prefix for the purpose of deciding the names of output files. " + "For example, the following command:\n" + " capnp compile --src-prefix=foo/bar -oc++:corge foo/bar/baz/qux.capnp\n" + "would generate the files corge/baz/qux.capnp.{h,c++}.") + .expectOneOrMoreArgs("", KJ_BIND_METHOD(*this, addSource)) + .callAfterParsing(KJ_BIND_METHOD(*this, generateOutput)); + } + + // ===================================================================================== + // shared options + + kj::MainBuilder::Validity addImportPath(kj::StringPtr path) { + loader.addImportPath(kj::heapString(path)); + return true; + } + + kj::MainBuilder::Validity noStandardImport() { + addStandardImportPaths = false; + return true; + } + + kj::MainBuilder::Validity addSource(kj::StringPtr file) { + // Strip redundant "./" prefixes to make src-prefix matching more lenient. + while (file.startsWith("./")) { + file = file.slice(2); + + // Remove redundant slashes as well (e.g. ".////foo" -> "foo"). + while (file.startsWith("/")) { + file = file.slice(1); + } + } + + if (!compilerConstructed) { + compiler = compilerSpace.construct(annotationFlag); + compilerConstructed = true; + } + + if (addStandardImportPaths) { + loader.addImportPath(kj::heapString("/usr/local/include")); + loader.addImportPath(kj::heapString("/usr/include")); +#ifdef CAPNP_INCLUDE_DIR + loader.addImportPath(kj::heapString(CAPNP_INCLUDE_DIR)); +#endif + addStandardImportPaths = false; + } + + KJ_IF_MAYBE(module, loadModule(file)) { + uint64_t id = compiler->add(*module); + compiler->eagerlyCompile(id, compileEagerness); + sourceFiles.add(SourceFile { id, module->getSourceName(), &*module }); + } else { + return "no such file"; + } + + return true; + } + +private: + kj::Maybe loadModule(kj::StringPtr file) { + size_t longestPrefix = 0; + + for (auto& prefix: sourcePrefixes) { + if (file.startsWith(prefix)) { + longestPrefix = kj::max(longestPrefix, prefix.size()); + } + } + + kj::StringPtr canonicalName = file.slice(longestPrefix); + return loader.loadModule(file, canonicalName); + } + +public: + // ===================================================================================== + // "id" command + + kj::MainBuilder::Validity generateId() { + context.exitInfo(kj::str("@0x", kj::hex(generateRandomId()))); + KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT; + } + + // ===================================================================================== + // "compile" command + + kj::MainBuilder::Validity addOutput(kj::StringPtr spec) { + KJ_IF_MAYBE(split, spec.findFirst(':')) { + kj::StringPtr dir = spec.slice(*split + 1); + auto plugin = spec.slice(0, *split); + + KJ_IF_MAYBE(split2, dir.findFirst(':')) { + // Grr, there are two colons. Might this be a Windows path? Let's do some heuristics. + if (*split == 1 && (dir.startsWith("/") || dir.startsWith("\\"))) { + // So, the first ':' was the second char, and was followed by '/' or '\', e.g.: + // capnp compile -o c:/foo.exe:bar + // + // In this case we can conclude that the second colon is actually meant to be the + // plugin/location separator, and the first colon was simply signifying a drive letter. + // + // Proof by contradiction: + // - Say that none of the colons were meant to be plugin/location separators; i.e. the + // whole argument is meant to be a plugin indicator and the location defaults to ".". + // -> In this case, the plugin path has two colons, which is not valid. + // -> CONTRADICTION + // - Say that the first colon was meant to be the plugin/location separator. + // -> In this case, the second colon must be the drive letter separator for the + // output location. + // -> However, the output location begins with '/' or '\', which is not a drive letter. + // -> CONTRADICTION + // - Say that there are more colons beyond the first two, and one of these is meant to + // be the plugin/location separator. + // -> In this case, the plugin path has two or more colons, which is not valid. + // -> CONTRADICTION + // + // We therefore conclude that the *second* colon is in fact the plugin/location separator. + // + // Note that there is still an ambiguous case: + // capnp compile -o c:/foo + // + // In this unfortunate case, we have no way to tell if the user meant "use the 'c' plugin + // and output to /foo" or "use the plugin c:/foo and output to the default location". We + // prefer the former interpretation, because the latter is Windows-specific and such + // users can always explicitly specify the output location like: + // capnp compile -o c:/foo:. + + dir = dir.slice(*split2 + 1); + plugin = spec.slice(0, *split2 + 2); + } + } + + struct stat stats; + if (stat(dir.cStr(), &stats) < 0 || !S_ISDIR(stats.st_mode)) { + return "output location is inaccessible or is not a directory"; + } + outputs.add(OutputDirective { plugin, dir }); + } else { + outputs.add(OutputDirective { spec.asArray(), nullptr }); + } + + return true; + } + + kj::MainBuilder::Validity addSourcePrefix(kj::StringPtr prefix) { + // Strip redundant "./" prefixes to make src-prefix matching more lenient. + while (prefix.startsWith("./")) { + prefix = prefix.slice(2); + } + + if (prefix == "" || prefix == ".") { + // Irrelevant prefix. + return true; + } + + if (prefix.endsWith("/")) { + sourcePrefixes.add(kj::heapString(prefix)); + } else { + sourcePrefixes.add(kj::str(prefix, '/')); + } + return true; + } + + kj::MainBuilder::Validity generateOutput() { + if (hadErrors()) { + // Skip output if we had any errors. + return true; + } + + // We require one or more sources and if they failed to compile we quit above, so this should + // pass. (This assertion also guarantees that `compiler` has been initialized.) + KJ_ASSERT(sourceFiles.size() > 0, "Shouldn't have gotten here without sources."); + + if (outputs.size() == 0) { + return "no outputs specified"; + } + + MallocMessageBuilder message; + auto request = message.initRoot(); + + auto version = request.getCapnpVersion(); + version.setMajor(CAPNP_VERSION_MAJOR); + version.setMinor(CAPNP_VERSION_MINOR); + version.setMicro(CAPNP_VERSION_MICRO); + + auto schemas = compiler->getLoader().getAllLoaded(); + auto nodes = request.initNodes(schemas.size()); + for (size_t i = 0; i < schemas.size(); i++) { + nodes.setWithCaveats(i, schemas[i].getProto()); + } + + auto requestedFiles = request.initRequestedFiles(sourceFiles.size()); + for (size_t i = 0; i < sourceFiles.size(); i++) { + auto requestedFile = requestedFiles[i]; + requestedFile.setId(sourceFiles[i].id); + requestedFile.setFilename(sourceFiles[i].name); + requestedFile.adoptImports(compiler->getFileImportTable( + *sourceFiles[i].module, Orphanage::getForMessageContaining(requestedFile))); + } + + for (auto& output: outputs) { + if (kj::str(output.name) == "-") { + writeMessageToFd(STDOUT_FILENO, message); + continue; + } + + int pipeFds[2]; + KJ_SYSCALL(kj::miniposix::pipe(pipeFds)); + + kj::String exeName; + bool shouldSearchPath = true; + for (char c: output.name) { +#if _WIN32 + if (c == '/' || c == '\\') { +#else + if (c == '/') { +#endif + shouldSearchPath = false; + break; + } + } + if (shouldSearchPath) { + exeName = kj::str("capnpc-", output.name); + } else { + exeName = kj::heapString(output.name); + } + + kj::Array pwd = kj::heapArray(256); + while (getcwd(pwd.begin(), pwd.size()) == nullptr) { + KJ_REQUIRE(pwd.size() < 8192, "WTF your working directory path is more than 8k?"); + pwd = kj::heapArray(pwd.size() * 2); + } + +#if _WIN32 + int oldStdin; + KJ_SYSCALL(oldStdin = dup(STDIN_FILENO)); + intptr_t child; + +#else // _WIN32 + pid_t child; + KJ_SYSCALL(child = fork()); + if (child == 0) { + // I am the child! + + KJ_SYSCALL(close(pipeFds[1])); +#endif // _WIN32, else + + KJ_SYSCALL(dup2(pipeFds[0], STDIN_FILENO)); + KJ_SYSCALL(close(pipeFds[0])); + + if (output.dir != nullptr) { + KJ_SYSCALL(chdir(output.dir.cStr()), output.dir); + } + + if (shouldSearchPath) { +#if _WIN32 + // MSVCRT's spawn*() don't correctly escape arguments, which is necessary on Windows + // since the underlying system call takes a single command line string rather than + // an arg list. Instead of trying to do the escaping ourselves, we just pass "plugin" + // for argv[0]. + child = _spawnlp(_P_NOWAIT, exeName.cStr(), "plugin", nullptr); +#else + execlp(exeName.cStr(), exeName.cStr(), nullptr); +#endif + } else { +#if _WIN32 + if (!exeName.startsWith("/") && !exeName.startsWith("\\") && + !(exeName.size() >= 2 && exeName[1] == ':')) { +#else + if (!exeName.startsWith("/")) { +#endif + // The name is relative. Prefix it with our original working directory path. + exeName = kj::str(pwd.begin(), "/", exeName); + } + +#if _WIN32 + // MSVCRT's spawn*() don't correctly escape arguments, which is necessary on Windows + // since the underlying system call takes a single command line string rather than + // an arg list. Instead of trying to do the escaping ourselves, we just pass "plugin" + // for argv[0]. + child = _spawnl(_P_NOWAIT, exeName.cStr(), "plugin", nullptr); +#else + execl(exeName.cStr(), exeName.cStr(), nullptr); +#endif + } + +#if _WIN32 + if (child == -1) { +#endif + int error = errno; + if (error == ENOENT) { + context.exitError(kj::str(output.name, ": no such plugin (executable should be '", + exeName, "')")); + } else { +#if _WIN32 + KJ_FAIL_SYSCALL("spawn()", error); +#else + KJ_FAIL_SYSCALL("exec()", error); +#endif + } +#if _WIN32 + } + + // Restore stdin. + KJ_SYSCALL(dup2(oldStdin, STDIN_FILENO)); + KJ_SYSCALL(close(oldStdin)); + + // Restore current directory. + KJ_SYSCALL(chdir(pwd.begin()), pwd.begin()); +#else // _WIN32 + } + + KJ_SYSCALL(close(pipeFds[0])); +#endif // _WIN32, else + + writeMessageToFd(pipeFds[1], message); + KJ_SYSCALL(close(pipeFds[1])); + +#if _WIN32 + int status; + if (_cwait(&status, child, 0) == -1) { + KJ_FAIL_SYSCALL("_cwait()", errno); + } + + if (status != 0) { + context.error(kj::str(output.name, ": plugin failed: exit code ", status)); + } + +#else // _WIN32 + int status; + KJ_SYSCALL(waitpid(child, &status, 0)); + if (WIFSIGNALED(status)) { + context.error(kj::str(output.name, ": plugin failed: ", strsignal(WTERMSIG(status)))); + } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + context.error(kj::str(output.name, ": plugin failed: exit code ", WEXITSTATUS(status))); + } +#endif // _WIN32, else + } + + return true; + } + + // ===================================================================================== + // "decode" command + + kj::MainBuilder::Validity codeBinary() { + if (packed) return "cannot be used with --packed"; + if (flat) return "cannot be used with --flat"; + binary = true; + return true; + } + kj::MainBuilder::Validity codeFlat() { + if (binary) return "cannot be used with --binary"; + flat = true; + return true; + } + kj::MainBuilder::Validity codePacked() { + if (binary) return "cannot be used with --binary"; + packed = true; + return true; + } + kj::MainBuilder::Validity printShort() { + pretty = false; + return true; + } + kj::MainBuilder::Validity setQuiet() { + quiet = true; + return true; + } + kj::MainBuilder::Validity setSegmentSize(kj::StringPtr size) { + if (flat) return "cannot be used with --flat"; + char* end; + segmentSize = strtol(size.cStr(), &end, 0); + if (size.size() == 0 || *end != '\0') { + return "not an integer"; + } + return true; + } + + kj::MainBuilder::Validity setRootType(kj::StringPtr type) { + KJ_ASSERT(sourceFiles.size() == 1); + + KJ_IF_MAYBE(schema, resolveName(sourceFiles[0].id, type)) { + if (schema->getProto().which() != schema::Node::STRUCT) { + return "not a struct type"; + } + rootType = schema->asStruct(); + return true; + } else { + return "no such type"; + } + } + +private: + kj::Maybe resolveName(uint64_t scopeId, kj::StringPtr name) { + while (name.size() > 0) { + kj::String temp; + kj::StringPtr part; + KJ_IF_MAYBE(dotpos, name.findFirst('.')) { + temp = kj::heapString(name.slice(0, *dotpos)); + part = temp; + name = name.slice(*dotpos + 1); + } else { + part = name; + name = nullptr; + } + + KJ_IF_MAYBE(childId, compiler->lookup(scopeId, part)) { + scopeId = *childId; + } else { + return nullptr; + } + } + return compiler->getLoader().get(scopeId); + } + +public: + kj::MainBuilder::Validity decode() { + kj::FdInputStream rawInput(STDIN_FILENO); + kj::BufferedInputStreamWrapper input(rawInput); + + if (!quiet) { + auto result = checkPlausibility(input.getReadBuffer()); + if (result.getError() != nullptr) { + return kj::mv(result); + } + } + + if (flat) { + // Read in the whole input to decode as one segment. + kj::Array words; + + { + kj::Vector allBytes; + for (;;) { + auto buffer = input.tryGetReadBuffer(); + if (buffer.size() == 0) break; + allBytes.addAll(buffer); + input.skip(buffer.size()); + } + + if (packed) { + words = kj::heapArray(computeUnpackedSizeInWords(allBytes)); + kj::ArrayInputStream input(allBytes); + capnp::_::PackedInputStream unpacker(input); + unpacker.read(words.asBytes().begin(), words.asBytes().size()); + word dummy; + KJ_ASSERT(unpacker.tryRead(&dummy, sizeof(dummy), sizeof(dummy)) == 0); + } else { + // Technically we don't know if the bytes are aligned so we'd better copy them to a new + // array. Note that if we have a non-whole number of words we chop off the straggler + // bytes. This is fine because if those bytes are actually part of the message we will + // hit an error later and if they are not then who cares? + words = kj::heapArray(allBytes.size() / sizeof(word)); + memcpy(words.begin(), allBytes.begin(), words.size() * sizeof(word)); + } + } + + kj::ArrayPtr segments = words; + decodeInner(arrayPtr(&segments, 1)); + } else { + while (input.tryGetReadBuffer().size() > 0) { + if (packed) { + decodeInner(input); + } else { + decodeInner(input); + } + } + } + + context.exit(); + KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT; + } + +private: + struct ParseErrorCatcher: public kj::ExceptionCallback { + void onRecoverableException(kj::Exception&& e) { + // Only capture the first exception, on the assumption that later exceptions are probably + // just cascading problems. + if (exception == nullptr) { + exception = kj::mv(e); + } + } + + kj::Maybe exception; + }; + + template + void decodeInner(Input&& input) { + // Since this is a debug tool, lift the usual security limits. Worse case is the process + // crashes or has to be killed. + ReaderOptions options; + options.nestingLimit = kj::maxValue; + options.traversalLimitInWords = kj::maxValue; + + MessageReaderType reader(input, options); + kj::String text; + kj::Maybe exception; + + { + ParseErrorCatcher catcher; + auto root = reader.template getRoot(rootType); + if (pretty) { + text = kj::str(prettyPrint(root), '\n'); + } else { + text = kj::str(root, '\n'); + } + exception = kj::mv(catcher.exception); + } + + kj::FdOutputStream(STDOUT_FILENO).write(text.begin(), text.size()); + + KJ_IF_MAYBE(e, exception) { + context.error(kj::str( + "*** ERROR DECODING PREVIOUS MESSAGE ***\n" + "The following error occurred while decoding the message above.\n" + "This probably means the input data is invalid/corrupted.\n", + "Exception description: ", e->getDescription(), "\n" + "Code location: ", e->getFile(), ":", e->getLine(), "\n" + "*** END ERROR ***")); + } + } + + enum Plausibility { + IMPOSSIBLE, + IMPLAUSIBLE, + WRONG_TYPE, + PLAUSIBLE + }; + + bool plausibleOrWrongType(Plausibility p) { + return p == PLAUSIBLE || p == WRONG_TYPE; + } + + Plausibility isPlausiblyFlat(kj::ArrayPtr prefix, uint segmentCount = 1) { + if (prefix.size() < 8) { + // Not enough prefix to say. + return PLAUSIBLE; + } + + if ((prefix[0] & 3) == 2) { + // Far pointer. Verify the segment ID. + uint32_t segmentId = prefix[4] | (prefix[5] << 8) + | (prefix[6] << 16) | (prefix[7] << 24); + if (segmentId == 0 || segmentId >= segmentCount) { + return IMPOSSIBLE; + } else { + return PLAUSIBLE; + } + } + + if ((prefix[0] & 3) != 0) { + // Not a struct pointer. + return IMPOSSIBLE; + } + if ((prefix[3] & 0x80) != 0) { + // Offset is negative (invalid). + return IMPOSSIBLE; + } + if ((prefix[3] & 0xe0) != 0) { + // Offset is over a gigabyte (implausible). + return IMPLAUSIBLE; + } + + uint data = prefix[4] | (prefix[5] << 8); + uint pointers = prefix[6] | (prefix[7] << 8); + + if (data + pointers > 2048) { + // Root struct is huge (over 16 KiB). + return IMPLAUSIBLE; + } + + auto structSchema = rootType.getProto().getStruct(); + if ((data < structSchema.getDataWordCount() && pointers > structSchema.getPointerCount()) || + (data > structSchema.getDataWordCount() && pointers < structSchema.getPointerCount())) { + // Struct is neither older nor newer than the schema. + return WRONG_TYPE; + } + + if (data > structSchema.getDataWordCount() && + data - structSchema.getDataWordCount() > 128) { + // Data section appears to have grown by 1k (128 words). This seems implausible. + return WRONG_TYPE; + } + if (pointers > structSchema.getPointerCount() && + pointers - structSchema.getPointerCount() > 128) { + // Pointer section appears to have grown by 1k (128 words). This seems implausible. + return WRONG_TYPE; + } + + return PLAUSIBLE; + } + + Plausibility isPlausiblyBinary(kj::ArrayPtr prefix) { + if (prefix.size() < 8) { + // Not enough prefix to say. + return PLAUSIBLE; + } + + uint32_t segmentCount = prefix[0] | (prefix[1] << 8) + | (prefix[2] << 16) | (prefix[3] << 24); + + // Actually, the bytes store segmentCount - 1. + ++segmentCount; + + if (segmentCount > 65536) { + // While technically possible, this is so implausible that we should mark it impossible. + // This helps to make sure we fail fast on packed input. + return IMPOSSIBLE; + } else if (segmentCount > 256) { + // Implausible segment count. + return IMPLAUSIBLE; + } + + uint32_t segment0Size = prefix[4] | (prefix[5] << 8) + | (prefix[6] << 16) | (prefix[7] << 24); + + if (segment0Size > (1 << 27)) { + // Segment larger than 1G seems implausible. + return IMPLAUSIBLE; + } + + uint32_t segment0Offset = 4 + segmentCount * 4; + if (segment0Offset % 8 != 0) { + segment0Offset += 4; + } + KJ_ASSERT(segment0Offset % 8 == 0); + + if (prefix.size() < segment0Offset + 8) { + // Segment 0 is past our prefix, so we can't check it. + return PLAUSIBLE; + } + + return isPlausiblyFlat(prefix.slice(segment0Offset, prefix.size()), segmentCount); + } + + Plausibility isPlausiblyPacked(kj::ArrayPtr prefix, + kj::Function)> checkUnpacked) { + kj::Vector unpacked; + + // Try to unpack a prefix so that we can check it. + const byte* pos = prefix.begin(); + const byte* end = prefix.end(); + if (end - pos > 1024) { + // Don't bother unpacking more than 1k. + end = pos + 1024; + } + while (pos < end) { + byte tag = *pos++; + for (uint i = 0; i < 8 && pos < end; i++) { + if (tag & (1 << i)) { + byte b = *pos++; + if (b == 0) { + // A zero byte should have been deflated away. + return IMPOSSIBLE; + } + unpacked.add(b); + } else { + unpacked.add(0); + } + } + + if (pos == end) { + break; + } + + if (tag == 0) { + uint count = *pos++ * 8; + unpacked.addAll(kj::repeat(byte(0), count)); + } else if (tag == 0xff) { + uint count = *pos++ * 8; + size_t available = end - pos; + uint n = kj::min(count, available); + unpacked.addAll(pos, pos + n); + pos += n; + } + } + + return checkUnpacked(unpacked); + } + + Plausibility isPlausiblyPacked(kj::ArrayPtr prefix) { + return isPlausiblyPacked(prefix, KJ_BIND_METHOD(*this, isPlausiblyBinary)); + } + + Plausibility isPlausiblyPackedFlat(kj::ArrayPtr prefix) { + return isPlausiblyPacked(prefix, [this](kj::ArrayPtr prefix) { + return isPlausiblyFlat(prefix); + }); + } + + kj::MainBuilder::Validity checkPlausibility(kj::ArrayPtr prefix) { + if (flat && packed) { + switch (isPlausiblyPackedFlat(prefix)) { + case PLAUSIBLE: + break; + case IMPOSSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + return "The input is not in --packed --flat format. It looks like it is in --packed " + "format. Try removing --flat."; + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + return "The input is not in --packed --flat format. It looks like it is in --flat " + "format. Try removing --packed."; + } else if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + return "The input is not in --packed --flat format. It looks like it is in regular " + "binary format. Try removing the --packed and --flat flags."; + } else { + return "The input is not a Cap'n Proto message."; + } + case IMPLAUSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed --flat format. It looks like\n" + "it may be in --packed format. I'll try to parse it in --packed --flat format\n" + "as you requested, but if it doesn't work, try removing --flat. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed --flat format. It looks like\n" + "it may be in --flat format. I'll try to parse it in --packed --flat format as\n" + "you requested, but if it doesn't work, try removing --packed. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed --flat format. It looks like\n" + "it may be in regular binary format. I'll try to parse it in --packed --flat\n" + "format as you requested, but if it doesn't work, try removing --packed and\n" + "--flat. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be a Cap'n Proto message in any known\n" + "binary format. I'll try to parse it anyway, but if it doesn't work, please\n" + "check your input. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + case WRONG_TYPE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. This could also be because the input is not in --flat\n" + "format; indeed, it looks like this input may be in regular --packed format,\n" + "so you might want to try removing --flat. Use --quiet to suppress this\n" + "warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + } + } else if (flat) { + switch (isPlausiblyFlat(prefix)) { + case PLAUSIBLE: + break; + case IMPOSSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + return "The input is not in --flat format. It looks like it is in --packed format. " + "Try that instead."; + } else if (plausibleOrWrongType(isPlausiblyPackedFlat(prefix))) { + return "The input is not in --flat format. It looks like it is in --packed --flat " + "format. Try adding --packed."; + } else if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + return "The input is not in --flat format. It looks like it is in regular binary " + "format. Try removing the --flat flag."; + } else { + return "The input is not a Cap'n Proto message."; + } + case IMPLAUSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --flat format. It looks like it may\n" + "be in --packed format. I'll try to parse it in --flat format as you\n" + "requested, but if it doesn't work, try --packed instead. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyPackedFlat(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --flat format. It looks like it may\n" + "be in --packed --flat format. I'll try to parse it in --flat format as you\n" + "requested, but if it doesn't work, try adding --packed. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --flat format. It looks like it may\n" + "be in regular binary format. I'll try to parse it in --flat format as you\n" + "requested, but if it doesn't work, try removing --flat. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be a Cap'n Proto message in any known\n" + "binary format. I'll try to parse it anyway, but if it doesn't work, please\n" + "check your input. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + case WRONG_TYPE: + if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. This could also be because the input is not in --flat\n" + "format; indeed, it looks like this input may be in regular binary format,\n" + "so you might want to try removing --flat. Use --quiet to suppress this\n" + "warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + } + } else if (packed) { + switch (isPlausiblyPacked(prefix)) { + case PLAUSIBLE: + break; + case IMPOSSIBLE: + if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + return "The input is not in --packed format. It looks like it is in regular binary " + "format. Try removing the --packed flag."; + } else if (plausibleOrWrongType(isPlausiblyPackedFlat(prefix))) { + return "The input is not in --packed format, nor does it look like it is in regular " + "binary format. It looks like it could be in --packed --flat format, although " + "that is unusual so I could be wrong."; + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + return "The input is not in --packed format, nor does it look like it is in regular " + "binary format. It looks like it could be in --flat format, although that " + "is unusual so I could be wrong."; + } else { + return "The input is not a Cap'n Proto message."; + } + case IMPLAUSIBLE: + if (plausibleOrWrongType(isPlausiblyPackedFlat(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed format. It looks like it may\n" + "be in --packed --flat format. I'll try to parse it in --packed format as you\n" + "requested, but if it doesn't work, try adding --flat. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyBinary(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed format. It looks like it\n" + "may be in regular binary format. I'll try to parse it in --packed format as\n" + "you requested, but if it doesn't work, try removing --packed. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in --packed format, nor does it look\n" + "like it's in regular binary format. It looks like it could be in --flat\n" + "format, although that is unusual so I could be wrong. I'll try to parse\n" + "it in --flat format as you requested, but if it doesn't work, you might\n" + "want to try --flat, or the data may not be Cap'n Proto at all. Use\n" + "--quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be a Cap'n Proto message in any known\n" + "binary format. I'll try to parse it anyway, but if it doesn't work, please\n" + "check your input. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + case WRONG_TYPE: + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + break; + } + } else { + switch (isPlausiblyBinary(prefix)) { + case PLAUSIBLE: + break; + case IMPOSSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + return "The input is not in regular binary format. It looks like it is in --packed " + "format. Try adding the --packed flag."; + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + return "The input is not in regular binary format, nor does it look like it is in " + "--packed format. It looks like it could be in --flat format, although that " + "is unusual so I could be wrong."; + } else if (plausibleOrWrongType(isPlausiblyPackedFlat(prefix))) { + return "The input is not in regular binary format, nor does it look like it is in " + "--packed format. It looks like it could be in --packed --flat format, " + "although that is unusual so I could be wrong."; + } else { + return "The input is not a Cap'n Proto message."; + } + case IMPLAUSIBLE: + if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in regular binary format. It looks like\n" + "it may be in --packed format. I'll try to parse it in regular format as you\n" + "requested, but if it doesn't work, try adding --packed. Use --quiet to\n" + "suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyPacked(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in regular binary format. It looks like\n" + "it may be in --packed --flat format. I'll try to parse it in regular format as\n" + "you requested, but if it doesn't work, try adding --packed --flat. Use --quiet\n" + "to suppress this warning.\n" + "*** END WARNING ***\n"); + } else if (plausibleOrWrongType(isPlausiblyFlat(prefix))) { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be in regular binary format, nor does it\n" + "look like it's in --packed format. It looks like it could be in --flat\n" + "format, although that is unusual so I could be wrong. I'll try to parse\n" + "it in regular format as you requested, but if it doesn't work, you might\n" + "want to try --flat, or the data may not be Cap'n Proto at all. Use\n" + "--quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } else { + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be a Cap'n Proto message in any known\n" + "binary format. I'll try to parse it anyway, but if it doesn't work, please\n" + "check your input. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + } + break; + case WRONG_TYPE: + context.warning( + "*** WARNING ***\n" + "The input data does not appear to be the type that you specified. I'll try\n" + "to parse it anyway, but if it doesn't look right, please verify that you\n" + "have the right type. Use --quiet to suppress this warning.\n" + "*** END WARNING ***\n"); + break; + } + } + + return true; + } + +public: + // ----------------------------------------------------------------- + + kj::MainBuilder::Validity encode() { + kj::Vector allText; + + { + kj::FdInputStream rawInput(STDIN_FILENO); + kj::BufferedInputStreamWrapper input(rawInput); + + for (;;) { + auto buf = input.tryGetReadBuffer(); + if (buf.size() == 0) break; + allText.addAll(buf.asChars()); + input.skip(buf.size()); + } + } + + EncoderErrorReporter errorReporter(*this, allText); + MallocMessageBuilder arena; + + // Lex the input. + auto lexedTokens = arena.initRoot(); + lex(allText, lexedTokens, errorReporter); + + // Set up the parser. + CapnpParser parser(arena.getOrphanage(), errorReporter); + auto tokens = lexedTokens.asReader().getTokens(); + CapnpParser::ParserInput parserInput(tokens.begin(), tokens.end()); + + // Set up stuff for the ValueTranslator. + ValueResolverGlue resolver(compiler->getLoader(), errorReporter); + + // Set up output stream. + kj::FdOutputStream rawOutput(STDOUT_FILENO); + kj::BufferedOutputStreamWrapper output(rawOutput); + + while (parserInput.getPosition() != tokens.end()) { + KJ_IF_MAYBE(expression, parser.getParsers().expression(parserInput)) { + MallocMessageBuilder item( + segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize, + segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE); + ValueTranslator translator(resolver, errorReporter, item.getOrphanage()); + + KJ_IF_MAYBE(value, translator.compileValue(expression->getReader(), rootType)) { + if (segmentSize == 0) { + writeFlat(value->getReader().as(), output); + } else { + item.adoptRoot(value->releaseAs()); + if (packed) { + writePackedMessage(output, item); + } else { + writeMessage(output, item); + } + } + } else { + // Errors were reported, so we'll exit with a failure status later. + } + } else { + auto best = parserInput.getBest(); + if (best == tokens.end()) { + context.exitError("Premature EOF."); + } else { + errorReporter.addErrorOn(*best, "Parse error."); + context.exit(); + } + } + } + + output.flush(); + context.exit(); + KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT; + } + + kj::MainBuilder::Validity evalConst(kj::StringPtr name) { + KJ_ASSERT(sourceFiles.size() == 1); + + auto parser = kj::parse::sequence( + kj::parse::many( + kj::parse::sequence( + kj::parse::identifier, + kj::parse::many( + kj::parse::sequence( + kj::parse::exactChar<'['>(), + kj::parse::integer, + kj::parse::exactChar<']'>())), + kj::parse::oneOf( + kj::parse::endOfInput, + kj::parse::sequence( + kj::parse::exactChar<'.'>(), + kj::parse::notLookingAt(kj::parse::endOfInput))))), + kj::parse::endOfInput); + + kj::parse::IteratorInput input(name.begin(), name.end()); + + kj::Array>> nameParts; + KJ_IF_MAYBE(p, parser(input)) { + nameParts = kj::mv(*p); + } else { + return "invalid syntax"; + } + + auto pos = nameParts.begin(); + + // Traverse the path to find a schema. + uint64_t scopeId = sourceFiles[0].id; + bool stoppedAtSubscript = false; + for (; pos != nameParts.end(); ++pos) { + kj::StringPtr part = kj::get<0>(*pos); + + KJ_IF_MAYBE(childId, compiler->lookup(scopeId, part)) { + scopeId = *childId; + + if (kj::get<1>(*pos).size() > 0) { + stoppedAtSubscript = true; + break; + } + } else { + break; + } + } + Schema schema = compiler->getLoader().get(scopeId); + + // Evaluate this schema to a DynamicValue. + DynamicValue::Reader value; + word zeroWord[1]; + memset(&zeroWord, 0, sizeof(zeroWord)); + kj::ArrayPtr segments[1] = { kj::arrayPtr(zeroWord, 1) }; + SegmentArrayMessageReader emptyMessage(segments); + switch (schema.getProto().which()) { + case schema::Node::CONST: + value = schema.asConst(); + break; + + case schema::Node::STRUCT: + if (pos == nameParts.end()) { + return kj::str("'", schema.getShortDisplayName(), "' cannot be evaluated."); + } + + // Use the struct's default value. + value = emptyMessage.getRoot(schema.asStruct()); + break; + + default: + if (stoppedAtSubscript) { + return kj::str("'", schema.getShortDisplayName(), "' is not a list."); + } else if (pos != nameParts.end()) { + return kj::str("'", kj::get<0>(*pos), "' is not defined."); + } else { + return kj::str("'", schema.getShortDisplayName(), "' cannot be evaluated."); + } + } + + // Traverse the rest of the path as struct fields. + for (; pos != nameParts.end(); ++pos) { + kj::StringPtr partName = kj::get<0>(*pos); + + if (!stoppedAtSubscript) { + if (value.getType() == DynamicValue::STRUCT) { + auto structValue = value.as(); + KJ_IF_MAYBE(field, structValue.getSchema().findFieldByName(partName)) { + value = structValue.get(*field); + } else { + return kj::str("'", kj::get<0>(pos[-1]), "' has no member '", partName, "'."); + } + } else { + return kj::str("'", kj::get<0>(pos[-1]), "' is not a struct."); + } + } + + auto& subscripts = kj::get<1>(*pos); + for (uint i = 0; i < subscripts.size(); i++) { + uint64_t subscript = subscripts[i]; + if (value.getType() == DynamicValue::LIST) { + auto listValue = value.as(); + if (subscript < listValue.size()) { + value = listValue[subscript]; + } else { + return kj::str("'", partName, "[", kj::strArray(subscripts.slice(0, i + 1), "]["), + "]' is out-of-bounds."); + } + } else { + if (i > 0) { + return kj::str("'", partName, "[", kj::strArray(subscripts.slice(0, i), "]["), + "]' is not a list."); + } else { + return kj::str("'", partName, "' is not a list."); + } + } + } + + stoppedAtSubscript = false; + } + + // OK, we have a value. Print it. + if (binary || packed || flat) { + if (value.getType() != DynamicValue::STRUCT) { + return "not a struct; binary output is only available on structs"; + } + + kj::FdOutputStream rawOutput(STDOUT_FILENO); + kj::BufferedOutputStreamWrapper output(rawOutput); + writeFlat(value.as(), output); + output.flush(); + context.exit(); + } else { + if (pretty && value.getType() == DynamicValue::STRUCT) { + context.exitInfo(prettyPrint(value.as()).flatten()); + } else if (pretty && value.getType() == DynamicValue::LIST) { + context.exitInfo(prettyPrint(value.as()).flatten()); + } else { + context.exitInfo(kj::str(value)); + } + } + + KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT; + } + +private: + void writeFlat(DynamicStruct::Reader value, kj::BufferedOutputStream& output) { + // Always copy the message to a flat array so that the output is predictable (one segment, + // in canonical order). + size_t size = value.totalSize().wordCount + 1; + kj::Array space = kj::heapArray(size); + memset(space.begin(), 0, size * sizeof(word)); + FlatMessageBuilder flatMessage(space); + flatMessage.setRoot(value); + flatMessage.requireFilled(); + + if (flat && packed) { + capnp::_::PackedOutputStream packer(output); + packer.write(space.begin(), space.size() * sizeof(word)); + } else if (flat) { + output.write(space.begin(), space.size() * sizeof(word)); + } else if (packed) { + writePackedMessage(output, flatMessage); + } else { + writeMessage(output, flatMessage); + } + } + + class EncoderErrorReporter final: public ErrorReporter { + public: + EncoderErrorReporter(GlobalErrorReporter& globalReporter, + kj::ArrayPtr content) + : globalReporter(globalReporter), lineBreaks(content) {} + + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + globalReporter.addError("", lineBreaks.toSourcePos(startByte), + lineBreaks.toSourcePos(endByte), message); + } + + bool hadErrors() override { + return globalReporter.hadErrors(); + } + + private: + GlobalErrorReporter& globalReporter; + LineBreakTable lineBreaks; + }; + + class ValueResolverGlue final: public ValueTranslator::Resolver { + public: + ValueResolverGlue(const SchemaLoader& loader, ErrorReporter& errorReporter) + : loader(loader), errorReporter(errorReporter) {} + + kj::Maybe resolveType(uint64_t id) { + // Don't use tryGet() here because we shouldn't even be here if there were compile errors. + return loader.get(id); + } + + kj::Maybe resolveConstant(Expression::Reader name) override { + errorReporter.addErrorOn(name, kj::str("External constants not allowed in encode input.")); + return nullptr; + } + + kj::Maybe> readEmbed(LocatedText::Reader filename) override { + errorReporter.addErrorOn(filename, kj::str("External embeds not allowed in encode input.")); + return nullptr; + } + + private: + const SchemaLoader& loader; + ErrorReporter& errorReporter; + }; + +public: + // ===================================================================================== + + void addError(kj::StringPtr file, SourcePos start, SourcePos end, + kj::StringPtr message) override { + kj::String wholeMessage; + if (end.line == start.line) { + if (end.column == start.column) { + wholeMessage = kj::str(file, ":", start.line + 1, ":", start.column + 1, + ": error: ", message, "\n"); + } else { + wholeMessage = kj::str(file, ":", start.line + 1, ":", start.column + 1, + "-", end.column + 1, ": error: ", message, "\n"); + } + } else { + // The error spans multiple lines, so just report it on the first such line. + wholeMessage = kj::str(file, ":", start.line + 1, ": error: ", message, "\n"); + } + + context.error(wholeMessage); + hadErrors_ = true; + } + + bool hadErrors() override { + return hadErrors_; + } + +private: + kj::ProcessContext& context; + ModuleLoader loader; + kj::SpaceFor compilerSpace; + bool compilerConstructed = false; + kj::Own compiler; + + Compiler::AnnotationFlag annotationFlag = Compiler::COMPILE_ANNOTATIONS; + + uint compileEagerness = Compiler::NODE | Compiler::CHILDREN | + Compiler::DEPENDENCIES | Compiler::DEPENDENCY_PARENTS; + // By default we compile each explicitly listed schema in full, plus first-level dependencies + // of those schemas, plus the parent nodes of any dependencies. This is what most code generators + // require to function. + + kj::Vector sourcePrefixes; + bool addStandardImportPaths = true; + + bool binary = false; + bool flat = false; + bool packed = false; + bool pretty = true; + bool quiet = false; + uint segmentSize = 0; + StructSchema rootType; + // For the "decode" and "encode" commands. + + struct SourceFile { + uint64_t id; + kj::StringPtr name; + Module* module; + }; + + kj::Vector sourceFiles; + + struct OutputDirective { + kj::ArrayPtr name; + kj::StringPtr dir; + }; + kj::Vector outputs; + + bool hadErrors_ = false; +}; + +} // namespace compiler +} // namespace capnp + +KJ_MAIN(capnp::compiler::CompilerMain); diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnp.ekam-manifest --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnp.ekam-manifest Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,3 @@ +capnp bin +capnpc-capnp bin +capnpc-c++ bin diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnpc-c++.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnpc-c++.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,3079 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This program is a code generator plugin for `capnp compile` which generates C++ code. + +#include +#include "../serialize.h" +#include +#include +#include +#include +#include +#include "../schema-loader.h" +#include "../dynamic.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef VERSION +#define VERSION "(unknown)" +#endif + +namespace capnp { +namespace { + +static constexpr uint64_t NAMESPACE_ANNOTATION_ID = 0xb9c6f99ebf805f2cull; +static constexpr uint64_t NAME_ANNOTATION_ID = 0xf264a779fef191ceull; + +bool hasDiscriminantValue(const schema::Field::Reader& reader) { + return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT; +} + +void enumerateDeps(schema::Type::Reader type, std::set& deps) { + switch (type.which()) { + case schema::Type::STRUCT: + deps.insert(type.getStruct().getTypeId()); + break; + case schema::Type::ENUM: + deps.insert(type.getEnum().getTypeId()); + break; + case schema::Type::INTERFACE: + deps.insert(type.getInterface().getTypeId()); + break; + case schema::Type::LIST: + enumerateDeps(type.getList().getElementType(), deps); + break; + default: + break; + } +} + +void enumerateDeps(schema::Node::Reader node, std::set& deps) { + switch (node.which()) { + case schema::Node::STRUCT: { + auto structNode = node.getStruct(); + for (auto field: structNode.getFields()) { + switch (field.which()) { + case schema::Field::SLOT: + enumerateDeps(field.getSlot().getType(), deps); + break; + case schema::Field::GROUP: + deps.insert(field.getGroup().getTypeId()); + break; + } + } + if (structNode.getIsGroup()) { + deps.insert(node.getScopeId()); + } + break; + } + case schema::Node::INTERFACE: { + auto interfaceNode = node.getInterface(); + for (auto superclass: interfaceNode.getSuperclasses()) { + deps.insert(superclass.getId()); + } + for (auto method: interfaceNode.getMethods()) { + deps.insert(method.getParamStructType()); + deps.insert(method.getResultStructType()); + } + break; + } + default: + break; + } +} + +struct OrderByName { + template + inline bool operator()(const T& a, const T& b) const { + return a.getProto().getName() < b.getProto().getName(); + } +}; + +template +kj::Array makeMembersByName(MemberList&& members) { + auto sorted = KJ_MAP(member, members) { return member; }; + std::sort(sorted.begin(), sorted.end(), OrderByName()); + return KJ_MAP(member, sorted) { return member.getIndex(); }; +} + +kj::StringPtr baseName(kj::StringPtr path) { + KJ_IF_MAYBE(slashPos, path.findLast('/')) { + return path.slice(*slashPos + 1); + } else { + return path; + } +} + +kj::String safeIdentifier(kj::StringPtr identifier) { + // Given a desired identifier name, munge it to make it safe for use in generated code. + // + // If the identifier is a keyword, this adds an underscore to the end. + + static const std::set keywords({ + "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", + "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "constexpr", + "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", + "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", + "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", + "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", + "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", + "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", + "volatile", "wchar_t", "while", "xor", "xor_eq" + }); + + if (keywords.count(identifier) > 0) { + return kj::str(identifier, '_'); + } else { + return kj::heapString(identifier); + } +} + +// ======================================================================================= + +class CppTypeName { + // Used to build a C++ type name string. This is complicated in the presence of templates, + // because we must add the "typename" and "template" disambiguator keywords as needed. + +public: + inline CppTypeName(): isArgDependent(false), needsTypename(false), + hasInterfaces_(false), hasDisambiguatedTemplate_(false) {} + CppTypeName(CppTypeName&& other) = default; + CppTypeName(const CppTypeName& other) + : name(kj::strTree(other.name.flatten())), + isArgDependent(other.isArgDependent), + needsTypename(other.needsTypename), + hasInterfaces_(other.hasInterfaces_), + hasDisambiguatedTemplate_(other.hasDisambiguatedTemplate_) {} + + CppTypeName& operator=(CppTypeName&& other) = default; + CppTypeName& operator=(const CppTypeName& other) { + name = kj::strTree(other.name.flatten()); + isArgDependent = other.isArgDependent; + needsTypename = other.needsTypename; + return *this; + } + + static CppTypeName makeRoot() { + return CppTypeName(kj::strTree(" "), false); + } + + static CppTypeName makeNamespace(kj::StringPtr name) { + return CppTypeName(kj::strTree(" ::", name), false); + } + + static CppTypeName makeTemplateParam(kj::StringPtr name) { + return CppTypeName(kj::strTree(name), true); + } + + static CppTypeName makePrimitive(kj::StringPtr name) { + return CppTypeName(kj::strTree(name), false); + } + + void addMemberType(kj::StringPtr innerName) { + // Append "::innerName" to refer to a member. + + name = kj::strTree(kj::mv(name), "::", innerName); + needsTypename = isArgDependent; + } + + void addMemberValue(kj::StringPtr innerName) { + // Append "::innerName" to refer to a member. + + name = kj::strTree(kj::mv(name), "::", innerName); + needsTypename = false; + } + + bool hasDisambiguatedTemplate() { + return hasDisambiguatedTemplate_; + } + + void addMemberTemplate(kj::StringPtr innerName, kj::Array&& params) { + // Append "::innerName". + // + // If necessary, add the "template" disambiguation keyword in front of `innerName`. + + bool parentIsArgDependent = isArgDependent; + needsTypename = parentIsArgDependent; + hasDisambiguatedTemplate_ = hasDisambiguatedTemplate_ || parentIsArgDependent; + + name = kj::strTree(kj::mv(name), + parentIsArgDependent ? "::template " : "::", + innerName, '<', + kj::StringTree(KJ_MAP(p, params) { + if (p.isArgDependent) isArgDependent = true; + if (p.hasInterfaces_) hasInterfaces_ = true; + if (p.hasDisambiguatedTemplate_) hasDisambiguatedTemplate_ = true; + return kj::strTree(kj::mv(p)); + }, ", "), + '>'); + } + + void setHasInterfaces() { + hasInterfaces_ = true; + } + + bool hasInterfaces() { + return hasInterfaces_; + } + + kj::StringTree strNoTypename() const & { return name.flatten(); } + kj::StringTree strNoTypename() && { return kj::mv(name); } + // Stringify but never prefix with `typename`. Use in contexts where `typename` is implicit. + +private: + kj::StringTree name; + + bool isArgDependent; + // Does the name contain any template-argument-dependent types? + + bool needsTypename; + // Does the name require a prefix of "typename"? + + bool hasInterfaces_; + // Does this type name refer to any interface types? If so it may need to be #ifdefed out in + // lite mode. + + bool hasDisambiguatedTemplate_; + // Whether the type name contains a template type that had to be disambiguated using the + // "template" keyword, e.g. "Foo::template Bar". + // + // TODO(msvc): We only track this because MSVC seems to get confused by it in some weird cases. + + inline CppTypeName(kj::StringTree&& name, bool isArgDependent) + : name(kj::mv(name)), isArgDependent(isArgDependent), needsTypename(false), + hasInterfaces_(false), hasDisambiguatedTemplate_(false) {} + + friend kj::StringTree KJ_STRINGIFY(CppTypeName&& typeName); + friend kj::String KJ_STRINGIFY(const CppTypeName& typeName); +}; + +kj::StringTree KJ_STRINGIFY(CppTypeName&& typeName) { + if (typeName.needsTypename) { + return kj::strTree("typename ", kj::mv(typeName.name)); + } else { + return kj::mv(typeName.name); + } +} +kj::String KJ_STRINGIFY(const CppTypeName& typeName) { + if (typeName.needsTypename) { + return kj::str("typename ", typeName.name); + } else { + return typeName.name.flatten(); + } +} + +// ======================================================================================= + +class CapnpcCppMain { +public: + CapnpcCppMain(kj::ProcessContext& context): context(context) {} + + kj::MainFunc getMain() { + return kj::MainBuilder(context, "Cap'n Proto C++ plugin version " VERSION, + "This is a Cap'n Proto compiler plugin which generates C++ code. " + "It is meant to be run using the Cap'n Proto compiler, e.g.:\n" + " capnp compile -oc++ foo.capnp") + .callAfterParsing(KJ_BIND_METHOD(*this, run)) + .build(); + } + +private: + kj::ProcessContext& context; + SchemaLoader schemaLoader; + std::unordered_set usedImports; + bool hasInterfaces = false; + + CppTypeName cppFullName(Schema schema, kj::Maybe method) { + return cppFullName(schema, schema, method); + } + + CppTypeName cppFullName(Schema schema, Schema brand, kj::Maybe method) { + auto node = schema.getProto(); + + if (node.getScopeId() == 0) { + // This is the file-level scope. Search for the namespace annotation. + KJ_REQUIRE(node.isFile(), + "Non-file had scopeId zero; perhaps it's a method param / result struct?"); + usedImports.insert(node.getId()); + KJ_IF_MAYBE(ns, annotationValue(node, NAMESPACE_ANNOTATION_ID)) { + return CppTypeName::makeNamespace(ns->getText()); + } else { + return CppTypeName::makeRoot(); + } + } else { + // This is a named type. + + // Figure out what name to use. + Schema parent = schemaLoader.get(node.getScopeId()); + kj::StringPtr unqualifiedName; + kj::String ownUnqualifiedName; + KJ_IF_MAYBE(annotatedName, annotationValue(node, NAME_ANNOTATION_ID)) { + // The node's name has been overridden for C++ by an annotation. + unqualifiedName = annotatedName->getText(); + } else { + // Search among the parent's nested nodes to for this node, in order to determine its name. + auto parentProto = parent.getProto(); + for (auto nested: parentProto.getNestedNodes()) { + if (nested.getId() == node.getId()) { + unqualifiedName = nested.getName(); + break; + } + } + if (unqualifiedName == nullptr) { + // Hmm, maybe it's a group node? + if (parentProto.isStruct()) { + for (auto field: parentProto.getStruct().getFields()) { + if (field.isGroup() && field.getGroup().getTypeId() == node.getId()) { + ownUnqualifiedName = toTitleCase(protoName(field)); + unqualifiedName = ownUnqualifiedName; + break; + } + } + } + } + KJ_REQUIRE(unqualifiedName != nullptr, + "A schema Node's supposed scope did not contain the node as a NestedNode."); + } + + auto result = cppFullName(parent, brand, method); + + // Construct the generic arguments. + auto params = node.getParameters(); + if (params.size() > 0) { + auto args = brand.getBrandArgumentsAtScope(node.getId()); + +#if 0 + // Figure out exactly how many params are not bound to AnyPointer. + // TODO(msvc): In a few obscure cases, MSVC does not like empty template pramater lists, + // even if all parameters have defaults. So, we give in and explicitly list all + // parameters in our generated code for now. Try again later. + uint paramCount = 0; + for (uint i: kj::indices(params)) { + auto arg = args[i]; + if (arg.which() != schema::Type::ANY_POINTER || arg.getBrandParameter() != nullptr || + (arg.getImplicitParameter() != nullptr && method != nullptr)) { + paramCount = i + 1; + } + } +#else + uint paramCount = params.size(); +#endif + + result.addMemberTemplate(unqualifiedName, + KJ_MAP(i, kj::range(0u, paramCount)) { + return typeName(args[i], method); + }); + } else { + result.addMemberType(unqualifiedName); + } + + return result; + } + } + + kj::String toUpperCase(kj::StringPtr name) { + kj::Vector result(name.size() + 4); + + for (char c: name) { + if ('a' <= c && c <= 'z') { + result.add(c - 'a' + 'A'); + } else if (result.size() > 0 && 'A' <= c && c <= 'Z') { + result.add('_'); + result.add(c); + } else { + result.add(c); + } + } + + if (result.size() == 4 && memcmp(result.begin(), "NULL", 4) == 0) { + // NULL probably collides with a macro. + result.add('_'); + } + + result.add('\0'); + + return kj::String(result.releaseAsArray()); + } + + kj::String toTitleCase(kj::StringPtr name) { + kj::String result = kj::heapString(name); + if ('a' <= result[0] && result[0] <= 'z') { + result[0] = result[0] - 'a' + 'A'; + } + return kj::mv(result); + } + + CppTypeName typeName(Type type, kj::Maybe method) { + switch (type.which()) { + case schema::Type::VOID: return CppTypeName::makePrimitive(" ::capnp::Void"); + + case schema::Type::BOOL: return CppTypeName::makePrimitive("bool"); + case schema::Type::INT8: return CppTypeName::makePrimitive(" ::int8_t"); + case schema::Type::INT16: return CppTypeName::makePrimitive(" ::int16_t"); + case schema::Type::INT32: return CppTypeName::makePrimitive(" ::int32_t"); + case schema::Type::INT64: return CppTypeName::makePrimitive(" ::int64_t"); + case schema::Type::UINT8: return CppTypeName::makePrimitive(" ::uint8_t"); + case schema::Type::UINT16: return CppTypeName::makePrimitive(" ::uint16_t"); + case schema::Type::UINT32: return CppTypeName::makePrimitive(" ::uint32_t"); + case schema::Type::UINT64: return CppTypeName::makePrimitive(" ::uint64_t"); + case schema::Type::FLOAT32: return CppTypeName::makePrimitive("float"); + case schema::Type::FLOAT64: return CppTypeName::makePrimitive("double"); + + case schema::Type::TEXT: return CppTypeName::makePrimitive(" ::capnp::Text"); + case schema::Type::DATA: return CppTypeName::makePrimitive(" ::capnp::Data"); + + case schema::Type::ENUM: + return cppFullName(type.asEnum(), method); + case schema::Type::STRUCT: + return cppFullName(type.asStruct(), method); + case schema::Type::INTERFACE: { + auto result = cppFullName(type.asInterface(), method); + result.setHasInterfaces(); + return result; + } + + case schema::Type::LIST: { + CppTypeName result = CppTypeName::makeNamespace("capnp"); + auto params = kj::heapArrayBuilder(1); + params.add(typeName(type.asList().getElementType(), method)); + result.addMemberTemplate("List", params.finish()); + return result; + } + + case schema::Type::ANY_POINTER: + KJ_IF_MAYBE(param, type.getBrandParameter()) { + return CppTypeName::makeTemplateParam(schemaLoader.get(param->scopeId).getProto() + .getParameters()[param->index].getName()); + } else KJ_IF_MAYBE(param, type.getImplicitParameter()) { + KJ_IF_MAYBE(m, method) { + auto params = m->getProto().getImplicitParameters(); + KJ_REQUIRE(param->index < params.size()); + return CppTypeName::makeTemplateParam(params[param->index].getName()); + } else { + return CppTypeName::makePrimitive(" ::capnp::AnyPointer"); + } + } else { + switch (type.whichAnyPointerKind()) { + case schema::Type::AnyPointer::Unconstrained::ANY_KIND: + return CppTypeName::makePrimitive(" ::capnp::AnyPointer"); + case schema::Type::AnyPointer::Unconstrained::STRUCT: + return CppTypeName::makePrimitive(" ::capnp::AnyStruct"); + case schema::Type::AnyPointer::Unconstrained::LIST: + return CppTypeName::makePrimitive(" ::capnp::AnyList"); + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + hasInterfaces = true; // Probably need to #inculde . + return CppTypeName::makePrimitive(" ::capnp::Capability"); + } + KJ_UNREACHABLE; + } + } + KJ_UNREACHABLE; + } + + template + kj::Maybe annotationValue(P proto, uint64_t annotationId) { + for (auto annotation: proto.getAnnotations()) { + if (annotation.getId() == annotationId) { + return annotation.getValue(); + } + } + return nullptr; + } + + template + kj::StringPtr protoName(P proto) { + KJ_IF_MAYBE(name, annotationValue(proto, NAME_ANNOTATION_ID)) { + return name->getText(); + } else { + return proto.getName(); + } + } + + kj::StringTree literalValue(Type type, schema::Value::Reader value) { + switch (value.which()) { + case schema::Value::VOID: return kj::strTree(" ::capnp::VOID"); + case schema::Value::BOOL: return kj::strTree(value.getBool() ? "true" : "false"); + case schema::Value::INT8: return kj::strTree(value.getInt8()); + case schema::Value::INT16: return kj::strTree(value.getInt16()); + case schema::Value::INT32: return kj::strTree(value.getInt32()); + case schema::Value::INT64: return kj::strTree(value.getInt64(), "ll"); + case schema::Value::UINT8: return kj::strTree(value.getUint8(), "u"); + case schema::Value::UINT16: return kj::strTree(value.getUint16(), "u"); + case schema::Value::UINT32: return kj::strTree(value.getUint32(), "u"); + case schema::Value::UINT64: return kj::strTree(value.getUint64(), "llu"); + case schema::Value::FLOAT32: { + auto text = kj::str(value.getFloat32()); + if (text.findFirst('.') == nullptr && + text.findFirst('e') == nullptr && + text.findFirst('E') == nullptr) { + text = kj::str(text, ".0"); + } + return kj::strTree(kj::mv(text), "f"); + } + case schema::Value::FLOAT64: return kj::strTree(value.getFloat64()); + case schema::Value::ENUM: { + EnumSchema schema = type.asEnum(); + if (value.getEnum() < schema.getEnumerants().size()) { + return kj::strTree( + cppFullName(schema, nullptr), "::", + toUpperCase(protoName(schema.getEnumerants()[value.getEnum()].getProto()))); + } else { + return kj::strTree("static_cast<", cppFullName(schema, nullptr), + ">(", value.getEnum(), ")"); + } + } + + case schema::Value::TEXT: + case schema::Value::DATA: + case schema::Value::STRUCT: + case schema::Value::INTERFACE: + case schema::Value::LIST: + case schema::Value::ANY_POINTER: + KJ_FAIL_REQUIRE("literalValue() can only be used on primitive types."); + } + KJ_UNREACHABLE; + } + + // ----------------------------------------------------------------- + + class TemplateContext { + public: + TemplateContext(): parent(nullptr) {} + explicit TemplateContext(schema::Node::Reader node) + : parent(nullptr), node(node) {} + TemplateContext(const TemplateContext& parent, kj::StringPtr name, schema::Node::Reader node) + : parent(parent), name(name), node(node) {} + + bool hasParams() const { + return node.getParameters().size() > 0; + } + bool isGeneric() const { + return node.getIsGeneric(); + } + kj::Maybe getParent() const { + return parent; + } + kj::StringPtr getName() const { return name; } + + kj::StringTree decl(bool withDefaults, kj::StringPtr suffix = nullptr) const { + // "template " for this type. Includes default assignments + // ("= ::capnp::AnyPointer") if `withDefaults` is true. Returns empty string if this type + // is not parameterized. + + auto params = node.getParameters(); + + if (params.size() == 0) { + return kj::strTree(); + } else { + return kj::strTree( + "template <", kj::StringTree(KJ_MAP(p, params) { + return kj::strTree("typename ", p.getName(), suffix, + withDefaults ? " = ::capnp::AnyPointer" : ""); + }, ", "), ">\n"); + } + } + + kj::StringTree allDecls() const { + // Decl for each generic parent plus this type, one per line. + return kj::strTree(parentDecls(), decl(false)); + } + + kj::StringTree parentDecls() const { + // Decls just for the parents. + KJ_IF_MAYBE(p, parent) { + return p->allDecls(); + } else { + return kj::strTree(); + } + } + + kj::StringTree args(kj::StringPtr suffix = nullptr) const { + // "" for this type. + auto params = node.getParameters(); + + if (params.size() == 0) { + return kj::strTree(); + } else { + return kj::strTree( + "<", kj::StringTree(KJ_MAP(p, params) { + return kj::strTree(p.getName(), suffix); + }, ", "), ">"); + } + } + + kj::StringTree allArgs() const { + // "S, T, U, V" -- listing all args for all enclosing scopes starting from the outermost. + + auto params = node.getParameters(); + + kj::StringTree self(KJ_MAP(p, params) { return kj::strTree(p.getName()); }, ", "); + kj::StringTree up; + KJ_IF_MAYBE(p, parent) { + up = p->allArgs(); + } + + if (self.size() == 0) { + return up; + } else if (up.size() == 0) { + return self; + } else { + return kj::strTree(kj::mv(up), ", ", kj::mv(self)); + } + } + + std::map::Reader> getScopeMap() const { + std::map::Reader> result; + const TemplateContext* current = this; + for (;;) { + auto params = current->node.getParameters(); + if (params.size() > 0) { + result[current->node.getId()] = params; + } + KJ_IF_MAYBE(p, current->parent) { + current = p; + } else { + return result; + } + } + } + + private: + kj::Maybe parent; + kj::StringPtr name; + schema::Node::Reader node; + }; + + struct BrandInitializerText { + kj::StringTree scopes; + kj::StringTree bindings; + kj::StringTree dependencies; + size_t dependencyCount; + // TODO(msvc): `dependencyCount` is the number of individual dependency definitions in + // `dependencies`. It's a hack to allow makeGenericDefinitions to hard-code the size of the + // `_capnpPrivate::brandDependencies` array into the definition of + // `_capnpPrivate::specificBrand::dependencyCount`. This is necessary because MSVC cannot deduce + // the size of `brandDependencies` if it is nested under a class template. It's probably this + // demoralizingly deferred bug: + // https://connect.microsoft.com/VisualStudio/feedback/details/759407/can-not-get-size-of-static-array-defined-in-class-template + }; + + BrandInitializerText makeBrandInitializers( + const TemplateContext& templateContext, Schema schema) { + auto scopeMap = templateContext.getScopeMap(); + + auto scopes = kj::heapArrayBuilder(scopeMap.size()); + kj::Vector bindings(scopeMap.size() * 2); // (estimate two params per scope) + + for (auto& scope: scopeMap) { + scopes.add(kj::strTree(" { ", + "0x", kj::hex(scope.first), ", " + "brandBindings + ", bindings.size(), ", ", + scope.second.size(), ", " + "false" + "},\n")); + + for (auto param: scope.second) { + bindings.add(kj::strTree(" ::capnp::_::brandBindingFor<", param.getName(), ">(),\n")); + } + } + + auto depMap = makeBrandDepMap(templateContext, schema); + auto dependencyCount = depMap.size(); + return { + kj::strTree("{\n", scopes.finish(), "}"), + kj::strTree("{\n", bindings.releaseAsArray(), "}"), + makeBrandDepInitializers(kj::mv(depMap)), + dependencyCount + }; + } + + std::map + makeBrandDepMap(const TemplateContext& templateContext, Schema schema) { + // Build deps. This is separate from makeBrandDepInitializers to give calling code the + // opportunity to count the number of dependencies, to calculate array sizes. + std::map depMap; + +#define ADD_DEP(kind, index, ...) \ + { \ + uint location = _::RawBrandedSchema::makeDepLocation( \ + _::RawBrandedSchema::DepKind::kind, index); \ + KJ_IF_MAYBE(dep, makeBrandDepInitializer(__VA_ARGS__)) { \ + depMap[location] = kj::mv(*dep); \ + } \ + } + + switch (schema.getProto().which()) { + case schema::Node::FILE: + case schema::Node::ENUM: + case schema::Node::ANNOTATION: + break; + + case schema::Node::STRUCT: + for (auto field: schema.asStruct().getFields()) { + ADD_DEP(FIELD, field.getIndex(), field.getType()); + } + break; + case schema::Node::INTERFACE: { + auto interface = schema.asInterface(); + auto superclasses = interface.getSuperclasses(); + for (auto i: kj::indices(superclasses)) { + ADD_DEP(SUPERCLASS, i, superclasses[i]); + } + auto methods = interface.getMethods(); + for (auto i: kj::indices(methods)) { + auto method = methods[i]; + ADD_DEP(METHOD_PARAMS, i, method, method.getParamType(), "Params"); + ADD_DEP(METHOD_RESULTS, i, method, method.getResultType(), "Results"); + } + break; + } + case schema::Node::CONST: + ADD_DEP(CONST_TYPE, 0, schema.asConst().getType()); + break; + } +#undef ADD_DEP + return depMap; + } + + kj::StringTree makeBrandDepInitializers(std::map&& depMap) { + // Process depMap. Returns a braced initialiser list, or an empty string if there are no + // dependencies. + if (!depMap.size()) { + return kj::strTree(); + } + + auto deps = kj::heapArrayBuilder(depMap.size()); + for (auto& entry: depMap) { + deps.add(kj::strTree(" { ", entry.first, ", ", kj::mv(entry.second), " },\n")); + } + + return kj::strTree("{\n", kj::StringTree(deps.finish(), ""), "}"); + } + + kj::Maybe makeBrandDepInitializer(Schema type) { + return makeBrandDepInitializer(type, cppFullName(type, nullptr)); + } + + kj::Maybe makeBrandDepInitializer( + InterfaceSchema::Method method, StructSchema type, kj::StringPtr suffix) { + auto typeProto = type.getProto(); + if (typeProto.getScopeId() == 0) { + // This is an auto-generated params or results type. + auto name = cppFullName(method.getContainingInterface(), nullptr); + auto memberTypeName = kj::str(toTitleCase(protoName(method.getProto())), suffix); + + if (typeProto.getParameters().size() == 0) { + name.addMemberType(memberTypeName); + } else { + // The method has implicit parameters (i.e. it's generic). For the purpose of the brand + // dep initializer, we only want to supply the default AnyPointer variant, so just don't + // pass any parameters here. + name.addMemberTemplate(memberTypeName, nullptr); + } + return makeBrandDepInitializer(type, kj::mv(name)); + } else { + return makeBrandDepInitializer(type); + } + } + + kj::Maybe makeBrandDepInitializer(Schema type, CppTypeName name) { + if (type.isBranded()) { + name.addMemberType("_capnpPrivate"); + name.addMemberValue("brand"); + return kj::strTree(name, "()"); + } else { + return nullptr; + } + } + + kj::Maybe makeBrandDepInitializer(Type type) { + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::ENUM: + case schema::Type::ANY_POINTER: + return nullptr; + + case schema::Type::STRUCT: + return makeBrandDepInitializer(type.asStruct()); + case schema::Type::INTERFACE: + return makeBrandDepInitializer(type.asInterface()); + case schema::Type::LIST: + return makeBrandDepInitializer(type.asList().getElementType()); + } + + KJ_UNREACHABLE; + } + + // ----------------------------------------------------------------- + // Code to deal with "slots" -- determines what to zero out when we clear a group. + + static uint typeSizeBits(schema::Type::Which whichType) { + switch (whichType) { + case schema::Type::BOOL: return 1; + case schema::Type::INT8: return 8; + case schema::Type::INT16: return 16; + case schema::Type::INT32: return 32; + case schema::Type::INT64: return 64; + case schema::Type::UINT8: return 8; + case schema::Type::UINT16: return 16; + case schema::Type::UINT32: return 32; + case schema::Type::UINT64: return 64; + case schema::Type::FLOAT32: return 32; + case schema::Type::FLOAT64: return 64; + case schema::Type::ENUM: return 16; + + case schema::Type::VOID: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("Should only be called for data types."); + } + KJ_UNREACHABLE; + } + + enum class Section { + NONE, + DATA, + POINTERS + }; + + static Section sectionFor(schema::Type::Which whichType) { + switch (whichType) { + case schema::Type::VOID: + return Section::NONE; + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + return Section::DATA; + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + return Section::POINTERS; + } + KJ_UNREACHABLE; + } + + static kj::StringPtr maskType(schema::Type::Which whichType) { + switch (whichType) { + case schema::Type::BOOL: return "bool"; + case schema::Type::INT8: return " ::uint8_t"; + case schema::Type::INT16: return " ::uint16_t"; + case schema::Type::INT32: return " ::uint32_t"; + case schema::Type::INT64: return " ::uint64_t"; + case schema::Type::UINT8: return " ::uint8_t"; + case schema::Type::UINT16: return " ::uint16_t"; + case schema::Type::UINT32: return " ::uint32_t"; + case schema::Type::UINT64: return " ::uint64_t"; + case schema::Type::FLOAT32: return " ::uint32_t"; + case schema::Type::FLOAT64: return " ::uint64_t"; + case schema::Type::ENUM: return " ::uint16_t"; + + case schema::Type::VOID: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("Should only be called for data types."); + } + KJ_UNREACHABLE; + } + + struct Slot { + schema::Type::Which whichType; + uint offset; + + bool isSupersetOf(Slot other) const { + auto section = sectionFor(whichType); + if (section != sectionFor(other.whichType)) return false; + switch (section) { + case Section::NONE: + return true; // all voids overlap + case Section::DATA: { + auto bits = typeSizeBits(whichType); + auto start = offset * bits; + auto otherBits = typeSizeBits(other.whichType); + auto otherStart = other.offset * otherBits; + return start <= otherStart && otherStart + otherBits <= start + bits; + } + case Section::POINTERS: + return offset == other.offset; + } + KJ_UNREACHABLE; + } + + bool operator<(Slot other) const { + // Sort by section, then start position, and finally size. + + auto section = sectionFor(whichType); + auto otherSection = sectionFor(other.whichType); + if (section < otherSection) { + return true; + } else if (section > otherSection) { + return false; + } + + switch (section) { + case Section::NONE: + return false; + case Section::DATA: { + auto bits = typeSizeBits(whichType); + auto start = offset * bits; + auto otherBits = typeSizeBits(other.whichType); + auto otherStart = other.offset * otherBits; + if (start < otherStart) { + return true; + } else if (start > otherStart) { + return false; + } + + // Sort larger sizes before smaller. + return bits > otherBits; + } + case Section::POINTERS: + return offset < other.offset; + } + KJ_UNREACHABLE; + } + }; + + void getSlots(StructSchema schema, kj::Vector& slots) { + auto structProto = schema.getProto().getStruct(); + if (structProto.getDiscriminantCount() > 0) { + slots.add(Slot { schema::Type::UINT16, structProto.getDiscriminantOffset() }); + } + + for (auto field: schema.getFields()) { + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + slots.add(Slot { slot.getType().which(), slot.getOffset() }); + break; + } + case schema::Field::GROUP: + getSlots(field.getType().asStruct(), slots); + break; + } + } + } + + kj::Array getSortedSlots(StructSchema schema) { + // Get a representation of all of the field locations owned by this schema, e.g. so that they + // can be zero'd out. + + kj::Vector slots(schema.getFields().size()); + getSlots(schema, slots); + std::sort(slots.begin(), slots.end()); + + kj::Vector result(slots.size()); + + // All void slots are redundant, and they sort towards the front of the list. By starting out + // with `prevSlot` = void, we will end up skipping them all, which is what we want. + Slot prevSlot = { schema::Type::VOID, 0 }; + for (auto slot: slots) { + if (prevSlot.isSupersetOf(slot)) { + // This slot is redundant as prevSlot is a superset of it. + continue; + } + + // Since all sizes are power-of-two, if two slots overlap at all, one must be a superset of + // the other. Since we sort slots by starting position, we know that the only way `slot` + // could be a superset of `prevSlot` is if they have the same starting position. However, + // since we sort slots with the same starting position by descending size, this is not + // possible. + KJ_DASSERT(!slot.isSupersetOf(prevSlot)); + + result.add(slot); + + prevSlot = slot; + } + + return result.releaseAsArray(); + } + + // ----------------------------------------------------------------- + + struct DiscriminantChecks { + kj::String has; + kj::String check; + kj::String set; + kj::StringTree readerIsDecl; + kj::StringTree builderIsDecl; + kj::StringTree isDefs; + }; + + DiscriminantChecks makeDiscriminantChecks(kj::StringPtr scope, + kj::StringPtr memberName, + StructSchema containingStruct, + const TemplateContext& templateContext) { + auto discrimOffset = containingStruct.getProto().getStruct().getDiscriminantOffset(); + + kj::String titleCase = toTitleCase(memberName); + kj::String upperCase = toUpperCase(memberName); + + return DiscriminantChecks { + kj::str( + " if (which() != ", scope, upperCase, ") return false;\n"), + kj::str( + // Extra parens around the condition are needed for when we're compiling a multi-arg + // generic type, which will have a comma, which would otherwise mess up the macro. + // Ah, C++. + " KJ_IREQUIRE((which() == ", scope, upperCase, "),\n" + " \"Must check which() before get()ing a union member.\");\n"), + kj::str( + " _builder.setDataField<", scope, "Which>(\n" + " ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS, ", + scope, upperCase, ");\n"), + kj::strTree(" inline bool is", titleCase, "() const;\n"), + kj::strTree(" inline bool is", titleCase, "();\n"), + kj::strTree( + templateContext.allDecls(), + "inline bool ", scope, "Reader::is", titleCase, "() const {\n" + " return which() == ", scope, upperCase, ";\n" + "}\n", + templateContext.allDecls(), + "inline bool ", scope, "Builder::is", titleCase, "() {\n" + " return which() == ", scope, upperCase, ";\n" + "}\n") + }; + } + + // ----------------------------------------------------------------- + + struct FieldText { + kj::StringTree readerMethodDecls; + kj::StringTree builderMethodDecls; + kj::StringTree pipelineMethodDecls; + kj::StringTree inlineMethodDefs; + }; + + enum class FieldKind { + PRIMITIVE, + BLOB, + STRUCT, + LIST, + INTERFACE, + ANY_POINTER, + BRAND_PARAMETER + }; + + FieldText makeFieldText(kj::StringPtr scope, StructSchema::Field field, + const TemplateContext& templateContext) { + auto proto = field.getProto(); + auto typeSchema = field.getType(); + auto baseName = protoName(proto); + kj::String titleCase = toTitleCase(baseName); + + DiscriminantChecks unionDiscrim; + if (hasDiscriminantValue(proto)) { + unionDiscrim = makeDiscriminantChecks(scope, baseName, field.getContainingStruct(), + templateContext); + } + + switch (proto.which()) { + case schema::Field::SLOT: + // Continue below. + break; + + case schema::Field::GROUP: { + auto slots = getSortedSlots(field.getType().asStruct()); + return FieldText { + kj::strTree( + kj::mv(unionDiscrim.readerIsDecl), + " inline typename ", titleCase, "::Reader get", titleCase, "() const;\n" + "\n"), + + kj::strTree( + kj::mv(unionDiscrim.builderIsDecl), + " inline typename ", titleCase, "::Builder get", titleCase, "();\n" + " inline typename ", titleCase, "::Builder init", titleCase, "();\n" + "\n"), + + hasDiscriminantValue(proto) ? kj::strTree() : + kj::strTree(" inline typename ", titleCase, "::Pipeline get", titleCase, "();\n"), + + kj::strTree( + kj::mv(unionDiscrim.isDefs), + templateContext.allDecls(), + "inline typename ", scope, titleCase, "::Reader ", scope, "Reader::get", titleCase, "() const {\n", + unionDiscrim.check, + " return typename ", scope, titleCase, "::Reader(_reader);\n" + "}\n", + templateContext.allDecls(), + "inline typename ", scope, titleCase, "::Builder ", scope, "Builder::get", titleCase, "() {\n", + unionDiscrim.check, + " return typename ", scope, titleCase, "::Builder(_builder);\n" + "}\n", + hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree( + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "inline typename ", scope, titleCase, "::Pipeline ", scope, "Pipeline::get", titleCase, "() {\n", + " return typename ", scope, titleCase, "::Pipeline(_typeless.noop());\n" + "}\n" + "#endif // !CAPNP_LITE\n"), + templateContext.allDecls(), + "inline typename ", scope, titleCase, "::Builder ", scope, "Builder::init", titleCase, "() {\n", + unionDiscrim.set, + KJ_MAP(slot, slots) { + switch (sectionFor(slot.whichType)) { + case Section::NONE: + return kj::strTree(); + case Section::DATA: + return kj::strTree( + " _builder.setDataField<", maskType(slot.whichType), ">(::capnp::bounded<", + slot.offset, ">() * ::capnp::ELEMENTS, 0);\n"); + case Section::POINTERS: + return kj::strTree( + " _builder.getPointerField(::capnp::bounded<", slot.offset, + ">() * ::capnp::POINTERS).clear();\n"); + } + KJ_UNREACHABLE; + }, + " return typename ", scope, titleCase, "::Builder(_builder);\n" + "}\n") + }; + } + } + + auto slot = proto.getSlot(); + + FieldKind kind = FieldKind::PRIMITIVE; + kj::String ownedType; + CppTypeName type = typeName(typeSchema, nullptr); + kj::StringPtr setterDefault; // only for void + kj::String defaultMask; // primitives only + size_t defaultOffset = 0; // pointers only: offset of the default value within the schema. + size_t defaultSize = 0; // blobs only: byte size of the default value. + + auto defaultBody = slot.getDefaultValue(); + switch (typeSchema.which()) { + case schema::Type::VOID: + kind = FieldKind::PRIMITIVE; + setterDefault = " = ::capnp::VOID"; + break; + +#define HANDLE_PRIMITIVE(discrim, typeName, defaultName, suffix) \ + case schema::Type::discrim: \ + kind = FieldKind::PRIMITIVE; \ + if (defaultBody.get##defaultName() != 0) { \ + defaultMask = kj::str(defaultBody.get##defaultName(), #suffix); \ + } \ + break; + + HANDLE_PRIMITIVE(BOOL, bool, Bool, ); + HANDLE_PRIMITIVE(INT8 , ::int8_t , Int8 , ); + HANDLE_PRIMITIVE(INT16, ::int16_t, Int16, ); + HANDLE_PRIMITIVE(INT32, ::int32_t, Int32, ); + HANDLE_PRIMITIVE(INT64, ::int64_t, Int64, ll); + HANDLE_PRIMITIVE(UINT8 , ::uint8_t , Uint8 , u); + HANDLE_PRIMITIVE(UINT16, ::uint16_t, Uint16, u); + HANDLE_PRIMITIVE(UINT32, ::uint32_t, Uint32, u); + HANDLE_PRIMITIVE(UINT64, ::uint64_t, Uint64, ull); +#undef HANDLE_PRIMITIVE + + case schema::Type::FLOAT32: + kind = FieldKind::PRIMITIVE; + if (defaultBody.getFloat32() != 0) { + uint32_t mask; + float value = defaultBody.getFloat32(); + static_assert(sizeof(mask) == sizeof(value), "bug"); + memcpy(&mask, &value, sizeof(mask)); + defaultMask = kj::str(mask, "u"); + } + break; + + case schema::Type::FLOAT64: + kind = FieldKind::PRIMITIVE; + if (defaultBody.getFloat64() != 0) { + uint64_t mask; + double value = defaultBody.getFloat64(); + static_assert(sizeof(mask) == sizeof(value), "bug"); + memcpy(&mask, &value, sizeof(mask)); + defaultMask = kj::str(mask, "ull"); + } + break; + + case schema::Type::TEXT: + kind = FieldKind::BLOB; + if (defaultBody.hasText()) { + defaultOffset = field.getDefaultValueSchemaOffset(); + defaultSize = defaultBody.getText().size(); + } + break; + case schema::Type::DATA: + kind = FieldKind::BLOB; + if (defaultBody.hasData()) { + defaultOffset = field.getDefaultValueSchemaOffset(); + defaultSize = defaultBody.getData().size(); + } + break; + + case schema::Type::ENUM: + kind = FieldKind::PRIMITIVE; + if (defaultBody.getEnum() != 0) { + defaultMask = kj::str(defaultBody.getEnum(), "u"); + } + break; + + case schema::Type::STRUCT: + kind = FieldKind::STRUCT; + if (defaultBody.hasStruct()) { + defaultOffset = field.getDefaultValueSchemaOffset(); + } + break; + case schema::Type::LIST: + kind = FieldKind::LIST; + if (defaultBody.hasList()) { + defaultOffset = field.getDefaultValueSchemaOffset(); + } + break; + case schema::Type::INTERFACE: + kind = FieldKind::INTERFACE; + break; + case schema::Type::ANY_POINTER: + if (defaultBody.hasAnyPointer()) { + defaultOffset = field.getDefaultValueSchemaOffset(); + } + if (typeSchema.getBrandParameter() != nullptr) { + kind = FieldKind::BRAND_PARAMETER; + } else { + kind = FieldKind::ANY_POINTER; + switch (typeSchema.whichAnyPointerKind()) { + case schema::Type::AnyPointer::Unconstrained::ANY_KIND: + kind = FieldKind::ANY_POINTER; + break; + case schema::Type::AnyPointer::Unconstrained::STRUCT: + kind = FieldKind::STRUCT; + break; + case schema::Type::AnyPointer::Unconstrained::LIST: + kind = FieldKind::LIST; + break; + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + kind = FieldKind::INTERFACE; + break; + } + } + break; + } + + kj::String defaultMaskParam; + if (defaultMask.size() > 0) { + defaultMaskParam = kj::str(", ", defaultMask); + } + + uint offset = slot.getOffset(); + + if (kind == FieldKind::PRIMITIVE) { + return FieldText { + kj::strTree( + kj::mv(unionDiscrim.readerIsDecl), + " inline ", type, " get", titleCase, "() const;\n" + "\n"), + + kj::strTree( + kj::mv(unionDiscrim.builderIsDecl), + " inline ", type, " get", titleCase, "();\n" + " inline void set", titleCase, "(", type, " value", setterDefault, ");\n" + "\n"), + + kj::strTree(), + + kj::strTree( + kj::mv(unionDiscrim.isDefs), + templateContext.allDecls(), + "inline ", type, " ", scope, "Reader::get", titleCase, "() const {\n", + unionDiscrim.check, + " return _reader.getDataField<", type, ">(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS", defaultMaskParam, ");\n", + "}\n" + "\n", + templateContext.allDecls(), + "inline ", type, " ", scope, "Builder::get", titleCase, "() {\n", + unionDiscrim.check, + " return _builder.getDataField<", type, ">(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS", defaultMaskParam, ");\n", + "}\n", + templateContext.allDecls(), + "inline void ", scope, "Builder::set", titleCase, "(", type, " value) {\n", + unionDiscrim.set, + " _builder.setDataField<", type, ">(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS, value", defaultMaskParam, ");\n", + "}\n" + "\n") + }; + + } else if (kind == FieldKind::INTERFACE) { + CppTypeName clientType = type; + clientType.addMemberType("Client"); + + return FieldText { + kj::strTree( + kj::mv(unionDiscrim.readerIsDecl), + " inline bool has", titleCase, "() const;\n" + "#if !CAPNP_LITE\n" + " inline ", clientType, " get", titleCase, "() const;\n" + "#endif // !CAPNP_LITE\n" + "\n"), + + kj::strTree( + kj::mv(unionDiscrim.builderIsDecl), + " inline bool has", titleCase, "();\n" + "#if !CAPNP_LITE\n" + " inline ", clientType, " get", titleCase, "();\n" + " inline void set", titleCase, "(", clientType, "&& value);\n", + " inline void set", titleCase, "(", clientType, "& value);\n", + " inline void adopt", titleCase, "(::capnp::Orphan<", type, ">&& value);\n" + " inline ::capnp::Orphan<", type, "> disown", titleCase, "();\n" + "#endif // !CAPNP_LITE\n" + "\n"), + + kj::strTree( + hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree( + " inline ", clientType, " get", titleCase, "();\n")), + + kj::strTree( + kj::mv(unionDiscrim.isDefs), + templateContext.allDecls(), + "inline bool ", scope, "Reader::has", titleCase, "() const {\n", + unionDiscrim.has, + " return !_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n", + templateContext.allDecls(), + "inline bool ", scope, "Builder::has", titleCase, "() {\n", + unionDiscrim.has, + " return !_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n" + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "inline ", clientType, " ", scope, "Reader::get", titleCase, "() const {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::get(_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n", + templateContext.allDecls(), + "inline ", clientType, " ", scope, "Builder::get", titleCase, "() {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::get(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n", + hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree( + templateContext.allDecls(), + "inline ", clientType, " ", scope, "Pipeline::get", titleCase, "() {\n", + " return ", clientType, "(_typeless.getPointerField(", offset, ").asCap());\n" + "}\n"), + templateContext.allDecls(), + "inline void ", scope, "Builder::set", titleCase, "(", clientType, "&& cap) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(cap));\n" + "}\n", + templateContext.allDecls(), + "inline void ", scope, "Builder::set", titleCase, "(", clientType, "& cap) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), cap);\n" + "}\n", + templateContext.allDecls(), + "inline void ", scope, "Builder::adopt", titleCase, "(\n" + " ::capnp::Orphan<", type, ">&& value) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::adopt(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(value));\n" + "}\n", + templateContext.allDecls(), + "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::disown(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n" + "#endif // !CAPNP_LITE\n" + "\n") + }; + + } else if (kind == FieldKind::ANY_POINTER) { + return FieldText { + kj::strTree( + kj::mv(unionDiscrim.readerIsDecl), + " inline bool has", titleCase, "() const;\n" + " inline ::capnp::AnyPointer::Reader get", titleCase, "() const;\n" + "\n"), + + kj::strTree( + kj::mv(unionDiscrim.builderIsDecl), + " inline bool has", titleCase, "();\n" + " inline ::capnp::AnyPointer::Builder get", titleCase, "();\n" + " inline ::capnp::AnyPointer::Builder init", titleCase, "();\n" + "\n"), + + kj::strTree(), + + kj::strTree( + kj::mv(unionDiscrim.isDefs), + templateContext.allDecls(), + "inline bool ", scope, "Reader::has", titleCase, "() const {\n", + unionDiscrim.has, + " return !_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n", + templateContext.allDecls(), + "inline bool ", scope, "Builder::has", titleCase, "() {\n", + unionDiscrim.has, + " return !_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n", + templateContext.allDecls(), + "inline ::capnp::AnyPointer::Reader ", scope, "Reader::get", titleCase, "() const {\n", + unionDiscrim.check, + " return ::capnp::AnyPointer::Reader(_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n", + templateContext.allDecls(), + "inline ::capnp::AnyPointer::Builder ", scope, "Builder::get", titleCase, "() {\n", + unionDiscrim.check, + " return ::capnp::AnyPointer::Builder(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n", + templateContext.allDecls(), + "inline ::capnp::AnyPointer::Builder ", scope, "Builder::init", titleCase, "() {\n", + unionDiscrim.set, + " auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + " result.clear();\n" + " return result;\n" + "}\n" + "\n") + }; + + } else { + // Blob, struct, list, or template param. These have only minor differences. + + uint64_t typeId = field.getContainingStruct().getProto().getId(); + kj::String defaultParam = defaultOffset == 0 ? kj::str() : kj::str( + ",\n ::capnp::schemas::bp_", kj::hex(typeId), " + ", defaultOffset, + defaultSize == 0 ? kj::strTree() : kj::strTree(", ", defaultSize)); + + bool shouldIncludeStructInit = + kind == FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER; + bool shouldIncludeSizedInit = + kind != FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER; + bool shouldIncludePipelineGetter = !hasDiscriminantValue(proto) && + (kind == FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER); + bool shouldIncludeArrayInitializer = false; + bool shouldExcludeInLiteMode = type.hasInterfaces(); + bool shouldTemplatizeInit = typeSchema.which() == schema::Type::ANY_POINTER && + kind != FieldKind::BRAND_PARAMETER; + + CppTypeName elementReaderType; + if (typeSchema.isList()) { + bool primitiveElement = false; + bool interface = false; + auto elementType = typeSchema.asList().getElementType(); + switch (elementType.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + primitiveElement = true; + shouldIncludeArrayInitializer = true; + break; + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + primitiveElement = false; + shouldIncludeArrayInitializer = true; + break; + + case schema::Type::ANY_POINTER: + primitiveElement = false; + shouldIncludeArrayInitializer = elementType.getBrandParameter() != nullptr; + break; + + case schema::Type::INTERFACE: + primitiveElement = false; + interface = true; + break; + + case schema::Type::STRUCT: + primitiveElement = false; + break; + } + elementReaderType = typeName(elementType, nullptr); + if (!primitiveElement) { + if (interface) { + elementReaderType.addMemberType("Client"); + } else { + elementReaderType.addMemberType("Reader"); + } + } + }; + + CppTypeName readerType; + CppTypeName builderType; + CppTypeName pipelineType; + if (kind == FieldKind::BRAND_PARAMETER) { + readerType = CppTypeName::makeNamespace("capnp"); + readerType.addMemberTemplate("ReaderFor", kj::heapArray(&type, 1)); + builderType = CppTypeName::makeNamespace("capnp"); + builderType.addMemberTemplate("BuilderFor", kj::heapArray(&type, 1)); + pipelineType = CppTypeName::makeNamespace("capnp"); + pipelineType.addMemberTemplate("PipelineFor", kj::heapArray(&type, 1)); + } else { + readerType = type; + readerType.addMemberType("Reader"); + builderType = type; + builderType.addMemberType("Builder"); + pipelineType = type; + pipelineType.addMemberType("Pipeline"); + } + + #define COND(cond, ...) ((cond) ? kj::strTree(__VA_ARGS__) : kj::strTree()) + + return FieldText { + kj::strTree( + kj::mv(unionDiscrim.readerIsDecl), + " inline bool has", titleCase, "() const;\n", + COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"), + " inline ", readerType, " get", titleCase, "() const;\n", + COND(shouldExcludeInLiteMode, "#endif // !CAPNP_LITE\n"), + "\n"), + + kj::strTree( + kj::mv(unionDiscrim.builderIsDecl), + " inline bool has", titleCase, "();\n", + COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"), + " inline ", builderType, " get", titleCase, "();\n" + " inline void set", titleCase, "(", readerType, " value);\n", + COND(shouldIncludeArrayInitializer, + " inline void set", titleCase, "(::kj::ArrayPtr value);\n"), + COND(shouldIncludeStructInit, + COND(shouldTemplatizeInit, + " template \n" + " inline ::capnp::BuilderFor init", titleCase, "As();\n"), + COND(!shouldTemplatizeInit, + " inline ", builderType, " init", titleCase, "();\n")), + COND(shouldIncludeSizedInit, + COND(shouldTemplatizeInit, + " template \n" + " inline ::capnp::BuilderFor init", titleCase, "As(unsigned int size);\n"), + COND(!shouldTemplatizeInit, + " inline ", builderType, " init", titleCase, "(unsigned int size);\n")), + " inline void adopt", titleCase, "(::capnp::Orphan<", type, ">&& value);\n" + " inline ::capnp::Orphan<", type, "> disown", titleCase, "();\n", + COND(shouldExcludeInLiteMode, "#endif // !CAPNP_LITE\n"), + "\n"), + + kj::strTree( + COND(shouldIncludePipelineGetter, + " inline ", pipelineType, " get", titleCase, "();\n")), + + kj::strTree( + kj::mv(unionDiscrim.isDefs), + templateContext.allDecls(), + "inline bool ", scope, "Reader::has", titleCase, "() const {\n", + unionDiscrim.has, + " return !_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n", + templateContext.allDecls(), + "inline bool ", scope, "Builder::has", titleCase, "() {\n", + unionDiscrim.has, + " return !_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n" + "}\n", + COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"), + templateContext.allDecls(), + "inline ", readerType, " ", scope, "Reader::get", titleCase, "() const {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::get(_reader.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS)", defaultParam, ");\n" + "}\n", + templateContext.allDecls(), + "inline ", builderType, " ", scope, "Builder::get", titleCase, "() {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::get(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS)", defaultParam, ");\n" + "}\n", + COND(shouldIncludePipelineGetter, + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "inline ", pipelineType, " ", scope, "Pipeline::get", titleCase, "() {\n", + " return ", pipelineType, "(_typeless.getPointerField(", offset, "));\n" + "}\n" + "#endif // !CAPNP_LITE\n"), + templateContext.allDecls(), + "inline void ", scope, "Builder::set", titleCase, "(", readerType, " value) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), value);\n" + "}\n", + COND(shouldIncludeArrayInitializer, + templateContext.allDecls(), + "inline void ", scope, "Builder::set", titleCase, "(::kj::ArrayPtr value) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), value);\n" + "}\n"), + COND(shouldIncludeStructInit, + COND(shouldTemplatizeInit, + templateContext.allDecls(), + "template \n" + "inline ::capnp::BuilderFor ", scope, "Builder::init", titleCase, "As() {\n", + " static_assert(::capnp::kind() == ::capnp::Kind::STRUCT,\n" + " \"", proto.getName(), " must be a struct\");\n", + unionDiscrim.set, + " return ::capnp::_::PointerHelpers::init(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n"), + COND(!shouldTemplatizeInit, + templateContext.allDecls(), + "inline ", builderType, " ", scope, "Builder::init", titleCase, "() {\n", + unionDiscrim.set, + " return ::capnp::_::PointerHelpers<", type, ">::init(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n")), + COND(shouldIncludeSizedInit, + COND(shouldTemplatizeInit, + templateContext.allDecls(), + "template \n" + "inline ::capnp::BuilderFor ", scope, "Builder::init", titleCase, "As(unsigned int size) {\n", + " static_assert(::capnp::kind() == ::capnp::Kind::LIST,\n" + " \"", proto.getName(), " must be a list\");\n", + unionDiscrim.set, + " return ::capnp::_::PointerHelpers::init(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), size);\n" + "}\n"), + COND(!shouldTemplatizeInit, + templateContext.allDecls(), + "inline ", builderType, " ", scope, "Builder::init", titleCase, "(unsigned int size) {\n", + unionDiscrim.set, + " return ::capnp::_::PointerHelpers<", type, ">::init(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), size);\n" + "}\n")), + templateContext.allDecls(), + "inline void ", scope, "Builder::adopt", titleCase, "(\n" + " ::capnp::Orphan<", type, ">&& value) {\n", + unionDiscrim.set, + " ::capnp::_::PointerHelpers<", type, ">::adopt(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(value));\n" + "}\n", + COND(type.hasDisambiguatedTemplate(), + "#ifndef _MSC_VER\n" + "// Excluded under MSVC because bugs may make it unable to compile this method.\n"), + templateContext.allDecls(), + "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n", + unionDiscrim.check, + " return ::capnp::_::PointerHelpers<", type, ">::disown(_builder.getPointerField(\n" + " ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n" + "}\n", + COND(type.hasDisambiguatedTemplate(), "#endif // !_MSC_VER\n"), + COND(shouldExcludeInLiteMode, "#endif // !CAPNP_LITE\n"), + "\n") + }; + + #undef COND + } + } + + // ----------------------------------------------------------------- + + enum class AsGenericRole { READER, BUILDER, CLIENT }; + + kj::StringTree makeAsGenericDef(AsGenericRole role, const TemplateContext& templateContext, + kj::StringPtr type, kj::String innerType = kj::String()) { + if (!templateContext.isGeneric()) { + return kj::StringTree(); + } + kj::StringTree self, up; + if (templateContext.hasParams()) { + auto returnType = [&]() { + return kj::strTree(type, templateContext.args("2"), innerType); + }; + kj::StringTree asGeneric = kj::strTree("as", innerType.size() ? type : "", "Generic()"); + switch (role) { + case AsGenericRole::READER: + self = kj::strTree( + " ", templateContext.decl(true, "2"), + " typename ", returnType(), "::Reader ", kj::mv(asGeneric), " {\n" + " return typename ", returnType(), "::Reader(_reader);\n" + " }\n" + "\n"); + break; + case AsGenericRole::BUILDER: + self = kj::strTree( + " ", templateContext.decl(true, "2"), + " typename ", returnType(), "::Builder ", kj::mv(asGeneric), " {\n" + " return typename ", returnType(), "::Builder(_builder);\n" + " }\n" + "\n"); + break; + case AsGenericRole::CLIENT: + self = kj::strTree( + " ", templateContext.decl(true, "2"), + " typename ", returnType(), "::Client ", kj::mv(asGeneric), " {\n" + " return castAs<", innerType.size() ? "typename " : "", returnType(), ">();\n" + " }\n" + "\n"); + break; + } + } + KJ_IF_MAYBE(p, templateContext.getParent()) { + up = makeAsGenericDef(role, *p, p->getName(), kj::strTree( + templateContext.hasParams() ? "::template " : "::", type, + templateContext.args()).flatten()); + } + return kj::strTree(kj::mv(self), kj::mv(up)); + } + + // ----------------------------------------------------------------- + + struct StructText { + kj::StringTree outerTypeDecl; + kj::StringTree outerTypeDef; + kj::StringTree readerBuilderDefs; + kj::StringTree inlineMethodDefs; + kj::StringTree sourceDefs; + }; + + kj::StringTree makeReaderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, + const TemplateContext& templateContext, bool isUnion, + kj::Array&& methodDecls) { + return kj::strTree( + templateContext.allDecls(), + "class ", fullName, "::Reader {\n" + "public:\n" + " typedef ", unqualifiedParentType, " Reads;\n" + "\n" + " Reader() = default;\n" + " inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}\n" + "\n" + " inline ::capnp::MessageSize totalSize() const {\n" + " return _reader.totalSize().asPublic();\n" + " }\n" + "\n" + "#if !CAPNP_LITE\n" + " inline ::kj::StringTree toString() const {\n" + " return ::capnp::_::structString(_reader, *_capnpPrivate::brand());\n" + " }\n" + "#endif // !CAPNP_LITE\n" + "\n", + makeAsGenericDef(AsGenericRole::READER, templateContext, unqualifiedParentType), + isUnion ? kj::strTree(" inline Which which() const;\n") : kj::strTree(), + kj::mv(methodDecls), + "private:\n" + " ::capnp::_::StructReader _reader;\n" + " template \n" + " friend struct ::capnp::ToDynamic_;\n" + " template \n" + " friend struct ::capnp::_::PointerHelpers;\n" + " template \n" + " friend struct ::capnp::List;\n" + " friend class ::capnp::MessageBuilder;\n" + " friend class ::capnp::Orphanage;\n" + "};\n" + "\n"); + } + + kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, + const TemplateContext& templateContext, bool isUnion, + kj::Array&& methodDecls) { + return kj::strTree( + templateContext.allDecls(), + "class ", fullName, "::Builder {\n" + "public:\n" + " typedef ", unqualifiedParentType, " Builds;\n" + "\n" + " Builder() = delete; // Deleted to discourage incorrect usage.\n" + " // You can explicitly initialize to nullptr instead.\n" + " inline Builder(decltype(nullptr)) {}\n" + " inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}\n" + " inline operator Reader() const { return Reader(_builder.asReader()); }\n" + " inline Reader asReader() const { return *this; }\n" + "\n" + " inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }\n" + "#if !CAPNP_LITE\n" + " inline ::kj::StringTree toString() const { return asReader().toString(); }\n" + "#endif // !CAPNP_LITE\n" + "\n", + makeAsGenericDef(AsGenericRole::BUILDER, templateContext, unqualifiedParentType), + isUnion ? kj::strTree(" inline Which which();\n") : kj::strTree(), + kj::mv(methodDecls), + "private:\n" + " ::capnp::_::StructBuilder _builder;\n" + " template \n" + " friend struct ::capnp::ToDynamic_;\n" + " friend class ::capnp::Orphanage;\n", + " template \n" + " friend struct ::capnp::_::PointerHelpers;\n" + "};\n" + "\n"); + } + + kj::StringTree makePipelineDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, + const TemplateContext& templateContext, bool isUnion, + kj::Array&& methodDecls) { + return kj::strTree( + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "class ", fullName, "::Pipeline {\n" + "public:\n" + " typedef ", unqualifiedParentType, " Pipelines;\n" + "\n" + " inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}\n" + " inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)\n" + " : _typeless(kj::mv(typeless)) {}\n" + "\n", + kj::mv(methodDecls), + "private:\n" + " ::capnp::AnyPointer::Pipeline _typeless;\n" + " friend class ::capnp::PipelineHook;\n" + " template \n" + " friend struct ::capnp::ToDynamic_;\n" + "};\n" + "#endif // !CAPNP_LITE\n" + "\n"); + } + + kj::StringTree makeGenericDeclarations(const TemplateContext& templateContext, + bool hasBrandDependencies) { + // Returns the declarations for the private members of a generic struct/interface; + // paired with the definitions from makeGenericDefinitions(). + return kj::strTree( + " static const ::capnp::_::RawBrandedSchema::Scope brandScopes[];\n" + " static const ::capnp::_::RawBrandedSchema::Binding brandBindings[];\n", + (!hasBrandDependencies ? "" : + " static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[];\n"), + " static const ::capnp::_::RawBrandedSchema specificBrand;\n" + " static constexpr ::capnp::_::RawBrandedSchema const* brand() { " + "return ::capnp::_::ChooseBrand<_capnpPrivate, ", templateContext.allArgs(), ">::brand(); }\n"); + } + + kj::StringTree makeGenericDefinitions( + const TemplateContext& templateContext, kj::StringPtr fullName, kj::StringPtr hexId, + BrandInitializerText brandInitializers) { + // Returns the definitions for the members from makeGenericDeclarations(). + bool hasBrandDependencies = (brandInitializers.dependencies.size() != 0); + + auto scopeCount = templateContext.getScopeMap().size(); + auto dependencyCount = brandInitializers.dependencyCount; + + kj::String templates = kj::str(templateContext.allDecls()); + + return kj::strTree( + templates, "const ::capnp::_::RawBrandedSchema::Scope ", fullName, + "::_capnpPrivate::brandScopes[] = ", kj::mv(brandInitializers.scopes), ";\n", + + templates, "const ::capnp::_::RawBrandedSchema::Binding ", fullName, + "::_capnpPrivate::brandBindings[] = ", kj::mv(brandInitializers.bindings), ";\n", + + (!hasBrandDependencies ? kj::strTree("") : kj::strTree( + templates, "const ::capnp::_::RawBrandedSchema::Dependency ", fullName, + "::_capnpPrivate::brandDependencies[] = ", kj::mv(brandInitializers.dependencies), + ";\n")), + + templates, "const ::capnp::_::RawBrandedSchema ", fullName, "::_capnpPrivate::specificBrand = {\n", + " &::capnp::schemas::s_", hexId, ", brandScopes, ", + (!hasBrandDependencies ? "nullptr" : "brandDependencies"), ",\n", + " ", scopeCount, ", ", dependencyCount, + ", nullptr\n" + "};\n"); + } + + StructText makeStructText(kj::StringPtr scope, kj::StringPtr name, StructSchema schema, + kj::Array nestedTypeDecls, + const TemplateContext& templateContext) { + auto proto = schema.getProto(); + KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) { + name = annotatedName->getText(); + } + auto fullName = kj::str(scope, name, templateContext.args()); + auto subScope = kj::str(fullName, "::"); + auto fieldTexts = KJ_MAP(f, schema.getFields()) { + return makeFieldText(subScope, f, templateContext); + }; + + auto structNode = proto.getStruct(); + uint discrimOffset = structNode.getDiscriminantOffset(); + auto hexId = kj::hex(proto.getId()); + + kj::String templates = kj::str(templateContext.allDecls()); // Ends with a newline + + // Private members struct + kj::StringTree declareText = kj::strTree( + " struct _capnpPrivate {\n" + " CAPNP_DECLARE_STRUCT_HEADER(", hexId, ", ", structNode.getDataWordCount(), ", ", + structNode.getPointerCount(), ")\n"); + + kj::StringTree defineText = kj::strTree( + "// ", fullName, "\n", + templates, "constexpr uint16_t ", fullName, "::_capnpPrivate::dataWordSize;\n", + templates, "constexpr uint16_t ", fullName, "::_capnpPrivate::pointerCount;\n" + "#if !CAPNP_LITE\n", + templates, "constexpr ::capnp::Kind ", fullName, "::_capnpPrivate::kind;\n", + templates, "constexpr ::capnp::_::RawSchema const* ", fullName, "::_capnpPrivate::schema;\n"); + + if (templateContext.isGeneric()) { + auto brandInitializers = makeBrandInitializers(templateContext, schema); + bool hasDeps = (brandInitializers.dependencies.size() != 0); + + declareText = kj::strTree(kj::mv(declareText), + " #if !CAPNP_LITE\n", + makeGenericDeclarations(templateContext, hasDeps), + " #endif // !CAPNP_LITE\n"); + + defineText = kj::strTree(kj::mv(defineText), + makeGenericDefinitions( + templateContext, fullName, kj::str(hexId), kj::mv(brandInitializers))); + } else { + declareText = kj::strTree(kj::mv(declareText), + " #if !CAPNP_LITE\n" + " static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }\n" + " #endif // !CAPNP_LITE\n"); + } + + declareText = kj::strTree(kj::mv(declareText), " };"); + defineText = kj::strTree(kj::mv(defineText), "#endif // !CAPNP_LITE\n\n"); + + // Name of the ::Which type, when applicable. + CppTypeName whichName; + if (structNode.getDiscriminantCount() != 0) { + whichName = cppFullName(schema, nullptr); + whichName.addMemberType("Which"); + } + + return StructText { + kj::strTree( + templateContext.hasParams() ? " " : "", templateContext.decl(true), + " struct ", name, ";\n"), + + kj::strTree( + templateContext.parentDecls(), + templateContext.decl(scope == nullptr), + "struct ", scope, name, " {\n", + " ", name, "() = delete;\n" + "\n" + " class Reader;\n" + " class Builder;\n" + " class Pipeline;\n", + structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree( + " enum Which: uint16_t {\n", + KJ_MAP(f, structNode.getFields()) { + if (hasDiscriminantValue(f)) { + return kj::strTree(" ", toUpperCase(protoName(f)), ",\n"); + } else { + return kj::strTree(); + } + }, + " };\n"), + KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, + "\n", + kj::mv(declareText), "\n", + "};\n" + "\n"), + + kj::strTree( + makeReaderDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0, + KJ_MAP(f, fieldTexts) { return kj::mv(f.readerMethodDecls); }), + makeBuilderDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0, + KJ_MAP(f, fieldTexts) { return kj::mv(f.builderMethodDecls); }), + makePipelineDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0, + KJ_MAP(f, fieldTexts) { return kj::mv(f.pipelineMethodDecls); })), + + kj::strTree( + structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree( + templateContext.allDecls(), + "inline ", whichName, " ", fullName, "::Reader::which() const {\n" + " return _reader.getDataField(\n" + " ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS);\n" + "}\n", + templateContext.allDecls(), + "inline ", whichName, " ", fullName, "::Builder::which() {\n" + " return _builder.getDataField(\n" + " ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS);\n" + "}\n" + "\n"), + KJ_MAP(f, fieldTexts) { return kj::mv(f.inlineMethodDefs); }), + + kj::mv(defineText) + }; + } + + // ----------------------------------------------------------------- + + struct MethodText { + kj::StringTree clientDecls; + kj::StringTree serverDecls; + kj::StringTree inlineDefs; + kj::StringTree sourceDefs; + kj::StringTree dispatchCase; + }; + + MethodText makeMethodText(kj::StringPtr interfaceName, InterfaceSchema::Method method, + const TemplateContext& templateContext) { + auto proto = method.getProto(); + auto name = protoName(proto); + auto titleCase = toTitleCase(name); + auto paramSchema = method.getParamType(); + auto resultSchema = method.getResultType(); + auto identifierName = safeIdentifier(name); + + auto paramProto = paramSchema.getProto(); + auto resultProto = resultSchema.getProto(); + + auto implicitParamsReader = proto.getImplicitParameters(); + auto implicitParamsBuilder = kj::heapArrayBuilder(implicitParamsReader.size()); + for (auto param: implicitParamsReader) { + implicitParamsBuilder.add(CppTypeName::makeTemplateParam(param.getName())); + } + auto implicitParams = implicitParamsBuilder.finish(); + + kj::String implicitParamsTemplateDecl; + if (implicitParams.size() > 0) { + implicitParamsTemplateDecl = kj::str( + "template <", kj::StringTree(KJ_MAP(p, implicitParams) { + return kj::strTree("typename ", p); + }, ", "), ">\n"); + } + + + CppTypeName interfaceTypeName = cppFullName(method.getContainingInterface(), nullptr); + CppTypeName paramType; + CppTypeName genericParamType; + if (paramProto.getScopeId() == 0) { + paramType = interfaceTypeName; + if (implicitParams.size() == 0) { + paramType.addMemberType(kj::str(titleCase, "Params")); + genericParamType = paramType; + } else { + genericParamType = paramType; + genericParamType.addMemberTemplate(kj::str(titleCase, "Params"), nullptr); + paramType.addMemberTemplate(kj::str(titleCase, "Params"), + kj::heapArray(implicitParams.asPtr())); + } + } else { + paramType = cppFullName(paramSchema, method); + genericParamType = cppFullName(paramSchema, nullptr); + } + CppTypeName resultType; + CppTypeName genericResultType; + if (resultProto.getScopeId() == 0) { + resultType = interfaceTypeName; + if (implicitParams.size() == 0) { + resultType.addMemberType(kj::str(titleCase, "Results")); + genericResultType = resultType; + } else { + genericResultType = resultType; + genericResultType.addMemberTemplate(kj::str(titleCase, "Results"), nullptr); + resultType.addMemberTemplate(kj::str(titleCase, "Results"), + kj::heapArray(implicitParams.asPtr())); + } + } else { + resultType = cppFullName(resultSchema, method); + genericResultType = cppFullName(resultSchema, nullptr); + } + + kj::String shortParamType = paramProto.getScopeId() == 0 ? + kj::str(titleCase, "Params") : kj::str(genericParamType); + kj::String shortResultType = resultProto.getScopeId() == 0 ? + kj::str(titleCase, "Results") : kj::str(genericResultType); + + auto interfaceProto = method.getContainingInterface().getProto(); + uint64_t interfaceId = interfaceProto.getId(); + auto interfaceIdHex = kj::hex(interfaceId); + uint16_t methodId = method.getIndex(); + + // TODO(msvc): Notice that the return type of this method's request function is supposed to be + // `::capnp::Request`. If the first template parameter to ::capnp::Request is a + // template instantiation, MSVC will sometimes complain that it's unspecialized and can't be + // used as a parameter in the return type (error C3203). It is not clear to me under what exact + // conditions this bug occurs, but it commonly crops up in test.capnp.h. + // + // The easiest (and only) workaround I found is to use C++14's return type deduction here, thus + // the `CAPNP_AUTO_IF_MSVC()` hackery in the return type declarations below. We're depending on + // the fact that that this function has an inline implementation for the deduction to work. + + auto requestMethodImpl = kj::strTree( + templateContext.allDecls(), + implicitParamsTemplateDecl, + templateContext.isGeneric() ? "CAPNP_AUTO_IF_MSVC(" : "", + "::capnp::Request<", paramType, ", ", resultType, ">", + templateContext.isGeneric() ? ")\n" : "\n", + interfaceName, "::Client::", name, "Request(::kj::Maybe< ::capnp::MessageSize> sizeHint) {\n" + " return newCall<", paramType, ", ", resultType, ">(\n" + " 0x", interfaceIdHex, "ull, ", methodId, ", sizeHint);\n" + "}\n"); + + return MethodText { + kj::strTree( + implicitParamsTemplateDecl.size() == 0 ? "" : " ", implicitParamsTemplateDecl, + templateContext.isGeneric() ? " CAPNP_AUTO_IF_MSVC(" : " ", + "::capnp::Request<", paramType, ", ", resultType, ">", + templateContext.isGeneric() ? ")" : "", + " ", name, "Request(\n" + " ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr);\n"), + + kj::strTree( + paramProto.getScopeId() != 0 ? kj::strTree() : kj::strTree( + " typedef ", genericParamType, " ", titleCase, "Params;\n"), + resultProto.getScopeId() != 0 ? kj::strTree() : kj::strTree( + " typedef ", genericResultType, " ", titleCase, "Results;\n"), + " typedef ::capnp::CallContext<", shortParamType, ", ", shortResultType, "> ", + titleCase, "Context;\n" + " virtual ::kj::Promise ", identifierName, "(", titleCase, "Context context);\n"), + + implicitParams.size() == 0 ? kj::strTree() : kj::mv(requestMethodImpl), + + kj::strTree( + implicitParams.size() == 0 ? kj::mv(requestMethodImpl) : kj::strTree(), + templateContext.allDecls(), + "::kj::Promise ", interfaceName, "::Server::", identifierName, "(", titleCase, "Context) {\n" + " return ::capnp::Capability::Server::internalUnimplemented(\n" + " \"", interfaceProto.getDisplayName(), "\", \"", name, "\",\n" + " 0x", interfaceIdHex, "ull, ", methodId, ");\n" + "}\n"), + + kj::strTree( + " case ", methodId, ":\n" + " return ", identifierName, "(::capnp::Capability::Server::internalGetTypedContext<\n" + " ", genericParamType, ", ", genericResultType, ">(context));\n") + }; + } + + struct InterfaceText { + kj::StringTree outerTypeDecl; + kj::StringTree outerTypeDef; + kj::StringTree clientServerDefs; + kj::StringTree inlineMethodDefs; + kj::StringTree sourceDefs; + }; + + struct ExtendInfo { + CppTypeName typeName; + uint64_t id; + }; + + void getTransitiveSuperclasses(InterfaceSchema schema, std::map& map) { + if (map.insert(std::make_pair(schema.getProto().getId(), schema)).second) { + for (auto sup: schema.getSuperclasses()) { + getTransitiveSuperclasses(sup, map); + } + } + } + + InterfaceText makeInterfaceText(kj::StringPtr scope, kj::StringPtr name, InterfaceSchema schema, + kj::Array nestedTypeDecls, + const TemplateContext& templateContext) { + auto fullName = kj::str(scope, name, templateContext.args()); + auto methods = KJ_MAP(m, schema.getMethods()) { + return makeMethodText(fullName, m, templateContext); + }; + + auto proto = schema.getProto(); + auto hexId = kj::hex(proto.getId()); + + auto superclasses = KJ_MAP(superclass, schema.getSuperclasses()) { + return ExtendInfo { cppFullName(superclass, nullptr), superclass.getProto().getId() }; + }; + + kj::Array transitiveSuperclasses; + { + std::map map; + getTransitiveSuperclasses(schema, map); + map.erase(schema.getProto().getId()); + transitiveSuperclasses = KJ_MAP(entry, map) { + return ExtendInfo { cppFullName(entry.second, nullptr), entry.second.getProto().getId() }; + }; + } + + CppTypeName typeName = cppFullName(schema, nullptr); + + CppTypeName clientName = typeName; + clientName.addMemberType("Client"); + + kj::String templates = kj::str(templateContext.allDecls()); // Ends with a newline + + // Private members struct + kj::StringTree declareText = kj::strTree( + " #if !CAPNP_LITE\n" + " struct _capnpPrivate {\n" + " CAPNP_DECLARE_INTERFACE_HEADER(", hexId, ")\n"); + + kj::StringTree defineText = kj::strTree( + "// ", fullName, "\n", + "#if !CAPNP_LITE\n", + templates, "constexpr ::capnp::Kind ", fullName, "::_capnpPrivate::kind;\n", + templates, "constexpr ::capnp::_::RawSchema const* ", fullName, "::_capnpPrivate::schema;\n"); + + if (templateContext.isGeneric()) { + auto brandInitializers = makeBrandInitializers(templateContext, schema); + bool hasDeps = (brandInitializers.dependencies.size() != 0); + + declareText = kj::strTree(kj::mv(declareText), + makeGenericDeclarations(templateContext, hasDeps)); + + defineText = kj::strTree(kj::mv(defineText), + makeGenericDefinitions( + templateContext, fullName, kj::str(hexId), kj::mv(brandInitializers))); + } else { + declareText = kj::strTree(kj::mv(declareText), + " static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }\n"); + } + + declareText = kj::strTree(kj::mv(declareText), " };\n #endif // !CAPNP_LITE"); + defineText = kj::strTree(kj::mv(defineText), "#endif // !CAPNP_LITE\n\n"); + + return InterfaceText { + kj::strTree( + templateContext.hasParams() ? " " : "", templateContext.decl(true), + " struct ", name, ";\n"), + + kj::strTree( + templateContext.parentDecls(), + templateContext.decl(scope == nullptr), + "struct ", scope, name, " {\n", + " ", name, "() = delete;\n" + "\n" + "#if !CAPNP_LITE\n" + " class Client;\n" + " class Server;\n" + "#endif // !CAPNP_LITE\n" + "\n", + KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, + "\n", + kj::mv(declareText), "\n" + "};\n" + "\n"), + + kj::strTree( + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "class ", fullName, "::Client\n" + " : public virtual ::capnp::Capability::Client", + KJ_MAP(s, superclasses) { + return kj::strTree(",\n public virtual ", s.typeName.strNoTypename(), "::Client"); + }, " {\n" + "public:\n" + " typedef ", name, " Calls;\n" + " typedef ", name, " Reads;\n" + "\n" + " Client(decltype(nullptr));\n" + " explicit Client(::kj::Own< ::capnp::ClientHook>&& hook);\n" + " template ()>>\n" + " Client(::kj::Own<_t>&& server);\n" + " template ()>>\n" + " Client(::kj::Promise<_t>&& promise);\n" + " Client(::kj::Exception&& exception);\n" + " Client(Client&) = default;\n" + " Client(Client&&) = default;\n" + " Client& operator=(Client& other);\n" + " Client& operator=(Client&& other);\n" + "\n", + makeAsGenericDef(AsGenericRole::CLIENT, templateContext, name), + KJ_MAP(m, methods) { return kj::mv(m.clientDecls); }, + "\n" + "protected:\n" + " Client() = default;\n" + "};\n" + "\n", + templateContext.allDecls(), + "class ", fullName, "::Server\n" + " : public virtual ::capnp::Capability::Server", + KJ_MAP(s, superclasses) { + return kj::strTree(",\n public virtual ", s.typeName.strNoTypename(), "::Server"); + }, " {\n" + "public:\n", + " typedef ", name, " Serves;\n" + "\n" + " ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId,\n" + " ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context)\n" + " override;\n" + "\n" + "protected:\n", + KJ_MAP(m, methods) { return kj::mv(m.serverDecls); }, + "\n" + " inline ", clientName, " thisCap() {\n" + " return ::capnp::Capability::Server::thisCap()\n" + " .template castAs<", typeName, ">();\n" + " }\n" + "\n" + " ::kj::Promise dispatchCallInternal(uint16_t methodId,\n" + " ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);\n" + "};\n" + "#endif // !CAPNP_LITE\n" + "\n"), + + kj::strTree( + "#if !CAPNP_LITE\n", + templateContext.allDecls(), + "inline ", fullName, "::Client::Client(decltype(nullptr))\n" + " : ::capnp::Capability::Client(nullptr) {}\n", + templateContext.allDecls(), + "inline ", fullName, "::Client::Client(\n" + " ::kj::Own< ::capnp::ClientHook>&& hook)\n" + " : ::capnp::Capability::Client(::kj::mv(hook)) {}\n", + templateContext.allDecls(), + "template \n" + "inline ", fullName, "::Client::Client(::kj::Own<_t>&& server)\n" + " : ::capnp::Capability::Client(::kj::mv(server)) {}\n", + templateContext.allDecls(), + "template \n" + "inline ", fullName, "::Client::Client(::kj::Promise<_t>&& promise)\n" + " : ::capnp::Capability::Client(::kj::mv(promise)) {}\n", + templateContext.allDecls(), + "inline ", fullName, "::Client::Client(::kj::Exception&& exception)\n" + " : ::capnp::Capability::Client(::kj::mv(exception)) {}\n", + templateContext.allDecls(), + "inline ", clientName, "& ", fullName, "::Client::operator=(Client& other) {\n" + " ::capnp::Capability::Client::operator=(other);\n" + " return *this;\n" + "}\n", + templateContext.allDecls(), + "inline ", clientName, "& ", fullName, "::Client::operator=(Client&& other) {\n" + " ::capnp::Capability::Client::operator=(kj::mv(other));\n" + " return *this;\n" + "}\n" + "\n", + KJ_MAP(m, methods) { return kj::mv(m.inlineDefs); }, + "#endif // !CAPNP_LITE\n"), + + kj::strTree( + "#if !CAPNP_LITE\n", + KJ_MAP(m, methods) { return kj::mv(m.sourceDefs); }, + templateContext.allDecls(), + "::kj::Promise ", fullName, "::Server::dispatchCall(\n" + " uint64_t interfaceId, uint16_t methodId,\n" + " ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {\n" + " switch (interfaceId) {\n" + " case 0x", kj::hex(proto.getId()), "ull:\n" + " return dispatchCallInternal(methodId, context);\n", + KJ_MAP(s, transitiveSuperclasses) { + return kj::strTree( + " case 0x", kj::hex(s.id), "ull:\n" + " return ", s.typeName.strNoTypename(), + "::Server::dispatchCallInternal(methodId, context);\n"); + }, + " default:\n" + " return internalUnimplemented(\"", proto.getDisplayName(), "\", interfaceId);\n" + " }\n" + "}\n", + templateContext.allDecls(), + "::kj::Promise ", fullName, "::Server::dispatchCallInternal(\n" + " uint16_t methodId,\n" + " ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {\n" + " switch (methodId) {\n", + KJ_MAP(m, methods) { return kj::mv(m.dispatchCase); }, + " default:\n" + " (void)context;\n" + " return ::capnp::Capability::Server::internalUnimplemented(\n" + " \"", proto.getDisplayName(), "\",\n" + " 0x", kj::hex(proto.getId()), "ull, methodId);\n" + " }\n" + "}\n" + "#endif // !CAPNP_LITE\n" + "\n", + kj::mv(defineText)) + }; + } + + // ----------------------------------------------------------------- + + struct ConstText { + bool needsSchema; + kj::StringTree decl; + kj::StringTree def; + }; + + ConstText makeConstText(kj::StringPtr scope, kj::StringPtr name, ConstSchema schema, + const TemplateContext& templateContext) { + auto proto = schema.getProto(); + auto constProto = proto.getConst(); + auto type = schema.getType(); + auto typeName_ = typeName(type, nullptr); + auto upperCase = toUpperCase(name); + + // Linkage qualifier for non-primitive types. + const char* linkage = scope.size() == 0 ? "extern " : "static "; + + switch (type.which()) { + case schema::Value::BOOL: + case schema::Value::INT8: + case schema::Value::INT16: + case schema::Value::INT32: + case schema::Value::INT64: + case schema::Value::UINT8: + case schema::Value::UINT16: + case schema::Value::UINT32: + case schema::Value::UINT64: + case schema::Value::ENUM: + return ConstText { + false, + kj::strTree("static constexpr ", typeName_, ' ', upperCase, " = ", + literalValue(schema.getType(), constProto.getValue()), ";\n"), + scope.size() == 0 ? kj::strTree() : kj::strTree( + // TODO(msvc): MSVC doesn't like definitions of constexprs, but other compilers and + // the standard require them. + "#ifndef _MSC_VER\n" + "constexpr ", typeName_, ' ', scope, upperCase, ";\n" + "#endif\n") + }; + + case schema::Value::VOID: + case schema::Value::FLOAT32: + case schema::Value::FLOAT64: { + // TODO(msvc): MSVC doesn't like float- or class-typed constexprs. As soon as this is fixed, + // treat VOID, FLOAT32, and FLOAT64 the same as the other primitives. + kj::String value = literalValue(schema.getType(), constProto.getValue()).flatten(); + return ConstText { + false, + kj::strTree("static KJ_CONSTEXPR(const) ", typeName_, ' ', upperCase, + " CAPNP_NON_INT_CONSTEXPR_DECL_INIT(", value, ");\n"), + scope.size() == 0 ? kj::strTree() : kj::strTree( + "KJ_CONSTEXPR(const) ", typeName_, ' ', scope, upperCase, + " CAPNP_NON_INT_CONSTEXPR_DEF_INIT(", value, ");\n") + }; + } + + case schema::Value::TEXT: { + kj::String constType = kj::strTree( + "::capnp::_::ConstText<", schema.as().size(), ">").flatten(); + return ConstText { + true, + kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), + kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", + kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") + }; + } + + case schema::Value::DATA: { + kj::String constType = kj::strTree( + "::capnp::_::ConstData<", schema.as().size(), ">").flatten(); + return ConstText { + true, + kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), + kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", + kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") + }; + } + + case schema::Value::STRUCT: { + kj::String constType = kj::strTree( + "::capnp::_::ConstStruct<", typeName_, ">").flatten(); + return ConstText { + true, + kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), + kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", + kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") + }; + } + + case schema::Value::LIST: { + kj::String constType = kj::strTree( + "::capnp::_::ConstList<", typeName(type.asList().getElementType(), nullptr), ">") + .flatten(); + return ConstText { + true, + kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"), + kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_", + kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n") + }; + } + + case schema::Value::ANY_POINTER: + case schema::Value::INTERFACE: + return ConstText { false, kj::strTree(), kj::strTree() }; + } + + KJ_UNREACHABLE; + } + + // ----------------------------------------------------------------- + + struct NodeText { + kj::StringTree outerTypeDecl; + kj::StringTree outerTypeDef; + kj::StringTree readerBuilderDefs; + kj::StringTree inlineMethodDefs; + kj::StringTree capnpSchemaDecls; + kj::StringTree capnpSchemaDefs; + kj::StringTree sourceFileDefs; + }; + + NodeText makeNodeText(kj::StringPtr namespace_, kj::StringPtr scope, + kj::StringPtr name, Schema schema, + const TemplateContext& parentTemplateContext) { + // `templateContext` is something like "template \ntemplate \n" + // declaring template parameters for all parent scopes. + + auto proto = schema.getProto(); + KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) { + name = annotatedName->getText(); + } + auto hexId = kj::hex(proto.getId()); + + TemplateContext templateContext(parentTemplateContext, name, proto); + + auto subScope = kj::str(scope, name, templateContext.args(), "::"); + + // Compute nested nodes, including groups. + kj::Vector nestedTexts(proto.getNestedNodes().size()); + for (auto nested: proto.getNestedNodes()) { + nestedTexts.add(makeNodeText( + namespace_, subScope, nested.getName(), schemaLoader.getUnbound(nested.getId()),\ + templateContext)); + }; + + if (proto.isStruct()) { + for (auto field: proto.getStruct().getFields()) { + if (field.isGroup()) { + nestedTexts.add(makeNodeText( + namespace_, subScope, toTitleCase(protoName(field)), + schemaLoader.getUnbound(field.getGroup().getTypeId()), + templateContext)); + } + } + } else if (proto.isInterface()) { + for (auto method: proto.getInterface().getMethods()) { + { + Schema params = schemaLoader.getUnbound(method.getParamStructType()); + auto paramsProto = schemaLoader.getUnbound(method.getParamStructType()).getProto(); + if (paramsProto.getScopeId() == 0) { + nestedTexts.add(makeNodeText(namespace_, subScope, + toTitleCase(kj::str(protoName(method), "Params")), params, templateContext)); + } + } + { + Schema results = schemaLoader.getUnbound(method.getResultStructType()); + auto resultsProto = schemaLoader.getUnbound(method.getResultStructType()).getProto(); + if (resultsProto.getScopeId() == 0) { + nestedTexts.add(makeNodeText(namespace_, subScope, + toTitleCase(kj::str(protoName(method), "Results")), results, templateContext)); + } + } + } + } + + // Convert the encoded schema to a literal byte array. + kj::ArrayPtr rawSchema = schema.asUncheckedMessage(); + auto schemaLiteral = kj::StringTree(KJ_MAP(w, rawSchema) { + const byte* bytes = reinterpret_cast(&w); + + return kj::strTree(KJ_MAP(i, kj::range(0, sizeof(word))) { + auto text = kj::toCharSequence(kj::implicitCast(bytes[i])); + return kj::strTree(kj::repeat(' ', 4 - text.size()), text, ","); + }); + }, "\n "); + + auto schemaDecl = kj::strTree( + "CAPNP_DECLARE_SCHEMA(", hexId, ");\n"); + + std::set deps; + enumerateDeps(proto, deps); + + kj::Array membersByName; + kj::Array membersByDiscrim; + switch (proto.which()) { + case schema::Node::STRUCT: { + auto structSchema = schema.asStruct(); + membersByName = makeMembersByName(structSchema.getFields()); + auto builder = kj::heapArrayBuilder(structSchema.getFields().size()); + for (auto field: structSchema.getUnionFields()) { + builder.add(field.getIndex()); + } + for (auto field: structSchema.getNonUnionFields()) { + builder.add(field.getIndex()); + } + membersByDiscrim = builder.finish(); + break; + } + case schema::Node::ENUM: + membersByName = makeMembersByName(schema.asEnum().getEnumerants()); + break; + case schema::Node::INTERFACE: + membersByName = makeMembersByName(schema.asInterface().getMethods()); + break; + default: + break; + } + + auto brandDeps = makeBrandDepInitializers( + makeBrandDepMap(templateContext, schema.getGeneric())); + + auto schemaDef = kj::strTree( + "static const ::capnp::_::AlignedData<", rawSchema.size(), "> b_", hexId, " = {\n" + " {", kj::mv(schemaLiteral), " }\n" + "};\n" + "::capnp::word const* const bp_", hexId, " = b_", hexId, ".words;\n" + "#if !CAPNP_LITE\n", + deps.size() == 0 ? kj::strTree() : kj::strTree( + "static const ::capnp::_::RawSchema* const d_", hexId, "[] = {\n", + KJ_MAP(depId, deps) { + return kj::strTree(" &s_", kj::hex(depId), ",\n"); + }, + "};\n"), + membersByName.size() == 0 ? kj::strTree() : kj::strTree( + "static const uint16_t m_", hexId, "[] = {", + kj::StringTree(KJ_MAP(index, membersByName) { return kj::strTree(index); }, ", "), + "};\n"), + membersByDiscrim.size() == 0 ? kj::strTree() : kj::strTree( + "static const uint16_t i_", hexId, "[] = {", + kj::StringTree(KJ_MAP(index, membersByDiscrim) { return kj::strTree(index); }, ", "), + "};\n"), + brandDeps.size() == 0 ? kj::strTree() : kj::strTree( + "KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_", hexId, "[] = ", + kj::mv(brandDeps), ";\n"), + "const ::capnp::_::RawSchema s_", hexId, " = {\n" + " 0x", hexId, ", b_", hexId, ".words, ", rawSchema.size(), ", ", + deps.size() == 0 ? kj::strTree("nullptr") : kj::strTree("d_", hexId), ", ", + membersByName.size() == 0 ? kj::strTree("nullptr") : kj::strTree("m_", hexId), ",\n", + " ", deps.size(), ", ", membersByName.size(), ", ", + membersByDiscrim.size() == 0 ? kj::strTree("nullptr") : kj::strTree("i_", hexId), + ", nullptr, nullptr, { &s_", hexId, ", nullptr, ", + brandDeps.size() == 0 ? kj::strTree("nullptr, 0, 0") : kj::strTree( + "bd_", hexId, ", 0, " "sizeof(bd_", hexId, ") / sizeof(bd_", hexId, "[0])"), + ", nullptr }\n" + "};\n" + "#endif // !CAPNP_LITE\n"); + + NodeText top = makeNodeTextWithoutNested( + namespace_, scope, name, schema, + KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDecl); }, + templateContext); + + NodeText result = { + kj::mv(top.outerTypeDecl), + + kj::strTree( + kj::mv(top.outerTypeDef), + KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDef); }), + + kj::strTree( + kj::mv(top.readerBuilderDefs), + KJ_MAP(n, nestedTexts) { return kj::mv(n.readerBuilderDefs); }), + + kj::strTree( + kj::mv(top.inlineMethodDefs), + KJ_MAP(n, nestedTexts) { return kj::mv(n.inlineMethodDefs); }), + + kj::strTree( + kj::mv(schemaDecl), + kj::mv(top.capnpSchemaDecls), + KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDecls); }), + + kj::strTree( + kj::mv(schemaDef), + kj::mv(top.capnpSchemaDefs), + KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDefs); }), + + kj::strTree( + kj::mv(top.sourceFileDefs), + KJ_MAP(n, nestedTexts) { return kj::mv(n.sourceFileDefs); }), + }; + + if (templateContext.isGeneric()) { + // This is a template, so move all source declarations into the header. + result.inlineMethodDefs = kj::strTree( + kj::mv(result.inlineMethodDefs), kj::mv(result.sourceFileDefs)); + result.sourceFileDefs = kj::strTree(); + } + + return result; + } + + NodeText makeNodeTextWithoutNested(kj::StringPtr namespace_, kj::StringPtr scope, + kj::StringPtr name, Schema schema, + kj::Array nestedTypeDecls, + const TemplateContext& templateContext) { + auto proto = schema.getProto(); + KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) { + name = annotatedName->getText(); + } + auto hexId = kj::hex(proto.getId()); + + switch (proto.which()) { + case schema::Node::FILE: + KJ_FAIL_REQUIRE("This method shouldn't be called on file nodes."); + + case schema::Node::STRUCT: { + StructText structText = + makeStructText(scope, name, schema.asStruct(), kj::mv(nestedTypeDecls), + templateContext); + + return NodeText { + kj::mv(structText.outerTypeDecl), + kj::mv(structText.outerTypeDef), + kj::mv(structText.readerBuilderDefs), + kj::mv(structText.inlineMethodDefs), + + kj::strTree(), + kj::strTree(), + + kj::mv(structText.sourceDefs), + }; + } + + case schema::Node::ENUM: { + auto enumerants = schema.asEnum().getEnumerants(); + + return NodeText { + scope.size() == 0 ? kj::strTree() : kj::strTree( + " typedef ::capnp::schemas::", name, "_", hexId, " ", name, ";\n" + "\n"), + + scope.size() > 0 ? kj::strTree() : kj::strTree( + "typedef ::capnp::schemas::", name, "_", hexId, " ", name, ";\n" + "\n"), + + kj::strTree(), + kj::strTree(), + + kj::strTree( + // We declare enums in the capnp::schemas namespace and then typedef them into + // place because we don't want them to be parameterized for generics. + "enum class ", name, "_", hexId, ": uint16_t {\n", + KJ_MAP(e, enumerants) { + return kj::strTree(" ", toUpperCase(protoName(e.getProto())), ",\n"); + }, + "};\n" + "CAPNP_DECLARE_ENUM(", name, ", ", hexId, ");\n"), + kj::strTree( + "CAPNP_DEFINE_ENUM(", name, "_", hexId, ", ", hexId, ");\n"), + + kj::strTree(), + }; + } + + case schema::Node::INTERFACE: { + hasInterfaces = true; + + InterfaceText interfaceText = + makeInterfaceText(scope, name, schema.asInterface(), kj::mv(nestedTypeDecls), + templateContext); + + return NodeText { + kj::mv(interfaceText.outerTypeDecl), + kj::mv(interfaceText.outerTypeDef), + kj::mv(interfaceText.clientServerDefs), + kj::mv(interfaceText.inlineMethodDefs), + + kj::strTree(), + kj::strTree(), + + kj::mv(interfaceText.sourceDefs), + }; + } + + case schema::Node::CONST: { + auto constText = makeConstText(scope, name, schema.asConst(), templateContext); + + return NodeText { + scope.size() == 0 ? kj::strTree() : kj::strTree(" ", kj::mv(constText.decl)), + scope.size() > 0 ? kj::strTree() : kj::mv(constText.decl), + kj::strTree(), + kj::strTree(), + + kj::strTree(), + kj::strTree(), + + kj::mv(constText.def), + }; + } + + case schema::Node::ANNOTATION: { + return NodeText { + kj::strTree(), + kj::strTree(), + kj::strTree(), + kj::strTree(), + + kj::strTree(), + kj::strTree(), + + kj::strTree(), + }; + } + } + + KJ_UNREACHABLE; + } + + // ----------------------------------------------------------------- + + struct FileText { + kj::StringTree header; + kj::StringTree source; + }; + + FileText makeFileText(Schema schema, + schema::CodeGeneratorRequest::RequestedFile::Reader request) { + usedImports.clear(); + + auto node = schema.getProto(); + auto displayName = node.getDisplayName(); + + kj::Vector> namespaceParts; + kj::String namespacePrefix; + + for (auto annotation: node.getAnnotations()) { + if (annotation.getId() == NAMESPACE_ANNOTATION_ID) { + kj::StringPtr ns = annotation.getValue().getText(); + kj::StringPtr ns2 = ns; + namespacePrefix = kj::str("::", ns); + + for (;;) { + KJ_IF_MAYBE(colonPos, ns.findFirst(':')) { + namespaceParts.add(ns.slice(0, *colonPos)); + ns = ns.slice(*colonPos); + if (!ns.startsWith("::")) { + context.exitError(kj::str(displayName, ": invalid namespace spec: ", ns2)); + } + ns = ns.slice(2); + } else { + namespaceParts.add(ns); + break; + } + } + + break; + } + } + + auto nodeTexts = KJ_MAP(nested, node.getNestedNodes()) { + return makeNodeText(namespacePrefix, "", nested.getName(), + schemaLoader.getUnbound(nested.getId()), TemplateContext()); + }; + + kj::String separator = kj::str("// ", kj::repeat('=', 87), "\n"); + + kj::Vector includes; + for (auto import: request.getImports()) { + if (usedImports.count(import.getId()) > 0) { + includes.add(import.getName()); + } + } + + kj::StringTree sourceDefs = kj::strTree( + KJ_MAP(n, nodeTexts) { return kj::mv(n.sourceFileDefs); }); + + return FileText { + kj::strTree( + "// Generated by Cap'n Proto compiler, DO NOT EDIT\n" + "// source: ", baseName(displayName), "\n" + "\n" + "#ifndef CAPNP_INCLUDED_", kj::hex(node.getId()), "_\n", + "#define CAPNP_INCLUDED_", kj::hex(node.getId()), "_\n" + "\n" + "#include \n", + hasInterfaces ? kj::strTree( + "#if !CAPNP_LITE\n" + "#include \n" + "#endif // !CAPNP_LITE\n" + ) : kj::strTree(), + "\n" + "#if CAPNP_VERSION != ", CAPNP_VERSION, "\n" + "#error \"Version mismatch between generated code and library headers. You must " + "use the same version of the Cap'n Proto compiler and library.\"\n" + "#endif\n" + "\n", + KJ_MAP(path, includes) { + if (path.startsWith("/")) { + return kj::strTree("#include <", path.slice(1), ".h>\n"); + } else { + return kj::strTree("#include \"", path, ".h\"\n"); + } + }, + "\n" + "namespace capnp {\n" + "namespace schemas {\n" + "\n", + KJ_MAP(n, nodeTexts) { return kj::mv(n.capnpSchemaDecls); }, + "\n" + "} // namespace schemas\n" + "} // namespace capnp\n" + "\n", + + KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n", + KJ_MAP(n, nodeTexts) { return kj::mv(n.outerTypeDef); }, + separator, "\n", + KJ_MAP(n, nodeTexts) { return kj::mv(n.readerBuilderDefs); }, + separator, "\n", + KJ_MAP(n, nodeTexts) { return kj::mv(n.inlineMethodDefs); }, + KJ_MAP(n, namespaceParts) { return kj::strTree("} // namespace\n"); }, "\n", + "#endif // CAPNP_INCLUDED_", kj::hex(node.getId()), "_\n"), + + kj::strTree( + "// Generated by Cap'n Proto compiler, DO NOT EDIT\n" + "// source: ", baseName(displayName), "\n" + "\n" + "#include \"", baseName(displayName), ".h\"\n" + "\n" + "namespace capnp {\n" + "namespace schemas {\n", + KJ_MAP(n, nodeTexts) { return kj::mv(n.capnpSchemaDefs); }, + "} // namespace schemas\n" + "} // namespace capnp\n", + sourceDefs.size() == 0 ? kj::strTree() : kj::strTree( + "\n", separator, "\n", + KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n", + kj::mv(sourceDefs), "\n", + KJ_MAP(n, namespaceParts) { return kj::strTree("} // namespace\n"); }, "\n")) + }; + } + + // ----------------------------------------------------------------- + + void makeDirectory(kj::StringPtr path) { + KJ_IF_MAYBE(slashpos, path.findLast('/')) { + // Make the parent dir. + makeDirectory(kj::str(path.slice(0, *slashpos))); + } + + if (kj::miniposix::mkdir(path.cStr(), 0777) < 0) { + int error = errno; + if (error != EEXIST) { + KJ_FAIL_SYSCALL("mkdir(path)", error, path); + } + } + } + + void writeFile(kj::StringPtr filename, const kj::StringTree& text) { + if (!filename.startsWith("/")) { + KJ_IF_MAYBE(slashpos, filename.findLast('/')) { + // Make the parent dir. + makeDirectory(kj::str(filename.slice(0, *slashpos))); + } + } + + int fd; + KJ_SYSCALL(fd = open(filename.cStr(), O_CREAT | O_WRONLY | O_TRUNC, 0666), filename); + kj::FdOutputStream out((kj::AutoCloseFd(fd))); + + text.visit( + [&](kj::ArrayPtr text) { + out.write(text.begin(), text.size()); + }); + } + + kj::MainBuilder::Validity run() { + ReaderOptions options; + options.traversalLimitInWords = 1 << 30; // Don't limit. + StreamFdMessageReader reader(STDIN_FILENO, options); + auto request = reader.getRoot(); + + auto capnpVersion = request.getCapnpVersion(); + + if (capnpVersion.getMajor() != CAPNP_VERSION_MAJOR || + capnpVersion.getMinor() != CAPNP_VERSION_MINOR || + capnpVersion.getMicro() != CAPNP_VERSION_MICRO) { + auto compilerVersion = request.hasCapnpVersion() + ? kj::str(capnpVersion.getMajor(), '.', capnpVersion.getMinor(), '.', + capnpVersion.getMicro()) + : kj::str("pre-0.6"); // pre-0.6 didn't send the version. + auto generatorVersion = kj::str( + CAPNP_VERSION_MAJOR, '.', CAPNP_VERSION_MINOR, '.', CAPNP_VERSION_MICRO); + + KJ_LOG(WARNING, + "You appear to be using different versions of 'capnp' (the compiler) and " + "'capnpc-c++' (the code generator). This can happen, for example, if you built " + "a custom version of 'capnp' but then ran it with '-oc++', which invokes " + "'capnpc-c++' from your PATH (i.e. the installed version). To specify an alternate " + "'capnpc-c++' executable, try something like '-o/path/to/capnpc-c++' instead.", + compilerVersion, generatorVersion); + } + + for (auto node: request.getNodes()) { + schemaLoader.load(node); + } + + kj::FdOutputStream rawOut(STDOUT_FILENO); + kj::BufferedOutputStreamWrapper out(rawOut); + + for (auto requestedFile: request.getRequestedFiles()) { + auto schema = schemaLoader.get(requestedFile.getId()); + auto fileText = makeFileText(schema, requestedFile); + + writeFile(kj::str(schema.getProto().getDisplayName(), ".h"), fileText.header); + writeFile(kj::str(schema.getProto().getDisplayName(), ".c++"), fileText.source); + } + + return true; + } +}; + +} // namespace +} // namespace capnp + +KJ_MAIN(capnp::CapnpcCppMain); diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/capnpc-capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/capnpc-capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,681 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This program is a code generator plugin for `capnp compile` which writes the schema back to +// stdout in roughly capnpc format. + +#include +#include "../serialize.h" +#include +#include +#include +#include +#include "../schema-loader.h" +#include "../dynamic.h" +#include +#include +#include +#include +#include + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef VERSION +#define VERSION "(unknown)" +#endif + +namespace capnp { +namespace { + +bool hasDiscriminantValue(const schema::Field::Reader& reader) { + return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT; +} + +struct Indent { + uint amount; + Indent() = default; + inline Indent(int amount): amount(amount) {} + + Indent next() { + return Indent(amount + 2); + } + + struct Iterator { + uint i; + Iterator() = default; + inline Iterator(uint i): i(i) {} + inline char operator*() const { return ' '; } + inline Iterator& operator++() { ++i; return *this; } + inline Iterator operator++(int) { Iterator result = *this; ++i; return result; } + inline bool operator==(const Iterator& other) const { return i == other.i; } + inline bool operator!=(const Iterator& other) const { return i != other.i; } + }; + + inline size_t size() const { return amount; } + + inline Iterator begin() const { return Iterator(0); } + inline Iterator end() const { return Iterator(amount); } +}; + +inline Indent KJ_STRINGIFY(const Indent& indent) { + return indent; +} + +// ======================================================================================= + +class CapnpcCapnpMain { +public: + CapnpcCapnpMain(kj::ProcessContext& context): context(context) {} + + kj::MainFunc getMain() { + return kj::MainBuilder(context, "Cap'n Proto loopback plugin version " VERSION, + "This is a Cap'n Proto compiler plugin which \"de-compiles\" the schema back into " + "Cap'n Proto schema language format, with comments showing the offsets chosen by the " + "compiler. This is meant to be run using the Cap'n Proto compiler, e.g.:\n" + " capnp compile -ocapnp foo.capnp") + .callAfterParsing(KJ_BIND_METHOD(*this, run)) + .build(); + } + +private: + kj::ProcessContext& context; + SchemaLoader schemaLoader; + + Text::Reader getUnqualifiedName(Schema schema) { + auto proto = schema.getProto(); + KJ_CONTEXT(proto.getDisplayName()); + auto parent = schemaLoader.get(proto.getScopeId()); + for (auto nested: parent.getProto().getNestedNodes()) { + if (nested.getId() == proto.getId()) { + return nested.getName(); + } + } + KJ_FAIL_REQUIRE("A schema Node's supposed scope did not contain the node as a NestedNode."); + return "(?)"; + } + + kj::StringTree nodeName(Schema target, Schema scope, schema::Brand::Reader brand, + kj::Maybe method) { + kj::Vector targetPath; + kj::Vector scopeParts; + + targetPath.add(target); + + std::map::Reader> scopeBindings; + for (auto scopeBrand: brand.getScopes()) { + switch (scopeBrand.which()) { + case schema::Brand::Scope::BIND: + scopeBindings[scopeBrand.getScopeId()] = scopeBrand.getBind(); + break; + case schema::Brand::Scope::INHERIT: + // TODO(someday): We need to pay attention to INHERIT and be sure to explicitly override + // any bindings that are not inherited. This requires a way to determine which of our + // parent scopes have a non-empty parameter list. + break; + } + } + + { + Schema parent = target; + while (parent.getProto().getScopeId() != 0) { + parent = schemaLoader.get(parent.getProto().getScopeId()); + targetPath.add(parent); + } + } + + { + Schema parent = scope; + scopeParts.add(parent); + while (parent.getProto().getScopeId() != 0) { + parent = schemaLoader.get(parent.getProto().getScopeId()); + scopeParts.add(parent); + } + } + + // Remove common scope (unless it has been reparameterized). + // TODO(someday): This is broken in that we aren't checking for shadowing. + while (!scopeParts.empty() && targetPath.size() > 1 && + scopeParts.back() == targetPath.back() && + scopeBindings.count(scopeParts.back().getProto().getId()) == 0) { + scopeParts.removeLast(); + targetPath.removeLast(); + } + + auto parts = kj::heapArrayBuilder(targetPath.size()); + while (!targetPath.empty()) { + auto part = targetPath.back(); + auto proto = part.getProto(); + kj::StringTree partStr; + if (proto.getScopeId() == 0) { + partStr = kj::strTree("import \"/", proto.getDisplayName(), '\"'); + } else { + partStr = kj::strTree(getUnqualifiedName(part)); + } + + auto iter = scopeBindings.find(proto.getId()); + if (iter != scopeBindings.end()) { + auto bindings = KJ_MAP(binding, iter->second) { + switch (binding.which()) { + case schema::Brand::Binding::UNBOUND: + return kj::strTree("AnyPointer"); + case schema::Brand::Binding::TYPE: + return genType(binding.getType(), scope, method); + } + return kj::strTree(""); + }; + partStr = kj::strTree(kj::mv(partStr), "(", kj::StringTree(kj::mv(bindings), ", "), ")"); + } + + parts.add(kj::mv(partStr)); + targetPath.removeLast(); + } + + return kj::StringTree(parts.finish(), "."); + } + + kj::StringTree genType(schema::Type::Reader type, Schema scope, + kj::Maybe method) { + switch (type.which()) { + case schema::Type::VOID: return kj::strTree("Void"); + case schema::Type::BOOL: return kj::strTree("Bool"); + case schema::Type::INT8: return kj::strTree("Int8"); + case schema::Type::INT16: return kj::strTree("Int16"); + case schema::Type::INT32: return kj::strTree("Int32"); + case schema::Type::INT64: return kj::strTree("Int64"); + case schema::Type::UINT8: return kj::strTree("UInt8"); + case schema::Type::UINT16: return kj::strTree("UInt16"); + case schema::Type::UINT32: return kj::strTree("UInt32"); + case schema::Type::UINT64: return kj::strTree("UInt64"); + case schema::Type::FLOAT32: return kj::strTree("Float32"); + case schema::Type::FLOAT64: return kj::strTree("Float64"); + case schema::Type::TEXT: return kj::strTree("Text"); + case schema::Type::DATA: return kj::strTree("Data"); + case schema::Type::LIST: + return kj::strTree("List(", genType(type.getList().getElementType(), scope, method), ")"); + case schema::Type::ENUM: + return nodeName(schemaLoader.get(type.getEnum().getTypeId()), scope, + type.getEnum().getBrand(), method); + case schema::Type::STRUCT: + return nodeName(schemaLoader.get(type.getStruct().getTypeId()), scope, + type.getStruct().getBrand(), method); + case schema::Type::INTERFACE: + return nodeName(schemaLoader.get(type.getInterface().getTypeId()), scope, + type.getInterface().getBrand(), method); + case schema::Type::ANY_POINTER: { + auto anyPointer = type.getAnyPointer(); + switch (anyPointer.which()) { + case schema::Type::AnyPointer::UNCONSTRAINED: + switch (anyPointer.getUnconstrained().which()) { + case schema::Type::AnyPointer::Unconstrained::ANY_KIND: + return kj::strTree("AnyPointer"); + case schema::Type::AnyPointer::Unconstrained::STRUCT: + return kj::strTree("AnyStruct"); + case schema::Type::AnyPointer::Unconstrained::LIST: + return kj::strTree("AnyList"); + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + return kj::strTree("Capability"); + } + KJ_UNREACHABLE; + case schema::Type::AnyPointer::PARAMETER: { + auto param = anyPointer.getParameter(); + auto scopeProto = scope.getProto(); + auto targetScopeId = param.getScopeId(); + while (scopeProto.getId() != targetScopeId) { + scopeProto = schemaLoader.get(param.getScopeId()).getProto(); + } + auto params = scopeProto.getParameters(); + KJ_REQUIRE(param.getParameterIndex() < params.size()); + return kj::strTree(params[param.getParameterIndex()].getName()); + } + case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: { + auto params = KJ_REQUIRE_NONNULL(method).getProto().getImplicitParameters(); + uint index = anyPointer.getImplicitMethodParameter().getParameterIndex(); + KJ_REQUIRE(index < params.size()); + return kj::strTree(params[index].getName()); + } + } + KJ_UNREACHABLE; + } + } + return kj::strTree(); + } + + int typeSizeBits(schema::Type::Reader type) { + switch (type.which()) { + case schema::Type::VOID: return 0; + case schema::Type::BOOL: return 1; + case schema::Type::INT8: return 8; + case schema::Type::INT16: return 16; + case schema::Type::INT32: return 32; + case schema::Type::INT64: return 64; + case schema::Type::UINT8: return 8; + case schema::Type::UINT16: return 16; + case schema::Type::UINT32: return 32; + case schema::Type::UINT64: return 64; + case schema::Type::FLOAT32: return 32; + case schema::Type::FLOAT64: return 64; + case schema::Type::TEXT: return -1; + case schema::Type::DATA: return -1; + case schema::Type::LIST: return -1; + case schema::Type::ENUM: return 16; + case schema::Type::STRUCT: return -1; + case schema::Type::INTERFACE: return -1; + case schema::Type::ANY_POINTER: return -1; + } + return 0; + } + + bool isEmptyValue(schema::Value::Reader value) { + switch (value.which()) { + case schema::Value::VOID: return true; + case schema::Value::BOOL: return value.getBool() == false; + case schema::Value::INT8: return value.getInt8() == 0; + case schema::Value::INT16: return value.getInt16() == 0; + case schema::Value::INT32: return value.getInt32() == 0; + case schema::Value::INT64: return value.getInt64() == 0; + case schema::Value::UINT8: return value.getUint8() == 0; + case schema::Value::UINT16: return value.getUint16() == 0; + case schema::Value::UINT32: return value.getUint32() == 0; + case schema::Value::UINT64: return value.getUint64() == 0; + case schema::Value::FLOAT32: return value.getFloat32() == 0; + case schema::Value::FLOAT64: return value.getFloat64() == 0; + case schema::Value::TEXT: return !value.hasText(); + case schema::Value::DATA: return !value.hasData(); + case schema::Value::LIST: return !value.hasList(); + case schema::Value::ENUM: return value.getEnum() == 0; + case schema::Value::STRUCT: return !value.hasStruct(); + case schema::Value::INTERFACE: return true; + case schema::Value::ANY_POINTER: return true; + } + return true; + } + + kj::StringTree genValue(Type type, schema::Value::Reader value) { + switch (value.which()) { + case schema::Value::VOID: return kj::strTree("void"); + case schema::Value::BOOL: + return kj::strTree(value.getBool() ? "true" : "false"); + case schema::Value::INT8: return kj::strTree((int)value.getInt8()); + case schema::Value::INT16: return kj::strTree(value.getInt16()); + case schema::Value::INT32: return kj::strTree(value.getInt32()); + case schema::Value::INT64: return kj::strTree(value.getInt64()); + case schema::Value::UINT8: return kj::strTree((uint)value.getUint8()); + case schema::Value::UINT16: return kj::strTree(value.getUint16()); + case schema::Value::UINT32: return kj::strTree(value.getUint32()); + case schema::Value::UINT64: return kj::strTree(value.getUint64()); + case schema::Value::FLOAT32: return kj::strTree(value.getFloat32()); + case schema::Value::FLOAT64: return kj::strTree(value.getFloat64()); + case schema::Value::TEXT: + return kj::strTree(DynamicValue::Reader(value.getText())); + case schema::Value::DATA: + return kj::strTree(DynamicValue::Reader(value.getData())); + case schema::Value::LIST: { + auto listValue = value.getList().getAs(type.asList()); + return kj::strTree(listValue); + } + case schema::Value::ENUM: { + auto enumNode = type.asEnum().getProto(); + auto enumerants = enumNode.getEnum().getEnumerants(); + KJ_REQUIRE(value.getEnum() < enumerants.size(), + "Enum value out-of-range.", value.getEnum(), enumNode.getDisplayName()); + return kj::strTree(enumerants[value.getEnum()].getName()); + } + case schema::Value::STRUCT: { + KJ_REQUIRE(type.which() == schema::Type::STRUCT, "type/value mismatch"); + auto structValue = value.getStruct().getAs(type.asStruct()); + return kj::strTree(structValue); + } + case schema::Value::INTERFACE: { + return kj::strTree(""); + } + case schema::Value::ANY_POINTER: { + return kj::strTree(""); + } + } + return kj::strTree(""); + } + + kj::StringTree genGenericParams(List::Reader params, Schema scope) { + if (params.size() == 0) { + return kj::strTree(); + } + + return kj::strTree(" (", kj::StringTree( + KJ_MAP(param, params) { return kj::strTree(param.getName()); }, ", "), ')'); + } + kj::StringTree genGenericParams(Schema schema) { + auto proto = schema.getProto(); + return genGenericParams(proto.getParameters(), schemaLoader.get(proto.getScopeId())); + } + + kj::StringTree genAnnotation(schema::Annotation::Reader annotation, + Schema scope, + const char* prefix = " ", const char* suffix = "") { + auto decl = schemaLoader.get(annotation.getId(), annotation.getBrand(), scope); + auto proto = decl.getProto(); + KJ_REQUIRE(proto.isAnnotation()); + auto annDecl = proto.getAnnotation(); + + auto value = genValue(schemaLoader.getType(annDecl.getType(), decl), + annotation.getValue()).flatten(); + if (value.startsWith("(")) { + return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand(), nullptr), + value, suffix); + } else { + return kj::strTree(prefix, "$", nodeName(decl, scope, annotation.getBrand(), nullptr), + "(", value, ")", suffix); + } + } + + kj::StringTree genAnnotations(List::Reader list, Schema scope) { + return kj::strTree(KJ_MAP(ann, list) { return genAnnotation(ann, scope); }); + } + kj::StringTree genAnnotations(Schema schema) { + auto proto = schema.getProto(); + return genAnnotations(proto.getAnnotations(), schemaLoader.get(proto.getScopeId())); + } + + const char* elementSizeName(schema::ElementSize size) { + switch (size) { + case schema::ElementSize::EMPTY: return "void"; + case schema::ElementSize::BIT: return "1-bit"; + case schema::ElementSize::BYTE: return "8-bit"; + case schema::ElementSize::TWO_BYTES: return "16-bit"; + case schema::ElementSize::FOUR_BYTES: return "32-bit"; + case schema::ElementSize::EIGHT_BYTES: return "64-bit"; + case schema::ElementSize::POINTER: return "pointer"; + case schema::ElementSize::INLINE_COMPOSITE: return "inline composite"; + } + return ""; + } + + struct OrderByCodeOrder { + template + inline bool operator()(const T& a, const T& b) const { + return a.getProto().getCodeOrder() < b.getProto().getCodeOrder(); + } + }; + + template + kj::Array()[0])> sortByCodeOrder(MemberList&& list) { + auto sorted = KJ_MAP(item, list) { return item; }; + std::sort(sorted.begin(), sorted.end(), OrderByCodeOrder()); + return kj::mv(sorted); + } + + kj::Array genStructFields(StructSchema schema, Indent indent) { + // Slightly hacky: We want to print in code order, but we also need to print the union in one + // chunk. Its fields should be together in code order anyway, but it's easier to simply + // output the whole union in place of the first union field, and then output nothing for the + // subsequent fields. + + bool seenUnion = false; + return KJ_MAP(field, sortByCodeOrder(schema.getFields())) { + if (hasDiscriminantValue(field.getProto())) { + if (seenUnion) { + return kj::strTree(); + } else { + seenUnion = true; + uint offset = schema.getProto().getStruct().getDiscriminantOffset(); + + // GCC 4.7.3 crashes if you inline unionFields. + auto unionFields = sortByCodeOrder(schema.getUnionFields()); + return kj::strTree( + indent, "union { # tag bits [", offset * 16, ", ", offset * 16 + 16, ")\n", + KJ_MAP(uField, unionFields) { + return genStructField(uField, schema, indent.next()); + }, + indent, "}\n"); + } + } else { + return genStructField(field, schema, indent); + } + }; + } + + kj::StringTree genStructField(StructSchema::Field field, Schema scope, Indent indent) { + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + int size = typeSizeBits(slot.getType()); + return kj::strTree( + indent, proto.getName(), " @", proto.getOrdinal().getExplicit(), + " :", genType(slot.getType(), scope, nullptr), + isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") : + kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())), + genAnnotations(proto.getAnnotations(), scope), + "; # ", size == -1 ? kj::strTree("ptr[", slot.getOffset(), "]") + : kj::strTree("bits[", slot.getOffset() * size, ", ", + (slot.getOffset() + 1) * size, ")"), + hasDiscriminantValue(proto) + ? kj::strTree(", union tag = ", proto.getDiscriminantValue()) : kj::strTree(), + "\n"); + } + case schema::Field::GROUP: { + auto group = field.getType().asStruct(); + return kj::strTree( + indent, proto.getName(), + " :group", genAnnotations(proto.getAnnotations(), scope), " {", + hasDiscriminantValue(proto) + ? kj::strTree(" # union tag = ", proto.getDiscriminantValue()) : kj::strTree(), + "\n", + genStructFields(group, indent.next()), + indent, "}\n"); + } + } + return kj::strTree(); + } + + kj::StringTree genParamList(InterfaceSchema interface, StructSchema schema, + schema::Brand::Reader brand, InterfaceSchema::Method method) { + if (schema.getProto().getScopeId() == 0) { + // A named parameter list. + return kj::strTree("(", kj::StringTree( + KJ_MAP(field, schema.getFields()) { + auto proto = field.getProto(); + auto slot = proto.getSlot(); + + return kj::strTree( + proto.getName(), " :", genType(slot.getType(), interface, nullptr), + isEmptyValue(slot.getDefaultValue()) ? kj::strTree("") : + kj::strTree(" = ", genValue(field.getType(), slot.getDefaultValue())), + genAnnotations(proto.getAnnotations(), interface)); + }, ", "), ")"); + } else { + return nodeName(schema, interface, brand, method); + } + } + + kj::StringTree genSuperclasses(InterfaceSchema interface) { + auto superclasses = interface.getProto().getInterface().getSuperclasses(); + if (superclasses.size() == 0) { + return kj::strTree(); + } else { + return kj::strTree(" superclasses(", kj::StringTree( + KJ_MAP(superclass, superclasses) { + return nodeName(schemaLoader.get(superclass.getId()), interface, + superclass.getBrand(), nullptr); + }, ", "), ")"); + } + } + + kj::StringTree genDecl(Schema schema, Text::Reader name, uint64_t scopeId, Indent indent) { + auto proto = schema.getProto(); + if (proto.getScopeId() != scopeId) { + // This appears to be an alias for something declared elsewhere. + KJ_FAIL_REQUIRE("Aliases not implemented."); + } + + switch (proto.which()) { + case schema::Node::FILE: + KJ_FAIL_REQUIRE("Encountered nested file node."); + break; + case schema::Node::STRUCT: { + auto structProto = proto.getStruct(); + return kj::strTree( + indent, "struct ", name, + " @0x", kj::hex(proto.getId()), genGenericParams(schema), + genAnnotations(schema), " { # ", + structProto.getDataWordCount() * 8, " bytes, ", + structProto.getPointerCount(), " ptrs", + structProto.getPreferredListEncoding() == schema::ElementSize::INLINE_COMPOSITE + ? kj::strTree() + : kj::strTree(", packed as ", + elementSizeName(structProto.getPreferredListEncoding())), + "\n", + genStructFields(schema.asStruct(), indent.next()), + genNestedDecls(schema, indent.next()), + indent, "}\n"); + } + case schema::Node::ENUM: { + return kj::strTree( + indent, "enum ", name, " @0x", kj::hex(proto.getId()), genAnnotations(schema), " {\n", + KJ_MAP(enumerant, sortByCodeOrder(schema.asEnum().getEnumerants())) { + return kj::strTree(indent.next(), enumerant.getProto().getName(), " @", + enumerant.getIndex(), + genAnnotations(enumerant.getProto().getAnnotations(), schema), + ";\n"); + }, + genNestedDecls(schema, indent.next()), + indent, "}\n"); + } + case schema::Node::INTERFACE: { + auto interface = schema.asInterface(); + return kj::strTree( + indent, "interface ", name, " @0x", kj::hex(proto.getId()), genGenericParams(schema), + genSuperclasses(interface), + genAnnotations(schema), " {\n", + KJ_MAP(method, sortByCodeOrder(interface.getMethods())) { + auto methodProto = method.getProto(); + + auto implicits = methodProto.getImplicitParameters(); + kj::StringTree implicitsStr; + if (implicits.size() > 0) { + implicitsStr = kj::strTree( + "[", kj::StringTree(KJ_MAP(implicit, implicits) { + return kj::strTree(implicit.getName()); + }, ", "), "] "); + } + + auto params = schemaLoader.get(methodProto.getParamStructType()).asStruct(); + auto results = schemaLoader.get(methodProto.getResultStructType()).asStruct(); + return kj::strTree( + indent.next(), methodProto.getName(), + " @", method.getIndex(), " ", kj::mv(implicitsStr), + genParamList(interface, params, methodProto.getParamBrand(), method), " -> ", + genParamList(interface, results, methodProto.getResultBrand(), method), + genAnnotations(methodProto.getAnnotations(), interface), ";\n"); + }, + genNestedDecls(schema, indent.next()), + indent, "}\n"); + } + case schema::Node::CONST: { + auto constProto = proto.getConst(); + return kj::strTree( + indent, "const ", name, " @0x", kj::hex(proto.getId()), " :", + genType(constProto.getType(), schema, nullptr), " = ", + genValue(schema.asConst().getType(), constProto.getValue()), + genAnnotations(schema), ";\n"); + } + case schema::Node::ANNOTATION: { + auto annotationProto = proto.getAnnotation(); + + kj::Vector targets(8); + bool targetsAll = true; + + auto dynamic = toDynamic(annotationProto); + for (auto field: dynamic.getSchema().getFields()) { + auto fieldName = field.getProto().getName(); + if (fieldName.startsWith("targets")) { + if (dynamic.get(field).as()) { + auto target = kj::str(fieldName.slice(strlen("targets"))); + target[0] = target[0] - 'A' + 'a'; + targets.add(kj::mv(target)); + } else { + targetsAll = false; + } + } + } + + if (targetsAll) { + targets = kj::Vector(1); + targets.add(kj::heapString("*")); + } + + return kj::strTree( + indent, "annotation ", name, " @0x", kj::hex(proto.getId()), + " (", strArray(targets, ", "), ") :", + genType(annotationProto.getType(), schema, nullptr), genAnnotations(schema), ";\n"); + } + } + + return kj::strTree(); + } + + kj::StringTree genNestedDecls(Schema schema, Indent indent) { + uint64_t id = schema.getProto().getId(); + return kj::strTree(KJ_MAP(nested, schema.getProto().getNestedNodes()) { + return genDecl(schemaLoader.get(nested.getId()), nested.getName(), id, indent); + }); + } + + kj::StringTree genFile(Schema file) { + auto proto = file.getProto(); + KJ_REQUIRE(proto.isFile(), "Expected a file node.", (uint)proto.which()); + + return kj::strTree( + "# ", proto.getDisplayName(), "\n", + "@0x", kj::hex(proto.getId()), ";\n", + KJ_MAP(ann, proto.getAnnotations()) { return genAnnotation(ann, file, "", ";\n"); }, + genNestedDecls(file, Indent(0))); + } + + kj::MainBuilder::Validity run() { + ReaderOptions options; + options.traversalLimitInWords = 1 << 30; // Don't limit. + StreamFdMessageReader reader(STDIN_FILENO, options); + auto request = reader.getRoot(); + + for (auto node: request.getNodes()) { + schemaLoader.load(node); + } + + kj::FdOutputStream rawOut(STDOUT_FILENO); + kj::BufferedOutputStreamWrapper out(rawOut); + + for (auto requestedFile: request.getRequestedFiles()) { + genFile(schemaLoader.get(requestedFile.getId())).visit( + [&](kj::ArrayPtr text) { + out.write(text.begin(), text.size()); + }); + } + + return true; + } +}; + +} // namespace +} // namespace capnp + +KJ_MAIN(capnp::CapnpcCapnpMain); diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/compiler.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/compiler.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1292 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "compiler.h" +#include "parser.h" // only for generateChildId() +#include +#include +#include +#include +#include +#include +#include +#include +#include "node-translator.h" +#include "md5.h" + +namespace capnp { +namespace compiler { + +class Compiler::Alias { +public: + Alias(CompiledModule& module, Node& parent, const Expression::Reader& targetName) + : module(module), parent(parent), targetName(targetName) {} + + kj::Maybe compile(); + +private: + CompiledModule& module; + Node& parent; + Expression::Reader targetName; + kj::Maybe target; + Orphan brandOrphan; + bool initialized = false; +}; + +class Compiler::Node final: public NodeTranslator::Resolver { + // Passes through four states: + // - Stub: On initial construction, the Node is just a placeholder object. Its ID has been + // determined, and it is placed in its parent's member table as well as the compiler's + // nodes-by-ID table. + // - Expanded: Nodes have been constructed for all of this Node's nested children. This happens + // the first time a lookup is performed for one of those children. + // - Bootstrap: A NodeTranslator has been built and advanced to the bootstrap phase. + // - Finished: A final Schema object has been constructed. + +public: + explicit Node(CompiledModule& module); + // Create a root node representing the given file. May + + Node(Node& parent, const Declaration::Reader& declaration); + // Create a child node. + + Node(kj::StringPtr name, Declaration::Which kind, + List::Reader genericParams); + // Create a dummy node representing a built-in declaration, like "Int32" or "true". + + uint64_t getId() { return id; } + uint getParameterCount() { return genericParamCount; } + Declaration::Which getKind() { return kind; } + + kj::Maybe getBootstrapSchema(); + kj::Maybe getFinalSchema(); + void loadFinalSchema(const SchemaLoader& loader); + + void traverse(uint eagerness, std::unordered_map& seen, + const SchemaLoader& finalLoader); + // Get the final schema for this node, and also possibly traverse the node's children and + // dependencies to ensure that they are loaded, depending on the mode. + + void addError(kj::StringPtr error); + // Report an error on this Node. + + // implements NodeTranslator::Resolver ----------------------------- + kj::Maybe resolve(kj::StringPtr name) override; + kj::Maybe resolveMember(kj::StringPtr name) override; + ResolvedDecl resolveBuiltin(Declaration::Which which) override; + ResolvedDecl resolveId(uint64_t id) override; + kj::Maybe getParent() override; + ResolvedDecl getTopScope() override; + kj::Maybe resolveBootstrapSchema( + uint64_t id, schema::Brand::Reader brand) override; + kj::Maybe resolveFinalSchema(uint64_t id) override; + kj::Maybe resolveImport(kj::StringPtr name) override; + kj::Maybe> readEmbed(kj::StringPtr name) override; + kj::Maybe resolveBootstrapType(schema::Type::Reader type, Schema scope) override; + +private: + CompiledModule* module; // null iff isBuiltin is true + kj::Maybe parent; + + Declaration::Reader declaration; + // AST of the declaration parsed from the schema file. May become invalid once the content + // state has reached FINISHED. + + uint64_t id; + // The ID of this node, either taken from the AST or computed based on the parent. Or, a dummy + // value, if duplicates were detected. + + kj::StringPtr displayName; + // Fully-qualified display name for this node. For files, this is just the file name, otherwise + // it is "filename:Path.To.Decl". + + Declaration::Which kind; + // Kind of node. + + uint genericParamCount; + // Number of generic parameters. + + bool isBuiltin; + // Whether this is a bulit-in declaration, like "Int32" or "true". + + uint32_t startByte; + uint32_t endByte; + // Start and end byte for reporting general errors. + + struct Content { + inline Content(): state(STUB) {} + + enum State { + STUB, + EXPANDED, + BOOTSTRAP, + FINISHED + }; + State state; + // Indicates which fields below are valid. + + inline bool stateHasReached(State minimumState) { + return state >= minimumState; + } + inline void advanceState(State newState) { + state = newState; + } + + // EXPANDED ------------------------------------ + + typedef std::multimap> NestedNodesMap; + NestedNodesMap nestedNodes; + kj::Vector orderedNestedNodes; + // multimap in case of duplicate member names -- we still want to compile them, even if it's an + // error. + + typedef std::multimap> AliasMap; + AliasMap aliases; + // The "using" declarations. These are just links to nodes elsewhere. + + // BOOTSTRAP ----------------------------------- + + NodeTranslator* translator; + // Node translator, allocated in the bootstrap arena. + + kj::Maybe bootstrapSchema; + // The schema built in the bootstrap loader. Null if the bootstrap loader threw an exception. + + // FINISHED ------------------------------------ + + kj::Maybe finalSchema; + // The completed schema, ready to load into the real schema loader. + + kj::Array auxSchemas; + // Schemas for all auxiliary nodes built by the NodeTranslator. + }; + + Content guardedContent; // Read using getContent() only! + bool inGetContent = false; // True while getContent() is running; detects cycles. + + kj::Maybe loadedFinalSchema; + // Copy of `finalSchema` as loaded into the final schema loader. This doesn't go away if the + // workspace is destroyed. + + // --------------------------------------------- + + static uint64_t generateId(uint64_t parentId, kj::StringPtr declName, + Declaration::Id::Reader declId); + // Extract the ID from the declaration, or if it has none, generate one based on the name and + // parent ID. + + static kj::StringPtr joinDisplayName(kj::Arena& arena, Node& parent, kj::StringPtr declName); + // Join the parent's display name with the child's unqualified name to construct the child's + // display name. + + kj::Maybe getContent(Content::State minimumState); + // Advances the content to at least the given state and returns it. Returns null if getContent() + // is being called recursively and the given state has not yet been reached, as this indicates + // that the declaration recursively depends on itself. + + void traverseNodeDependencies(const schema::Node::Reader& schemaNode, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader); + void traverseType(const schema::Type::Reader& type, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader); + void traverseBrand(const schema::Brand::Reader& brand, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader); + void traverseAnnotations(const List::Reader& annotations, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader); + void traverseDependency(uint64_t depId, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader, + bool ignoreIfNotFound = false); + // Helpers for traverse(). +}; + +class Compiler::CompiledModule { +public: + CompiledModule(Compiler::Impl& compiler, Module& parserModule); + + Compiler::Impl& getCompiler() { return compiler; } + + ErrorReporter& getErrorReporter() { return parserModule; } + ParsedFile::Reader getParsedFile() { return content.getReader(); } + Node& getRootNode() { return rootNode; } + kj::StringPtr getSourceName() { return parserModule.getSourceName(); } + + kj::Maybe importRelative(kj::StringPtr importPath); + kj::Maybe> embedRelative(kj::StringPtr importPath); + + Orphan> + getFileImportTable(Orphanage orphanage); + +private: + Compiler::Impl& compiler; + Module& parserModule; + MallocMessageBuilder contentArena; + Orphan content; + Node rootNode; +}; + +class Compiler::Impl: public SchemaLoader::LazyLoadCallback { +public: + explicit Impl(AnnotationFlag annotationFlag); + virtual ~Impl() noexcept(false); + + uint64_t add(Module& module); + kj::Maybe lookup(uint64_t parent, kj::StringPtr childName); + Orphan> + getFileImportTable(Module& module, Orphanage orphanage); + void eagerlyCompile(uint64_t id, uint eagerness, const SchemaLoader& loader); + CompiledModule& addInternal(Module& parsedModule); + + struct Workspace { + // Scratch space where stuff can be allocated while working. The Workspace is available + // whenever nodes are actively being compiled, then is destroyed once control exits the + // compiler. Note that since nodes are compiled lazily, a new Workspace may have to be + // constructed in order to compile more nodes later. + + MallocMessageBuilder message; + Orphanage orphanage; + // Orphanage for allocating temporary Cap'n Proto objects. + + kj::Arena arena; + // Arena for allocating temporary native objects. Note that objects in `arena` may contain + // pointers into `message` that will be manipulated on destruction, so `arena` must be declared + // after `message`. + + SchemaLoader bootstrapLoader; + // Loader used to load bootstrap schemas. The bootstrap schema nodes are similar to the final + // versions except that any value expressions which depend on knowledge of other types (e.g. + // default values for struct fields) are left unevaluated (the values in the schema are empty). + // These bootstrap schemas can then be plugged into the dynamic API and used to evaluate these + // remaining values. + + inline explicit Workspace(const SchemaLoader::LazyLoadCallback& loaderCallback) + : orphanage(message.getOrphanage()), + bootstrapLoader(loaderCallback) {} + }; + + kj::Arena& getNodeArena() { return nodeArena; } + // Arena where nodes and other permanent objects should be allocated. + + Workspace& getWorkspace() { return workspace; } + // Temporary workspace that can be used to construct bootstrap objects. + + inline bool shouldCompileAnnotations() { + return annotationFlag == AnnotationFlag::COMPILE_ANNOTATIONS; + } + + void clearWorkspace(); + // Reset the temporary workspace. + + uint64_t addNode(uint64_t desiredId, Node& node); + // Add the given node to the by-ID map under the given ID. If another node with the same ID + // already exists, choose a new one arbitrarily and use that instead. Return the ID that was + // finally used. + + kj::Maybe findNode(uint64_t id); + + kj::Maybe lookupBuiltin(kj::StringPtr name); + Node& getBuiltin(Declaration::Which which); + + void load(const SchemaLoader& loader, uint64_t id) const override; + // SchemaLoader callback for the bootstrap loader. + + void loadFinal(const SchemaLoader& loader, uint64_t id); + // Called from the SchemaLoader callback for the final loader. + +private: + AnnotationFlag annotationFlag; + + kj::Arena nodeArena; + // Arena used to allocate nodes and other permanent objects. + + std::unordered_map> modules; + // Map of parser modules to compiler modules. + + Workspace workspace; + // The temporary workspace. This field must be declared after `modules` because objects + // allocated in the workspace may hold references to the compiled modules in `modules`. + + std::unordered_map nodesById; + // Map of nodes by ID. + + std::map> builtinDecls; + std::map builtinDeclsByKind; + // Map of built-in declarations, like "Int32" and "List", which make up the global scope. + + uint64_t nextBogusId = 1000; + // Counter for assigning bogus IDs to nodes whose real ID is a duplicate. +}; + +// ======================================================================================= + +kj::Maybe Compiler::Alias::compile() { + if (!initialized) { + initialized = true; + + auto& workspace = module.getCompiler().getWorkspace(); + brandOrphan = workspace.orphanage.newOrphan(); + + // If the Workspace is destroyed, revert the alias to the uninitialized state, because the + // orphan we created is no longer valid in this case. + workspace.arena.copy(kj::defer([this]() { + initialized = false; + brandOrphan = Orphan(); + })); + + target = NodeTranslator::compileDecl( + parent.getId(), parent.getParameterCount(), parent, + module.getErrorReporter(), targetName, brandOrphan.get()); + } + + return target; +} + +// ======================================================================================= + +Compiler::Node::Node(CompiledModule& module) + : module(&module), + parent(nullptr), + declaration(module.getParsedFile().getRoot()), + id(generateId(0, declaration.getName().getValue(), declaration.getId())), + displayName(module.getSourceName()), + kind(declaration.which()), + genericParamCount(declaration.getParameters().size()), + isBuiltin(false) { + auto name = declaration.getName(); + if (name.getValue().size() > 0) { + startByte = name.getStartByte(); + endByte = name.getEndByte(); + } else { + startByte = declaration.getStartByte(); + endByte = declaration.getEndByte(); + } + + id = module.getCompiler().addNode(id, *this); +} + +Compiler::Node::Node(Node& parent, const Declaration::Reader& declaration) + : module(parent.module), + parent(parent), + declaration(declaration), + id(generateId(parent.id, declaration.getName().getValue(), declaration.getId())), + displayName(joinDisplayName(parent.module->getCompiler().getNodeArena(), + parent, declaration.getName().getValue())), + kind(declaration.which()), + genericParamCount(declaration.getParameters().size()), + isBuiltin(false) { + auto name = declaration.getName(); + if (name.getValue().size() > 0) { + startByte = name.getStartByte(); + endByte = name.getEndByte(); + } else { + startByte = declaration.getStartByte(); + endByte = declaration.getEndByte(); + } + + id = module->getCompiler().addNode(id, *this); +} + +Compiler::Node::Node(kj::StringPtr name, Declaration::Which kind, + List::Reader genericParams) + : module(nullptr), + parent(nullptr), + // It's helpful if these have unique IDs. Real type IDs can't be under 2^31 anyway. + id(1000 + static_cast(kind)), + displayName(name), + kind(kind), + genericParamCount(genericParams.size()), + isBuiltin(true), + startByte(0), + endByte(0) {} + +uint64_t Compiler::Node::generateId(uint64_t parentId, kj::StringPtr declName, + Declaration::Id::Reader declId) { + if (declId.isUid()) { + return declId.getUid().getValue(); + } + + return generateChildId(parentId, declName); +} + +kj::StringPtr Compiler::Node::joinDisplayName( + kj::Arena& arena, Node& parent, kj::StringPtr declName) { + kj::ArrayPtr result = arena.allocateArray( + parent.displayName.size() + declName.size() + 2); + + size_t separatorPos = parent.displayName.size(); + memcpy(result.begin(), parent.displayName.begin(), separatorPos); + result[separatorPos] = parent.parent == nullptr ? ':' : '.'; + memcpy(result.begin() + separatorPos + 1, declName.begin(), declName.size()); + result[result.size() - 1] = '\0'; + return kj::StringPtr(result.begin(), result.size() - 1); +} + +kj::Maybe Compiler::Node::getContent(Content::State minimumState) { + KJ_REQUIRE(!isBuiltin, "illegal method call for built-in declaration"); + + auto& content = guardedContent; + + if (content.stateHasReached(minimumState)) { + return content; + } + + if (inGetContent) { + addError("Declaration recursively depends on itself."); + return nullptr; + } + + inGetContent = true; + KJ_DEFER(inGetContent = false); + + switch (content.state) { + case Content::STUB: { + if (minimumState <= Content::STUB) break; + + // Expand the child nodes. + auto& arena = module->getCompiler().getNodeArena(); + + for (auto nestedDecl: declaration.getNestedDecls()) { + switch (nestedDecl.which()) { + case Declaration::FILE: + case Declaration::CONST: + case Declaration::ANNOTATION: + case Declaration::ENUM: + case Declaration::STRUCT: + case Declaration::INTERFACE: { + kj::Own subNode = arena.allocateOwn(*this, nestedDecl); + kj::StringPtr name = nestedDecl.getName().getValue(); + content.orderedNestedNodes.add(subNode); + content.nestedNodes.insert(std::make_pair(name, kj::mv(subNode))); + break; + } + + case Declaration::USING: { + kj::Own alias = arena.allocateOwn( + *module, *this, nestedDecl.getUsing().getTarget()); + kj::StringPtr name = nestedDecl.getName().getValue(); + content.aliases.insert(std::make_pair(name, kj::mv(alias))); + break; + } + case Declaration::ENUMERANT: + case Declaration::FIELD: + case Declaration::UNION: + case Declaration::GROUP: + case Declaration::METHOD: + case Declaration::NAKED_ID: + case Declaration::NAKED_ANNOTATION: + // Not a node. Skip. + break; + default: + KJ_FAIL_ASSERT("unknown declaration type", nestedDecl); + break; + } + } + + content.advanceState(Content::EXPANDED); + // no break + } + + case Content::EXPANDED: { + if (minimumState <= Content::EXPANDED) break; + + // Construct the NodeTranslator. + auto& workspace = module->getCompiler().getWorkspace(); + + auto schemaNode = workspace.orphanage.newOrphan(); + auto builder = schemaNode.get(); + builder.setId(id); + builder.setDisplayName(displayName); + // TODO(cleanup): Would be better if we could remember the prefix length from before we + // added this decl's name to the end. + KJ_IF_MAYBE(lastDot, displayName.findLast('.')) { + builder.setDisplayNamePrefixLength(*lastDot + 1); + } + KJ_IF_MAYBE(lastColon, displayName.findLast(':')) { + if (*lastColon > builder.getDisplayNamePrefixLength()) { + builder.setDisplayNamePrefixLength(*lastColon + 1); + } + } + KJ_IF_MAYBE(p, parent) { + builder.setScopeId(p->id); + } + + auto nestedNodes = builder.initNestedNodes(content.orderedNestedNodes.size()); + auto nestedIter = nestedNodes.begin(); + for (auto node: content.orderedNestedNodes) { + nestedIter->setName(node->declaration.getName().getValue()); + nestedIter->setId(node->id); + ++nestedIter; + } + + content.translator = &workspace.arena.allocate( + *this, module->getErrorReporter(), declaration, kj::mv(schemaNode), + module->getCompiler().shouldCompileAnnotations()); + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){ + auto nodeSet = content.translator->getBootstrapNode(); + for (auto& auxNode: nodeSet.auxNodes) { + workspace.bootstrapLoader.loadOnce(auxNode); + } + content.bootstrapSchema = workspace.bootstrapLoader.loadOnce(nodeSet.node); + })) { + content.bootstrapSchema = nullptr; + // Only bother to report validation failures if we think we haven't seen any errors. + // Otherwise we assume that the errors caused the validation failure. + if (!module->getErrorReporter().hadErrors()) { + addError(kj::str("Internal compiler bug: Bootstrap schema failed validation:\n", + *exception)); + } + } + + // If the Workspace is destroyed, revert the node to the EXPANDED state, because the + // NodeTranslator is no longer valid in this case. + workspace.arena.copy(kj::defer([&content]() { + content.bootstrapSchema = nullptr; + if (content.state > Content::EXPANDED) { + content.state = Content::EXPANDED; + } + })); + + content.advanceState(Content::BOOTSTRAP); + // no break + } + + case Content::BOOTSTRAP: { + if (minimumState <= Content::BOOTSTRAP) break; + + // Create the final schema. + auto nodeSet = content.translator->finish(); + content.finalSchema = nodeSet.node; + content.auxSchemas = kj::mv(nodeSet.auxNodes); + + content.advanceState(Content::FINISHED); + // no break + } + + case Content::FINISHED: + break; + } + + return content; +} + +kj::Maybe Compiler::Node::getBootstrapSchema() { + KJ_IF_MAYBE(schema, loadedFinalSchema) { + // We don't need to rebuild the bootstrap schema if we already have a final schema. + return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*schema); + } else KJ_IF_MAYBE(content, getContent(Content::BOOTSTRAP)) { + if (content->state == Content::FINISHED && content->bootstrapSchema == nullptr) { + // The bootstrap schema was discarded. Copy it from the final schema. + // (We can't just return the final schema because using it could trigger schema loader + // callbacks that would deadlock.) + KJ_IF_MAYBE(finalSchema, content->finalSchema) { + return module->getCompiler().getWorkspace().bootstrapLoader.loadOnce(*finalSchema); + } else { + return nullptr; + } + } else { + return content->bootstrapSchema; + } + } else { + return nullptr; + } +} +kj::Maybe Compiler::Node::getFinalSchema() { + KJ_IF_MAYBE(schema, loadedFinalSchema) { + return *schema; + } else KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { + return content->finalSchema; + } else { + return nullptr; + } +} +void Compiler::Node::loadFinalSchema(const SchemaLoader& loader) { + KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&](){ + KJ_IF_MAYBE(finalSchema, content->finalSchema) { + KJ_MAP(auxSchema, content->auxSchemas) { + return loader.loadOnce(auxSchema); + }; + loadedFinalSchema = loader.loadOnce(*finalSchema).getProto(); + } + })) { + // Schema validation threw an exception. + + // Don't try loading this again. + content->finalSchema = nullptr; + + // Only bother to report validation failures if we think we haven't seen any errors. + // Otherwise we assume that the errors caused the validation failure. + if (!module->getErrorReporter().hadErrors()) { + addError(kj::str("Internal compiler bug: Schema failed validation:\n", *exception)); + } + } + } +} + +void Compiler::Node::traverse(uint eagerness, std::unordered_map& seen, + const SchemaLoader& finalLoader) { + uint& slot = seen[this]; + if ((slot & eagerness) == eagerness) { + // We've already covered this node. + return; + } + slot |= eagerness; + + KJ_IF_MAYBE(content, getContent(Content::FINISHED)) { + loadFinalSchema(finalLoader); + + KJ_IF_MAYBE(schema, getFinalSchema()) { + if (eagerness / DEPENDENCIES != 0) { + // For traversing dependencies, discard the bits lower than DEPENDENCIES and replace + // them with the bits above DEPENDENCIES shifted over. + uint newEagerness = (eagerness & ~(DEPENDENCIES - 1)) | (eagerness / DEPENDENCIES); + + traverseNodeDependencies(*schema, newEagerness, seen, finalLoader); + for (auto& aux: content->auxSchemas) { + traverseNodeDependencies(aux, newEagerness, seen, finalLoader); + } + } + } + } + + if (eagerness & PARENTS) { + KJ_IF_MAYBE(p, parent) { + p->traverse(eagerness, seen, finalLoader); + } + } + + if (eagerness & CHILDREN) { + KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) { + for (auto& child: content->orderedNestedNodes) { + child->traverse(eagerness, seen, finalLoader); + } + + // Also traverse `using` declarations. + for (auto& child: content->aliases) { + child.second->compile(); + } + } + } +} + +void Compiler::Node::traverseNodeDependencies( + const schema::Node::Reader& schemaNode, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader) { + switch (schemaNode.which()) { + case schema::Node::STRUCT: + for (auto field: schemaNode.getStruct().getFields()) { + switch (field.which()) { + case schema::Field::SLOT: + traverseType(field.getSlot().getType(), eagerness, seen, finalLoader); + break; + case schema::Field::GROUP: + // Aux node will be scanned later. + break; + } + + traverseAnnotations(field.getAnnotations(), eagerness, seen, finalLoader); + } + break; + + case schema::Node::ENUM: + for (auto enumerant: schemaNode.getEnum().getEnumerants()) { + traverseAnnotations(enumerant.getAnnotations(), eagerness, seen, finalLoader); + } + break; + + case schema::Node::INTERFACE: { + auto interface = schemaNode.getInterface(); + for (auto superclass: interface.getSuperclasses()) { + uint64_t superclassId = superclass.getId(); + if (superclassId != 0) { // if zero, we reported an error earlier + traverseDependency(superclassId, eagerness, seen, finalLoader); + } + traverseBrand(superclass.getBrand(), eagerness, seen, finalLoader); + } + for (auto method: interface.getMethods()) { + traverseDependency(method.getParamStructType(), eagerness, seen, finalLoader, true); + traverseBrand(method.getParamBrand(), eagerness, seen, finalLoader); + traverseDependency(method.getResultStructType(), eagerness, seen, finalLoader, true); + traverseBrand(method.getResultBrand(), eagerness, seen, finalLoader); + traverseAnnotations(method.getAnnotations(), eagerness, seen, finalLoader); + } + break; + } + + case schema::Node::CONST: + traverseType(schemaNode.getConst().getType(), eagerness, seen, finalLoader); + break; + + case schema::Node::ANNOTATION: + traverseType(schemaNode.getAnnotation().getType(), eagerness, seen, finalLoader); + break; + + default: + break; + } + + traverseAnnotations(schemaNode.getAnnotations(), eagerness, seen, finalLoader); +} + +void Compiler::Node::traverseType(const schema::Type::Reader& type, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader) { + uint64_t id = 0; + schema::Brand::Reader brand; + switch (type.which()) { + case schema::Type::STRUCT: + id = type.getStruct().getTypeId(); + brand = type.getStruct().getBrand(); + break; + case schema::Type::ENUM: + id = type.getEnum().getTypeId(); + brand = type.getEnum().getBrand(); + break; + case schema::Type::INTERFACE: + id = type.getInterface().getTypeId(); + brand = type.getInterface().getBrand(); + break; + case schema::Type::LIST: + traverseType(type.getList().getElementType(), eagerness, seen, finalLoader); + return; + default: + return; + } + + traverseDependency(id, eagerness, seen, finalLoader); + traverseBrand(brand, eagerness, seen, finalLoader); +} + +void Compiler::Node::traverseBrand( + const schema::Brand::Reader& brand, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader) { + for (auto scope: brand.getScopes()) { + switch (scope.which()) { + case schema::Brand::Scope::BIND: + for (auto binding: scope.getBind()) { + switch (binding.which()) { + case schema::Brand::Binding::UNBOUND: + break; + case schema::Brand::Binding::TYPE: + traverseType(binding.getType(), eagerness, seen, finalLoader); + break; + } + } + break; + case schema::Brand::Scope::INHERIT: + break; + } + } +} + +void Compiler::Node::traverseDependency(uint64_t depId, uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader, + bool ignoreIfNotFound) { + KJ_IF_MAYBE(node, module->getCompiler().findNode(depId)) { + node->traverse(eagerness, seen, finalLoader); + } else if (!ignoreIfNotFound) { + KJ_FAIL_ASSERT("Dependency ID not present in compiler?", depId); + } +} + +void Compiler::Node::traverseAnnotations(const List::Reader& annotations, + uint eagerness, + std::unordered_map& seen, + const SchemaLoader& finalLoader) { + for (auto annotation: annotations) { + KJ_IF_MAYBE(node, module->getCompiler().findNode(annotation.getId())) { + node->traverse(eagerness, seen, finalLoader); + } + } +} + + +void Compiler::Node::addError(kj::StringPtr error) { + module->getErrorReporter().addError(startByte, endByte, error); +} + +kj::Maybe +Compiler::Node::resolve(kj::StringPtr name) { + // Check members. + KJ_IF_MAYBE(member, resolveMember(name)) { + return *member; + } + + // Check parameters. + // TODO(perf): Maintain a map? + auto params = declaration.getParameters(); + for (uint i: kj::indices(params)) { + if (params[i].getName() == name) { + ResolveResult result; + result.init(ResolvedParameter {id, i}); + return result; + } + } + + // Check parent scope. + KJ_IF_MAYBE(p, parent) { + return p->resolve(name); + } else KJ_IF_MAYBE(b, module->getCompiler().lookupBuiltin(name)) { + ResolveResult result; + result.init(ResolvedDecl { b->id, b->genericParamCount, 0, b->kind, b, nullptr }); + return result; + } else { + return nullptr; + } +} + +kj::Maybe +Compiler::Node::resolveMember(kj::StringPtr name) { + if (isBuiltin) return nullptr; + + KJ_IF_MAYBE(content, getContent(Content::EXPANDED)) { + { + auto iter = content->nestedNodes.find(name); + if (iter != content->nestedNodes.end()) { + Node* node = iter->second; + ResolveResult result; + result.init(ResolvedDecl { + node->id, node->genericParamCount, id, node->kind, node, nullptr }); + return result; + } + } + { + auto iter = content->aliases.find(name); + if (iter != content->aliases.end()) { + return iter->second->compile(); + } + } + } + return nullptr; +} + +NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveBuiltin(Declaration::Which which) { + auto& b = module->getCompiler().getBuiltin(which); + return { b.id, b.genericParamCount, 0, b.kind, &b, nullptr }; +} + +NodeTranslator::Resolver::ResolvedDecl Compiler::Node::resolveId(uint64_t id) { + auto& n = KJ_ASSERT_NONNULL(module->getCompiler().findNode(id)); + uint64_t parentId = n.parent.map([](Node& n) { return n.id; }).orDefault(0); + return { n.id, n.genericParamCount, parentId, n.kind, &n, nullptr }; +} + +kj::Maybe Compiler::Node::getParent() { + return parent.map([](Node& parent) { + uint64_t scopeId = parent.parent.map([](Node& gp) { return gp.id; }).orDefault(0); + return ResolvedDecl { parent.id, parent.genericParamCount, scopeId, parent.kind, &parent, nullptr }; + }); +} + +NodeTranslator::Resolver::ResolvedDecl Compiler::Node::getTopScope() { + Node& node = module->getRootNode(); + return ResolvedDecl { node.id, 0, 0, node.kind, &node, nullptr }; +} + +kj::Maybe Compiler::Node::resolveBootstrapSchema( + uint64_t id, schema::Brand::Reader brand) { + KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { + // Make sure the bootstrap schema is loaded into the SchemaLoader. + if (node->getBootstrapSchema() == nullptr) { + return nullptr; + } + + // Now we actually invoke get() to evaluate the brand. + return module->getCompiler().getWorkspace().bootstrapLoader.get(id, brand); + } else { + KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before."); + } +} + +kj::Maybe Compiler::Node::resolveFinalSchema(uint64_t id) { + KJ_IF_MAYBE(node, module->getCompiler().findNode(id)) { + return node->getFinalSchema(); + } else { + KJ_FAIL_REQUIRE("Tried to get schema for ID we haven't seen before."); + } +} + +kj::Maybe +Compiler::Node::resolveImport(kj::StringPtr name) { + KJ_IF_MAYBE(m, module->importRelative(name)) { + Node& root = m->getRootNode(); + return ResolvedDecl { root.id, 0, 0, root.kind, &root, nullptr }; + } else { + return nullptr; + } +} + +kj::Maybe> Compiler::Node::readEmbed(kj::StringPtr name) { + return module->embedRelative(name); +} + +kj::Maybe Compiler::Node::resolveBootstrapType(schema::Type::Reader type, Schema scope) { + // TODO(someday): Arguably should return null if the type or its dependencies are placeholders. + + kj::Maybe result; + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + result = module->getCompiler().getWorkspace().bootstrapLoader.getType(type, scope); + })) { + result = nullptr; + if (!module->getErrorReporter().hadErrors()) { + addError(kj::str("Internal compiler bug: Bootstrap schema failed to load:\n", + *exception)); + } + } + return result; +} + +// ======================================================================================= + +Compiler::CompiledModule::CompiledModule(Compiler::Impl& compiler, Module& parserModule) + : compiler(compiler), parserModule(parserModule), + content(parserModule.loadContent(contentArena.getOrphanage())), + rootNode(*this) {} + +kj::Maybe Compiler::CompiledModule::importRelative( + kj::StringPtr importPath) { + return parserModule.importRelative(importPath).map( + [this](Module& module) -> Compiler::CompiledModule& { + return compiler.addInternal(module); + }); +} + +kj::Maybe> Compiler::CompiledModule::embedRelative(kj::StringPtr embedPath) { + return parserModule.embedRelative(embedPath); +} + +static void findImports(Expression::Reader exp, std::set& output) { + switch (exp.which()) { + case Expression::UNKNOWN: + case Expression::POSITIVE_INT: + case Expression::NEGATIVE_INT: + case Expression::FLOAT: + case Expression::STRING: + case Expression::BINARY: + case Expression::RELATIVE_NAME: + case Expression::ABSOLUTE_NAME: + case Expression::EMBED: + break; + + case Expression::IMPORT: + output.insert(exp.getImport().getValue()); + break; + + case Expression::LIST: + for (auto element: exp.getList()) { + findImports(element, output); + } + break; + + case Expression::TUPLE: + for (auto element: exp.getTuple()) { + findImports(element.getValue(), output); + } + break; + + case Expression::APPLICATION: { + auto app = exp.getApplication(); + findImports(app.getFunction(), output); + for (auto param: app.getParams()) { + findImports(param.getValue(), output); + } + break; + } + + case Expression::MEMBER: { + findImports(exp.getMember().getParent(), output); + break; + } + } +} + +static void findImports(Declaration::Reader decl, std::set& output) { + switch (decl.which()) { + case Declaration::USING: + findImports(decl.getUsing().getTarget(), output); + break; + case Declaration::CONST: + findImports(decl.getConst().getType(), output); + break; + case Declaration::FIELD: + findImports(decl.getField().getType(), output); + break; + case Declaration::INTERFACE: + for (auto superclass: decl.getInterface().getSuperclasses()) { + findImports(superclass, output); + } + break; + case Declaration::METHOD: { + auto method = decl.getMethod(); + + auto params = method.getParams(); + if (params.isNamedList()) { + for (auto param: params.getNamedList()) { + findImports(param.getType(), output); + for (auto ann: param.getAnnotations()) { + findImports(ann.getName(), output); + } + } + } else { + findImports(params.getType(), output); + } + + if (method.getResults().isExplicit()) { + auto results = method.getResults().getExplicit(); + if (results.isNamedList()) { + for (auto param: results.getNamedList()) { + findImports(param.getType(), output); + for (auto ann: param.getAnnotations()) { + findImports(ann.getName(), output); + } + } + } else { + findImports(results.getType(), output); + } + } + break; + } + default: + break; + } + + for (auto ann: decl.getAnnotations()) { + findImports(ann.getName(), output); + } + + for (auto nested: decl.getNestedDecls()) { + findImports(nested, output); + } +} + +Orphan> + Compiler::CompiledModule::getFileImportTable(Orphanage orphanage) { + // Build a table of imports for CodeGeneratorRequest.RequestedFile.imports. Note that we only + // care about type imports, not constant value imports, since constant values (including default + // values) are already embedded in full in the schema. In other words, we only need the imports + // that would need to be #included in the generated code. + + std::set importNames; + findImports(content.getReader().getRoot(), importNames); + + auto result = orphanage.newOrphan>( + importNames.size()); + auto builder = result.get(); + + uint i = 0; + for (auto name: importNames) { + // We presumably ran this import before, so it shouldn't throw now. + auto entry = builder[i++]; + entry.setId(KJ_ASSERT_NONNULL(importRelative(name)).rootNode.getId()); + entry.setName(name); + } + + return result; +} + +// ======================================================================================= + +Compiler::Impl::Impl(AnnotationFlag annotationFlag) + : annotationFlag(annotationFlag), workspace(*this) { + // Reflectively interpret the members of Declaration.body. Any member prefixed by "builtin" + // defines a builtin declaration visible in the global scope. + + StructSchema declSchema = Schema::from(); + for (auto field: declSchema.getFields()) { + auto fieldProto = field.getProto(); + if (fieldProto.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT) { + auto name = fieldProto.getName(); + if (name.startsWith("builtin")) { + kj::StringPtr symbolName = name.slice(strlen("builtin")); + + List::Reader params; + for (auto annotation: fieldProto.getAnnotations()) { + if (annotation.getId() == 0x94099c3f9eb32d6bull) { + params = annotation.getValue().getList().getAs>(); + break; + } + } + + Declaration::Which which = + static_cast(fieldProto.getDiscriminantValue()); + kj::Own newNode = nodeArena.allocateOwn(symbolName, which, params); + builtinDeclsByKind[which] = newNode; + builtinDecls[symbolName] = kj::mv(newNode); + } + } + } +} + +Compiler::Impl::~Impl() noexcept(false) {} + +void Compiler::Impl::clearWorkspace() { + // Make sure we reconstruct the workspace even if destroying it throws an exception. + KJ_DEFER(kj::ctor(workspace, *this)); + kj::dtor(workspace); +} + +Compiler::CompiledModule& Compiler::Impl::addInternal(Module& parsedModule) { + kj::Own& slot = modules[&parsedModule]; + if (slot.get() == nullptr) { + slot = kj::heap(*this, parsedModule); + } + + return *slot; +} + +uint64_t Compiler::Impl::addNode(uint64_t desiredId, Node& node) { + for (;;) { + auto insertResult = nodesById.insert(std::make_pair(desiredId, &node)); + if (insertResult.second) { + return desiredId; + } + + // Only report an error if this ID is not bogus. Actual IDs specified in the original source + // code are required to have the upper bit set. Anything else must have been manufactured + // at some point to cover up an error. + if (desiredId & (1ull << 63)) { + node.addError(kj::str("Duplicate ID @0x", kj::hex(desiredId), ".")); + insertResult.first->second->addError( + kj::str("ID @0x", kj::hex(desiredId), " originally used here.")); + } + + // Assign a new bogus ID. + desiredId = nextBogusId++; + } +} + +kj::Maybe Compiler::Impl::findNode(uint64_t id) { + auto iter = nodesById.find(id); + if (iter == nodesById.end()) { + return nullptr; + } else { + return *iter->second; + } +} + +kj::Maybe Compiler::Impl::lookupBuiltin(kj::StringPtr name) { + auto iter = builtinDecls.find(name); + if (iter == builtinDecls.end()) { + return nullptr; + } else { + return *iter->second; + } +} + +Compiler::Node& Compiler::Impl::getBuiltin(Declaration::Which which) { + auto iter = builtinDeclsByKind.find(which); + KJ_REQUIRE(iter != builtinDeclsByKind.end(), "invalid builtin", (uint)which); + return *iter->second; +} + +uint64_t Compiler::Impl::add(Module& module) { + return addInternal(module).getRootNode().getId(); +} + +kj::Maybe Compiler::Impl::lookup(uint64_t parent, kj::StringPtr childName) { + // Looking up members does not use the workspace, so we don't need to lock it. + KJ_IF_MAYBE(parentNode, findNode(parent)) { + KJ_IF_MAYBE(child, parentNode->resolveMember(childName)) { + if (child->is()) { + return child->get().id; + } else { + // An alias. We don't support looking up aliases with this method. + return nullptr; + } + } else { + return nullptr; + } + } else { + KJ_FAIL_REQUIRE("lookup()s parameter 'parent' must be a known ID.", parent); + } +} + +Orphan> + Compiler::Impl::getFileImportTable(Module& module, Orphanage orphanage) { + return addInternal(module).getFileImportTable(orphanage); +} + +void Compiler::Impl::eagerlyCompile(uint64_t id, uint eagerness, + const SchemaLoader& finalLoader) { + KJ_IF_MAYBE(node, findNode(id)) { + std::unordered_map seen; + node->traverse(eagerness, seen, finalLoader); + } else { + KJ_FAIL_REQUIRE("id did not come from this Compiler.", id); + } +} + +void Compiler::Impl::load(const SchemaLoader& loader, uint64_t id) const { + // We know that this load() is only called from the bootstrap loader which is already protected + // by our mutex, so we can drop thread-safety. + auto& self = const_cast(*this); + + KJ_IF_MAYBE(node, self.findNode(id)) { + node->getBootstrapSchema(); + } +} + +void Compiler::Impl::loadFinal(const SchemaLoader& loader, uint64_t id) { + KJ_IF_MAYBE(node, findNode(id)) { + node->loadFinalSchema(loader); + } +} + +// ======================================================================================= + +Compiler::Compiler(AnnotationFlag annotationFlag) + : impl(kj::heap(annotationFlag)), + loader(*this) {} +Compiler::~Compiler() noexcept(false) {} + +uint64_t Compiler::add(Module& module) const { + return impl.lockExclusive()->get()->add(module); +} + +kj::Maybe Compiler::lookup(uint64_t parent, kj::StringPtr childName) const { + return impl.lockExclusive()->get()->lookup(parent, childName); +} + +Orphan> + Compiler::getFileImportTable(Module& module, Orphanage orphanage) const { + return impl.lockExclusive()->get()->getFileImportTable(module, orphanage); +} + +void Compiler::eagerlyCompile(uint64_t id, uint eagerness) const { + impl.lockExclusive()->get()->eagerlyCompile(id, eagerness, loader); +} + +void Compiler::clearWorkspace() const { + impl.lockExclusive()->get()->clearWorkspace(); +} + +void Compiler::load(const SchemaLoader& loader, uint64_t id) const { + impl.lockExclusive()->get()->loadFinal(loader, id); +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/compiler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/compiler.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,198 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPILER_COMPILER_H_ +#define CAPNP_COMPILER_COMPILER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include +#include "error-reporter.h" + +namespace capnp { +namespace compiler { + +class Module: public ErrorReporter { +public: + virtual kj::StringPtr getSourceName() = 0; + // The name of the module file relative to the source tree. Used to decide where to output + // generated code and to form the `displayName` in the schema. + + virtual Orphan loadContent(Orphanage orphanage) = 0; + // Loads the module content, using the given orphanage to allocate objects if necessary. + + virtual kj::Maybe importRelative(kj::StringPtr importPath) = 0; + // Find another module, relative to this one. Importing the same logical module twice should + // produce the exact same object, comparable by identity. These objects are owned by some + // outside pool that outlives the Compiler instance. + + virtual kj::Maybe> embedRelative(kj::StringPtr embedPath) = 0; + // Read and return the content of a file specified using `embed`. +}; + +class Compiler final: private SchemaLoader::LazyLoadCallback { + // Cross-links separate modules (schema files) and translates them into schema nodes. + // + // This class is thread-safe, hence all its methods are const. + +public: + enum AnnotationFlag { + COMPILE_ANNOTATIONS, + // Compile annotations normally. + + DROP_ANNOTATIONS + // Do not compile any annotations, eagerly or lazily. All "annotations" fields in the schema + // will be left empty. This is useful to avoid parsing imports that are used only for + // annotations which you don't intend to use anyway. + // + // Unfortunately annotations cannot simply be compiled lazily because filling in the + // "annotations" field at the usage site requires knowing the annotation's type, which requires + // compiling the annotation, and the schema API has no particular way to detect when you + // try to access the "annotations" field in order to lazily compile the annotations at that + // point. + }; + + explicit Compiler(AnnotationFlag annotationFlag = COMPILE_ANNOTATIONS); + ~Compiler() noexcept(false); + KJ_DISALLOW_COPY(Compiler); + + uint64_t add(Module& module) const; + // Add a module to the Compiler, returning the module's file ID. The ID can then be looked up in + // the `SchemaLoader` returned by `getLoader()`. However, the SchemaLoader may behave as if the + // schema node doesn't exist if any compilation errors occur (reported via the module's + // ErrorReporter). The module is parsed at the time `add()` is called, but not fully compiled -- + // individual schema nodes are compiled lazily. If you want to force eager compilation, + // see `eagerlyCompile()`, below. + + kj::Maybe lookup(uint64_t parent, kj::StringPtr childName) const; + // Given the type ID of a schema node, find the ID of a node nested within it. Throws an + // exception if the parent ID is not recognized; returns null if the parent has no child of the + // given name. Neither the parent nor the child schema node is actually compiled. + + Orphan> + getFileImportTable(Module& module, Orphanage orphanage) const; + // Build the import table for the CodeGeneratorRequest for the given module. + + enum Eagerness: uint32_t { + // Flags specifying how eager to be about compilation. These are intended to be bitwise OR'd. + // Used with the method `eagerlyCompile()`. + // + // Schema declarations can be compiled upfront, or they can be compiled lazily as they are + // needed. Usually, the difference is not observable, but it is not a perfect abstraction. + // The difference has the following effects: + // * `getLoader().getAllLoaded()` only returns the schema nodes which have been compiled so + // far. + // * `getLoader().get()` (i.e. searching for a schema by ID) can only find schema nodes that + // have either been compiled already, or which are referenced by schema nodes which have been + // compiled already. This means that if the ID you pass in came from another schema node + // compiled with the same compiler, there should be no observable difference, but if you + // have an ID from elsewhere which you _a priori_ expect is defined in a particular schema + // file, you will need to compile that file eagerly before you look up the node by ID. + // * Errors are reported when they are encountered, so some errors will not be reported until + // the node is actually compiled. + // * If an imported file is not needed, it will never even be read from disk. + // + // The last point is the main reason why you might want to prefer lazy compilation: it allows + // you to use a schema file with missing imports, so long as those missing imports are not + // actually needed. + // + // For example, the flag combo: + // EAGER_NODE | EAGER_CHILDREN | EAGER_DEPENDENCIES | EAGER_DEPENDENCY_PARENTS + // will compile the entire given module, plus all direct dependencies of anything in that + // module, plus all lexical ancestors of those dependencies. This is what the Cap'n Proto + // compiler uses when building initial code generator requests. + + ALL_RELATED_NODES = ~0u, + // Compile everything that is in any way related to the target node, including its entire + // containing file and everything transitively imported by it. + + NODE = 1 << 0, + // Eagerly compile the requested node, but not necessarily any of its parents, children, or + // dependencies. + + PARENTS = 1 << 1, + // Eagerly compile all lexical parents of the requested node. Only meaningful in conjuction + // with NODE. + + CHILDREN = 1 << 2, + // Eagerly compile all of the node's lexically nested nodes. Only meaningful in conjuction + // with NODE. + + DEPENDENCIES = NODE << 15, + // For all nodes compiled as a result of the above flags, also compile their direct + // dependencies. E.g. if Foo is a struct which contains a field of type Bar, and Foo is + // compiled, then also compile Bar. "Dependencies" are defined as field types, method + // parameter and return types, and annotation types. Nested types and outer types are not + // considered dependencies. + + DEPENDENCY_PARENTS = PARENTS * DEPENDENCIES, + DEPENDENCY_CHILDREN = CHILDREN * DEPENDENCIES, + DEPENDENCY_DEPENDENCIES = DEPENDENCIES * DEPENDENCIES, + // Like PARENTS, CHILDREN, and DEPENDENCIES, but applies relative to dependency nodes rather + // than the original requested node. Note that DEPENDENCY_DEPENDENCIES causes all transitive + // dependencies of the requested node to be compiled. + // + // These flags are defined as multiples of the original flag and DEPENDENCIES so that we + // can form the flags to use when traversing a dependency by shifting bits. + }; + + void eagerlyCompile(uint64_t id, uint eagerness) const; + // Force eager compilation of schema nodes related to the given ID. `eagerness` specifies which + // related nodes should be compiled before returning. It is a bitwise OR of the possible values + // of the `Eagerness` enum. + // + // If this returns and no errors have been reported, then it is guaranteed that the compiled + // nodes can be found in the SchemaLoader returned by `getLoader()`. + + const SchemaLoader& getLoader() const { return loader; } + SchemaLoader& getLoader() { return loader; } + // Get a SchemaLoader backed by this compiler. Schema nodes will be lazily constructed as you + // traverse them using this loader. + + void clearWorkspace() const; + // The compiler builds a lot of temporary tables and data structures while it works. It's + // useful to keep these around if more work is expected (especially if you are using lazy + // compilation and plan to look up Schema nodes that haven't already been seen), but once + // the SchemaLoader has everything you need, you can call clearWorkspace() to free up the + // temporary space. Note that it's safe to call clearWorkspace() even if you do expect to + // compile more nodes in the future; it may simply lead to redundant work if the discarded + // structures are needed again. + +private: + class Impl; + kj::MutexGuarded> impl; + SchemaLoader loader; + + class CompiledModule; + class Node; + class Alias; + + void load(const SchemaLoader& loader, uint64_t id) const override; +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_COMPILER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/error-reporter.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/error-reporter.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,68 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "error-reporter.h" +#include + +namespace capnp { +namespace compiler { + +namespace { + +template +static size_t findLargestElementBefore(const kj::Vector& vec, const T& key) { + KJ_REQUIRE(vec.size() > 0 && vec[0] <= key); + + size_t lower = 0; + size_t upper = vec.size(); + + while (upper - lower > 1) { + size_t mid = (lower + upper) / 2; + if (vec[mid] > key) { + upper = mid; + } else { + lower = mid; + } + } + + return lower; +} + +} // namespace + +LineBreakTable::LineBreakTable(kj::ArrayPtr content) + : lineBreaks(content.size() / 40) { + lineBreaks.add(0); + for (const char* pos = content.begin(); pos < content.end(); ++pos) { + if (*pos == '\n') { + lineBreaks.add(pos + 1 - content.begin()); + } + } +} + +GlobalErrorReporter::SourcePos LineBreakTable::toSourcePos(uint32_t byteOffset) const { + uint line = findLargestElementBefore(lineBreaks, byteOffset); + uint col = byteOffset - lineBreaks[line]; + return GlobalErrorReporter::SourcePos { byteOffset, line, col }; +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/error-reporter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/error-reporter.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,97 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef ERROR_REPORTER_H_ +#define ERROR_REPORTER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "../common.h" +#include +#include +#include + +namespace capnp { +namespace compiler { + +class ErrorReporter { + // Callback for reporting errors within a particular file. + +public: + virtual void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) = 0; + // Report an error at the given location in the input text. `startByte` and `endByte` indicate + // the span of text that is erroneous. They may be equal, in which case the parser was only + // able to identify where the error begins, not where it ends. + + template + inline void addErrorOn(T&& decl, kj::StringPtr message) { + // Works for any `T` that defines `getStartByte()` and `getEndByte()` methods, which many + // of the Cap'n Proto types defined in `grammar.capnp` do. + + addError(decl.getStartByte(), decl.getEndByte(), message); + } + + virtual bool hadErrors() = 0; + // Return true if any errors have been reported, globally. The main use case for this callback + // is to inhibit the reporting of errors which may have been caused by previous errors, or to + // allow the compiler to bail out entirely if it gets confused and thinks this could be because + // of previous errors. +}; + +class GlobalErrorReporter { + // Callback for reporting errors in any file. + +public: + struct SourcePos { + uint byte; + uint line; + uint column; + }; + + virtual void addError(kj::StringPtr file, SourcePos start, SourcePos end, + kj::StringPtr message) = 0; + // Report an error at the given location in the given file. + + virtual bool hadErrors() = 0; + // Return true if any errors have been reported, globally. The main use case for this callback + // is to inhibit the reporting of errors which may have been caused by previous errors, or to + // allow the compiler to bail out entirely if it gets confused and thinks this could be because + // of previous errors. +}; + +class LineBreakTable { +public: + LineBreakTable(kj::ArrayPtr content); + + GlobalErrorReporter::SourcePos toSourcePos(uint32_t byteOffset) const; + +private: + kj::Vector lineBreaks; + // Byte offsets of the first byte in each source line. The first element is always zero. + // Initialized the first time the module is loaded. +}; + +} // namespace compiler +} // namespace capnp + +#endif // ERROR_REPORTER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/evolution-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/evolution-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,911 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This is a fuzz test which randomly generates a schema for a struct one change at a time. +// Each modification is known a priori to be compatible or incompatible. The type is compiled +// before and after the change and both versions are loaded into a SchemaLoader with the +// expectation that this will succeed if they are compatible and fail if they are not. If +// the types are expected to be compatible, the test also constructs an instance of the old +// type and reads it as the new type, and vice versa. + +#include +#include +#include +#include +#include "compiler.h" +#include +#include +#include +#include +#include +#include +#include + +namespace capnp { +namespace compiler { +namespace { + +static const kj::StringPtr RFC3092[] = {"foo", "bar", "baz", "qux"}; + +template +T& chooseFrom(T (&arr)[size]) { + return arr[rand() % size]; +} +template +auto chooseFrom(T arr) -> decltype(arr[0]) { + return arr[rand() % arr.size()]; +} + +static Declaration::Builder addNested(Declaration::Builder parent) { + auto oldNestedOrphan = parent.disownNestedDecls(); + auto oldNested = oldNestedOrphan.get(); + auto newNested = parent.initNestedDecls(oldNested.size() + 1); + + uint index = rand() % (oldNested.size() + 1); + + for (uint i = 0; i < index; i++) { + newNested.setWithCaveats(i, oldNested[i]); + } + for (uint i = index + 1; i < newNested.size(); i++) { + newNested.setWithCaveats(i, oldNested[i - 1]); + } + + return newNested[index]; +} + +struct TypeOption { + kj::StringPtr name; + kj::ConstFunction makeValue; +}; + +static const TypeOption TYPE_OPTIONS[] = { + { "Int32", + [](Expression::Builder builder) { + builder.setPositiveInt(rand() % (1 << 24)); + }}, + { "Float64", + [](Expression::Builder builder) { + builder.setPositiveInt(rand()); + }}, + { "Int8", + [](Expression::Builder builder) { + builder.setPositiveInt(rand() % 128); + }}, + { "UInt16", + [](Expression::Builder builder) { + builder.setPositiveInt(rand() % (1 << 16)); + }}, + { "Bool", + [](Expression::Builder builder) { + builder.initRelativeName().setValue("true"); + }}, + { "Text", + [](Expression::Builder builder) { + builder.setString(chooseFrom(RFC3092)); + }}, + { "StructType", + [](Expression::Builder builder) { + auto assignment = builder.initTuple(1)[0]; + assignment.initNamed().setValue("i"); + assignment.initValue().setPositiveInt(rand() % (1 << 24)); + }}, + { "EnumType", + [](Expression::Builder builder) { + builder.initRelativeName().setValue(chooseFrom(RFC3092)); + }}, +}; + +void setDeclName(Expression::Builder decl, kj::StringPtr name) { + decl.initRelativeName().setValue(name); +} + +static kj::ConstFunction randomizeType(Expression::Builder type) { + auto option = &chooseFrom(TYPE_OPTIONS); + + if (rand() % 4 == 0) { + auto app = type.initApplication(); + setDeclName(app.initFunction(), "List"); + setDeclName(app.initParams(1)[0].initValue(), option->name); + return [option](Expression::Builder builder) { + for (auto element: builder.initList(rand() % 4 + 1)) { + option->makeValue(element); + } + }; + } else { + setDeclName(type, option->name); + return option->makeValue.reference(); + } +} + +enum ChangeKind { + NO_CHANGE, + COMPATIBLE, + INCOMPATIBLE, + + SUBTLY_COMPATIBLE + // The change is technically compatible on the wire, but SchemaLoader will complain. +}; + +struct ChangeInfo { + ChangeKind kind; + kj::String description; + + ChangeInfo(): kind(NO_CHANGE) {} + ChangeInfo(ChangeKind kind, kj::StringPtr description) + : kind(kind), description(kj::str(description)) {} + ChangeInfo(ChangeKind kind, kj::String&& description) + : kind(kind), description(kj::mv(description)) {} +}; + +extern kj::ArrayPtr> STRUCT_MODS; +extern kj::ArrayPtr> FIELD_MODS; + +// ================================================================================ + +static ChangeInfo declChangeName(Declaration::Builder decl, uint& nextOrdinal, + bool scopeHasUnion) { + auto name = decl.getName(); + if (name.getValue().size() == 0) { + // Naming an unnamed union. + name.setValue(kj::str("unUnnamed", nextOrdinal)); + return { SUBTLY_COMPATIBLE, "Assign name to unnamed union." }; + } else { + name.setValue(kj::str(name.getValue(), "Xx")); + return { COMPATIBLE, "Rename declaration." }; + } +} + +static ChangeInfo structAddField(Declaration::Builder decl, uint& nextOrdinal, bool scopeHasUnion) { + auto fieldDecl = addNested(decl); + + uint ordinal = nextOrdinal++; + + fieldDecl.initName().setValue(kj::str("f", ordinal)); + fieldDecl.getId().initOrdinal().setValue(ordinal); + + auto field = fieldDecl.initField(); + + auto makeValue = randomizeType(field.initType()); + if (rand() % 4 == 0) { + makeValue(field.getDefaultValue().initValue()); + } else { + field.getDefaultValue().setNone(); + } + return { COMPATIBLE, "Add field." }; +} + +static ChangeInfo structModifyField(Declaration::Builder decl, uint& nextOrdinal, + bool scopeHasUnion) { + auto nested = decl.getNestedDecls(); + + if (nested.size() == 0) { + return { NO_CHANGE, "Modify field, but there were none to modify." }; + } + + auto field = chooseFrom(nested); + + bool hasUnion = false; + if (decl.isUnion()) { + hasUnion = true; + } else { + for (auto n: nested) { + if (n.isUnion() && n.getName().getValue().size() == 0) { + hasUnion = true; + break; + } + } + } + + if (field.isGroup() || field.isUnion()) { + return chooseFrom(STRUCT_MODS)(field, nextOrdinal, hasUnion); + } else { + return chooseFrom(FIELD_MODS)(field, nextOrdinal, hasUnion); + } +} + +static ChangeInfo structGroupifyFields( + Declaration::Builder decl, uint& nextOrdinal, bool scopeHasUnion) { + // Place a random subset of the fields into a group. + + if (decl.isUnion()) { + return { NO_CHANGE, + "Randomly make a group out of some fields, but I can't do this to a union." }; + } + + kj::Vector> groupified; + kj::Vector> notGroupified; + auto orphanage = Orphanage::getForMessageContaining(decl); + + for (auto nested: decl.getNestedDecls()) { + if (rand() % 2) { + groupified.add(orphanage.newOrphanCopy(nested.asReader())); + } else { + notGroupified.add(orphanage.newOrphanCopy(nested.asReader())); + } + } + + if (groupified.size() == 0) { + return { NO_CHANGE, + "Randomly make a group out of some fields, but I ended up choosing none of them." }; + } + + auto newNested = decl.initNestedDecls(notGroupified.size() + 1); + uint index = rand() % (notGroupified.size() + 1); + + for (uint i = 0; i < index; i++) { + newNested.adoptWithCaveats(i, kj::mv(notGroupified[i])); + } + for (uint i = index; i < notGroupified.size(); i++) { + newNested.adoptWithCaveats(i + 1, kj::mv(notGroupified[i])); + } + + auto newGroup = newNested[index]; + auto groupNested = newGroup.initNestedDecls(groupified.size()); + for (uint i = 0; i < groupified.size(); i++) { + groupNested.adoptWithCaveats(i, kj::mv(groupified[i])); + } + + newGroup.initName().setValue(kj::str("g", nextOrdinal, "x", groupNested[0].getName().getValue())); + newGroup.getId().setUnspecified(); + newGroup.setGroup(); + + return { SUBTLY_COMPATIBLE, "Randomly group some set of existing fields." }; +} + +static ChangeInfo structPermuteFields( + Declaration::Builder decl, uint& nextOrdinal, bool scopeHasUnion) { + if (decl.getNestedDecls().size() == 0) { + return { NO_CHANGE, "Permute field code order, but there were none." }; + } + + auto oldOrphan = decl.disownNestedDecls(); + auto old = oldOrphan.get(); + + KJ_STACK_ARRAY(uint, mapping, old.size(), 16, 64); + + for (uint i = 0; i < mapping.size(); i++) { + mapping[i] = i; + } + for (uint i = mapping.size() - 1; i > 0; i--) { + uint j = rand() % i; + uint temp = mapping[j]; + mapping[j] = mapping[i]; + mapping[i] = temp; + } + + auto newNested = decl.initNestedDecls(old.size()); + for (uint i = 0; i < old.size(); i++) { + newNested.setWithCaveats(i, old[mapping[i]]); + } + + return { COMPATIBLE, "Permute field code order." }; +} + +kj::ConstFunction STRUCT_MODS_[] = { + structAddField, + structAddField, + structAddField, + structModifyField, + structModifyField, + structModifyField, + structPermuteFields, + declChangeName, + structGroupifyFields // do more rarely because it creates slowness +}; +kj::ArrayPtr> + STRUCT_MODS = STRUCT_MODS_; + +// ================================================================================ + +static ChangeInfo fieldUpgradeList(Declaration::Builder decl, uint& nextOrdinal, + bool scopeHasUnion) { + // Upgrades a non-struct list to a struct list. + + auto field = decl.getField(); + if (field.getDefaultValue().isValue()) { + return { NO_CHANGE, "Upgrade primitive list to struct list, but it had a default value." }; + } + + auto type = field.getType(); + if (!type.isApplication()) { + return { NO_CHANGE, "Upgrade primitive list to struct list, but it wasn't a list." }; + } + auto typeParams = type.getApplication().getParams(); + + auto elementType = typeParams[0].getValue(); + auto relativeName = elementType.getRelativeName(); + auto nameText = relativeName.asReader().getValue(); + if (nameText == "StructType" || nameText.endsWith("Struct")) { + return { NO_CHANGE, "Upgrade primitive list to struct list, but it was already a struct list."}; + } + if (nameText == "Bool") { + return { NO_CHANGE, "Upgrade primitive list to struct list, but bool lists can't be upgraded."}; + } + + relativeName.setValue(kj::str(nameText, "Struct")); + return { COMPATIBLE, "Upgrade primitive list to struct list" }; +} + +static ChangeInfo fieldExpandGroup(Declaration::Builder decl, uint& nextOrdinal, + bool scopeHasUnion) { + Declaration::Builder newDecl = decl.initNestedDecls(1)[0]; + newDecl.adoptName(decl.disownName()); + newDecl.getId().adoptOrdinal(decl.getId().disownOrdinal()); + + auto field = decl.getField(); + auto newField = newDecl.initField(); + + newField.adoptType(field.disownType()); + if (field.getDefaultValue().isValue()) { + newField.getDefaultValue().adoptValue(field.getDefaultValue().disownValue()); + } else { + newField.getDefaultValue().setNone(); + } + + decl.initName().setValue(kj::str("g", newDecl.getName().getValue())); + decl.getId().setUnspecified(); + + if (rand() % 2 == 0) { + decl.setGroup(); + } else { + decl.setUnion(); + if (!scopeHasUnion && rand() % 2 == 0) { + // Make it an unnamed union. + decl.getName().setValue(""); + } + structAddField(decl, nextOrdinal, scopeHasUnion); // union must have two members + } + + return { COMPATIBLE, "Wrap a field in a singleton group." }; +} + +static ChangeInfo fieldChangeType(Declaration::Builder decl, uint& nextOrdinal, + bool scopeHasUnion) { + auto field = decl.getField(); + + if (field.getDefaultValue().isNone()) { + // Change the type. + auto type = field.getType(); + while (type.isApplication()) { + // Either change the list parameter, or revert to a non-list. + if (rand() % 2) { + type = type.getApplication().getParams()[0].getValue(); + } else { + type.initRelativeName(); + } + } + auto typeName = type.getRelativeName(); + if (typeName.asReader().getValue().startsWith("Text")) { + typeName.setValue("Int32"); + } else { + typeName.setValue("Text"); + } + return { INCOMPATIBLE, "Change the type of a field." }; + } else { + // Change the default value. + auto dval = field.getDefaultValue().getValue(); + switch (dval.which()) { + case Expression::UNKNOWN: KJ_FAIL_ASSERT("unknown value expression?"); + case Expression::POSITIVE_INT: dval.setPositiveInt(dval.getPositiveInt() ^ 1); break; + case Expression::NEGATIVE_INT: dval.setNegativeInt(dval.getNegativeInt() ^ 1); break; + case Expression::FLOAT: dval.setFloat(-dval.getFloat()); break; + case Expression::RELATIVE_NAME: { + auto name = dval.getRelativeName(); + auto nameText = name.asReader().getValue(); + if (nameText == "true") { + name.setValue("false"); + } else if (nameText == "false") { + name.setValue("true"); + } else if (nameText == "foo") { + name.setValue("bar"); + } else { + name.setValue("foo"); + } + break; + } + case Expression::STRING: + case Expression::BINARY: + case Expression::LIST: + case Expression::TUPLE: + return { NO_CHANGE, "Change the default value of a field, but it's a pointer field." }; + + case Expression::ABSOLUTE_NAME: + case Expression::IMPORT: + case Expression::EMBED: + case Expression::APPLICATION: + case Expression::MEMBER: + KJ_FAIL_ASSERT("Unexpected expression type."); + } + return { INCOMPATIBLE, "Change the default value of a pritimive field." }; + } +} + +kj::ConstFunction FIELD_MODS_[] = { + fieldUpgradeList, + fieldExpandGroup, + fieldChangeType, + declChangeName +}; +kj::ArrayPtr> + FIELD_MODS = FIELD_MODS_; + +// ================================================================================ + +uint getOrdinal(StructSchema::Field field) { + auto proto = field.getProto(); + if (proto.getOrdinal().isExplicit()) { + return proto.getOrdinal().getExplicit(); + } + + KJ_ASSERT(proto.isGroup()); + + auto group = field.getType().asStruct(); + return getOrdinal(group.getFields()[0]); +} + +Orphan makeExampleStruct( + Orphanage orphanage, StructSchema schema, uint sharedOrdinalCount); +void checkExampleStruct(DynamicStruct::Reader reader, uint sharedOrdinalCount); + +Orphan makeExampleValue( + Orphanage orphanage, uint ordinal, Type type, uint sharedOrdinalCount) { + switch (type.which()) { + case schema::Type::INT32: return ordinal * 47327; + case schema::Type::FLOAT64: return ordinal * 313.25; + case schema::Type::INT8: return int(ordinal % 256) - 128; + case schema::Type::UINT16: return ordinal * 13; + case schema::Type::BOOL: return ordinal % 2 == 0; + case schema::Type::TEXT: return orphanage.newOrphanCopy(Text::Reader(kj::str(ordinal))); + case schema::Type::STRUCT: { + auto structType = type.asStruct(); + auto result = orphanage.newOrphan(structType); + auto builder = result.get(); + + KJ_IF_MAYBE(fieldI, structType.findFieldByName("i")) { + // Type is "StructType" + builder.set(*fieldI, ordinal); + } else { + // Type is "Int32Struct" or the like. + auto field = structType.getFieldByName("f0"); + builder.adopt(field, makeExampleValue( + orphanage, ordinal, field.getType(), sharedOrdinalCount)); + } + + return kj::mv(result); + } + case schema::Type::ENUM: { + auto enumerants = type.asEnum().getEnumerants(); + return DynamicEnum(enumerants[ordinal %enumerants.size()]); + } + case schema::Type::LIST: { + auto listType = type.asList(); + auto elementType = listType.getElementType(); + auto result = orphanage.newOrphan(listType, 1); + result.get().adopt(0, makeExampleValue( + orphanage, ordinal, elementType, sharedOrdinalCount)); + return kj::mv(result); + } + default: + KJ_FAIL_ASSERT("You added a new possible field type!"); + } +} + +void checkExampleValue(DynamicValue::Reader value, uint ordinal, schema::Type::Reader type, + uint sharedOrdinalCount) { + switch (type.which()) { + case schema::Type::INT32: KJ_ASSERT(value.as() == ordinal * 47327); break; + case schema::Type::FLOAT64: KJ_ASSERT(value.as() == ordinal * 313.25); break; + case schema::Type::INT8: KJ_ASSERT(value.as() == int(ordinal % 256) - 128); break; + case schema::Type::UINT16: KJ_ASSERT(value.as() == ordinal * 13); break; + case schema::Type::BOOL: KJ_ASSERT(value.as() == (ordinal % 2 == 0)); break; + case schema::Type::TEXT: KJ_ASSERT(value.as() == kj::str(ordinal)); break; + case schema::Type::STRUCT: { + auto structValue = value.as(); + auto structType = structValue.getSchema(); + + KJ_IF_MAYBE(fieldI, structType.findFieldByName("i")) { + // Type is "StructType" + KJ_ASSERT(structValue.get(*fieldI).as() == ordinal); + } else { + // Type is "Int32Struct" or the like. + auto field = structType.getFieldByName("f0"); + checkExampleValue(structValue.get(field), ordinal, + field.getProto().getSlot().getType(), sharedOrdinalCount); + } + break; + } + case schema::Type::ENUM: { + auto enumerant = KJ_ASSERT_NONNULL(value.as().getEnumerant()); + KJ_ASSERT(enumerant.getIndex() == + ordinal % enumerant.getContainingEnum().getEnumerants().size()); + break; + } + case schema::Type::LIST: + checkExampleValue(value.as()[0], ordinal, type.getList().getElementType(), + sharedOrdinalCount); + break; + default: + KJ_FAIL_ASSERT("You added a new possible field type!"); + } +} + +void setExampleField(DynamicStruct::Builder builder, StructSchema::Field field, + uint sharedOrdinalCount) { + auto fieldProto = field.getProto(); + switch (fieldProto.which()) { + case schema::Field::SLOT: + builder.adopt(field, makeExampleValue( + Orphanage::getForMessageContaining(builder), + getOrdinal(field), field.getType(), sharedOrdinalCount)); + break; + case schema::Field::GROUP: + builder.adopt(field, makeExampleStruct( + Orphanage::getForMessageContaining(builder), + field.getType().asStruct(), sharedOrdinalCount)); + break; + } +} + +void checkExampleField(DynamicStruct::Reader reader, StructSchema::Field field, + uint sharedOrdinalCount) { + auto fieldProto = field.getProto(); + switch (fieldProto.which()) { + case schema::Field::SLOT: { + uint ordinal = getOrdinal(field); + if (ordinal < sharedOrdinalCount) { + checkExampleValue(reader.get(field), ordinal, + fieldProto.getSlot().getType(), sharedOrdinalCount); + } + break; + } + case schema::Field::GROUP: + checkExampleStruct(reader.get(field).as(), sharedOrdinalCount); + break; + } +} + +Orphan makeExampleStruct( + Orphanage orphanage, StructSchema schema, uint sharedOrdinalCount) { + // Initialize all fields of the struct via reflection, such that they can be verified using + // a different version of the struct. sharedOrdinalCount is the number of ordinals shared by + // the two versions. This is used mainly to avoid setting union members that the other version + // doesn't have. + + Orphan result = orphanage.newOrphan(schema); + auto builder = result.get(); + + for (auto field: schema.getNonUnionFields()) { + setExampleField(builder, field, sharedOrdinalCount); + } + + auto unionFields = schema.getUnionFields(); + + // Pretend the union doesn't have any fields that aren't in the shared ordinal range. + uint range = unionFields.size(); + while (range > 0 && getOrdinal(unionFields[range - 1]) >= sharedOrdinalCount) { + --range; + } + + if (range > 0) { + auto field = unionFields[getOrdinal(unionFields[0]) % range]; + setExampleField(builder, field, sharedOrdinalCount); + } + + return kj::mv(result); +} + +void checkExampleStruct(DynamicStruct::Reader reader, uint sharedOrdinalCount) { + auto schema = reader.getSchema(); + + for (auto field: schema.getNonUnionFields()) { + checkExampleField(reader, field, sharedOrdinalCount); + } + + auto unionFields = schema.getUnionFields(); + + // Pretend the union doesn't have any fields that aren't in the shared ordinal range. + uint range = unionFields.size(); + while (range > 0 && getOrdinal(unionFields[range - 1]) >= sharedOrdinalCount) { + --range; + } + + if (range > 0) { + auto field = unionFields[getOrdinal(unionFields[0]) % range]; + checkExampleField(reader, field, sharedOrdinalCount); + } +} + +// ================================================================================ + +class ModuleImpl final: public Module { +public: + explicit ModuleImpl(ParsedFile::Reader content): content(content) {} + + kj::StringPtr getSourceName() override { return "evolving-schema.capnp"; } + Orphan loadContent(Orphanage orphanage) override { + return orphanage.newOrphanCopy(content); + } + kj::Maybe importRelative(kj::StringPtr importPath) override { + return nullptr; + } + kj::Maybe> embedRelative(kj::StringPtr embedPath) override { + return nullptr; + } + + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + KJ_FAIL_ASSERT("Unexpected parse error.", startByte, endByte, message); + } + bool hadErrors() override { + return false; + } + +private: + ParsedFile::Reader content; +}; + +static void loadStructAndGroups(const SchemaLoader& src, SchemaLoader& dst, uint64_t id) { + auto proto = src.get(id).getProto(); + dst.load(proto); + + for (auto field: proto.getStruct().getFields()) { + if (field.isGroup()) { + loadStructAndGroups(src, dst, field.getGroup().getTypeId()); + } + } +} + +static kj::Maybe loadFile( + ParsedFile::Reader file, SchemaLoader& loader, bool allNodes, + kj::Maybe>& messageBuilder, + uint sharedOrdinalCount) { + Compiler compiler; + ModuleImpl module(file); + KJ_ASSERT(compiler.add(module) == 0x8123456789abcdefllu); + + if (allNodes) { + // Eagerly compile and load the whole thing. + compiler.eagerlyCompile(0x8123456789abcdefllu, Compiler::ALL_RELATED_NODES); + + KJ_IF_MAYBE(m, messageBuilder) { + // Build an example struct using the compiled schema. + m->get()->adoptRoot(makeExampleStruct( + m->get()->getOrphanage(), compiler.getLoader().get(0x823456789abcdef1llu).asStruct(), + sharedOrdinalCount)); + } + + for (auto schema: compiler.getLoader().getAllLoaded()) { + loader.load(schema.getProto()); + } + return nullptr; + } else { + // Compile the file root so that the children are findable, then load the specific child + // we want. + compiler.eagerlyCompile(0x8123456789abcdefllu, Compiler::NODE); + + KJ_IF_MAYBE(m, messageBuilder) { + // Check that the example struct matches the compiled schema. + auto root = m->get()->getRoot( + compiler.getLoader().get(0x823456789abcdef1llu).asStruct()).asReader(); + KJ_CONTEXT(root); + checkExampleStruct(root, sharedOrdinalCount); + } + + return kj::runCatchingExceptions([&]() { + loadStructAndGroups(compiler.getLoader(), loader, 0x823456789abcdef1llu); + }); + } +} + +bool checkChange(ParsedFile::Reader file1, ParsedFile::Reader file2, ChangeKind changeKind, + uint sharedOrdinalCount) { + // Try loading file1 followed by file2 into the same SchemaLoader, expecting it to behave + // according to changeKind. Returns true if the files are both expected to be compatible and + // actually are -- the main loop uses this to decide which version to keep + + kj::Maybe> exampleBuilder; + + if (changeKind != INCOMPATIBLE) { + // For COMPATIBLE and SUBTLY_COMPATIBLE changes, build an example message with one schema + // and check it with the other. + exampleBuilder = kj::heap(); + } + + SchemaLoader loader; + loadFile(file1, loader, true, exampleBuilder, sharedOrdinalCount); + auto exception = loadFile(file2, loader, false, exampleBuilder, sharedOrdinalCount); + + if (changeKind == COMPATIBLE) { + KJ_IF_MAYBE(e, exception) { + kj::getExceptionCallback().onFatalException(kj::mv(*e)); + return false; + } else { + return true; + } + } else if (changeKind == INCOMPATIBLE) { + KJ_ASSERT(exception != nullptr, file1, file2); + return false; + } else { + KJ_ASSERT(changeKind == SUBTLY_COMPATIBLE); + + // SchemaLoader is allowed to throw an exception in this case, but we ignore it. + return true; + } +} + +void doTest() { + auto builder = kj::heap(); + + { + // Set up the basic file decl. + auto parsedFile = builder->initRoot(); + auto file = parsedFile.initRoot(); + file.setFile(); + file.initId().initUid().setValue(0x8123456789abcdefllu); + auto decls = file.initNestedDecls(3 + kj::size(TYPE_OPTIONS)); + + { + auto decl = decls[0]; + decl.initName().setValue("EvolvingStruct"); + decl.initId().initUid().setValue(0x823456789abcdef1llu); + decl.setStruct(); + } + { + auto decl = decls[1]; + decl.initName().setValue("StructType"); + decl.setStruct(); + + auto fieldDecl = decl.initNestedDecls(1)[0]; + fieldDecl.initName().setValue("i"); + fieldDecl.getId().initOrdinal().setValue(0); + auto field = fieldDecl.initField(); + setDeclName(field.initType(), "UInt32"); + } + { + auto decl = decls[2]; + decl.initName().setValue("EnumType"); + decl.setEnum(); + + auto enumerants = decl.initNestedDecls(4); + + for (uint i = 0; i < kj::size(RFC3092); i++) { + auto enumerantDecl = enumerants[i]; + enumerantDecl.initName().setValue(RFC3092[i]); + enumerantDecl.getId().initOrdinal().setValue(i); + enumerantDecl.setEnumerant(); + } + } + + // For each of TYPE_OPTIONS, declare a struct type that contains that type as its @0 field. + for (uint i = 0; i < kj::size(TYPE_OPTIONS); i++) { + auto decl = decls[3 + i]; + auto& option = TYPE_OPTIONS[i]; + + decl.initName().setValue(kj::str(option.name, "Struct")); + decl.setStruct(); + + auto fieldDecl = decl.initNestedDecls(1)[0]; + fieldDecl.initName().setValue("f0"); + fieldDecl.getId().initOrdinal().setValue(0); + auto field = fieldDecl.initField(); + setDeclName(field.initType(), option.name); + + uint ordinal = 1; + for (auto j: kj::range(0, rand() % 4)) { + (void)j; + structAddField(decl, ordinal, false); + } + } + } + + uint nextOrdinal = 0; + + for (uint i = 0; i < 96; i++) { + uint oldOrdinalCount = nextOrdinal; + + auto newBuilder = kj::heap(); + newBuilder->setRoot(builder->getRoot().asReader()); + + auto parsedFile = newBuilder->getRoot(); + Declaration::Builder decl = parsedFile.getRoot().getNestedDecls()[0]; + + // Apply a random modification. + ChangeInfo changeInfo; + while (changeInfo.kind == NO_CHANGE) { + auto& mod = chooseFrom(STRUCT_MODS); + changeInfo = mod(decl, nextOrdinal, false); + } + + KJ_CONTEXT(changeInfo.description); + + if (checkChange(builder->getRoot(), parsedFile, changeInfo.kind, oldOrdinalCount) && + checkChange(parsedFile, builder->getRoot(), changeInfo.kind, oldOrdinalCount)) { + builder = kj::mv(newBuilder); + } + } +} + +class EvolutionTestMain { +public: + explicit EvolutionTestMain(kj::ProcessContext& context) + : context(context) {} + + kj::MainFunc getMain() { + return kj::MainBuilder(context, "(unknown version)", + "Integration test / fuzzer which randomly modifies schemas is backwards-compatible ways " + "and verifies that they do actually remain compatible.") + .addOptionWithArg({"seed"}, KJ_BIND_METHOD(*this, setSeed), "", + "Set random number seed to . By default, time() is used.") + .callAfterParsing(KJ_BIND_METHOD(*this, run)) + .build(); + } + + kj::MainBuilder::Validity setSeed(kj::StringPtr value) { + char* end; + seed = strtol(value.cStr(), &end, 0); + if (value.size() == 0 || *end != '\0') { + return "not an integer"; + } else { + return true; + } + } + + kj::MainBuilder::Validity run() { + // https://github.com/sandstorm-io/capnproto/issues/344 describes an obscure bug in the layout + // algorithm, the fix for which breaks backwards-compatibility for any schema triggering the + // bug. In order to avoid silently breaking protocols, we are temporarily throwing an exception + // in cases where this bug would have occurred, so that people can decide what to do. + // However, the evolution test can occasionally trigger the bug (depending on the random path + // it takes). Rather than try to avoid it, we disable the exception-throwing, because the bug + // is actually fixed, and the exception is only there to raise awareness of the compatibility + // concerns. + // + // On Linux, seed 1467142714 (for example) will trigger the exception (without this env var). +#if defined(__MINGW32__) || defined(_MSC_VER) + putenv("CAPNP_IGNORE_ISSUE_344=1"); +#else + setenv("CAPNP_IGNORE_ISSUE_344", "1", true); +#endif + + srand(seed); + + { + kj::String text = kj::str( + "Randomly testing backwards-compatibility scenarios with seed: ", seed, "\n"); + kj::FdOutputStream(STDOUT_FILENO).write(text.begin(), text.size()); + } + + KJ_CONTEXT(seed, "PLEASE REPORT THIS FAILURE AND INCLUDE THE SEED"); + + doTest(); + + return true; + } + +private: + kj::ProcessContext& context; + uint seed = time(nullptr); +}; + +} // namespace +} // namespace compiler +} // namespace capnp + +KJ_MAIN(capnp::compiler::EvolutionTestMain); diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,268 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xc56be168dcbbc3c6; +# The structures in this file correspond to the AST of the Cap'n Proto schema language. +# +# This file is intended to be used internally by capnpc. Mostly, it is useful because it is more +# convenient than defining data classes in C++, particularly where variant types (unions) are +# needed. Over time, this file may change in backwards-incompatible ways. + +using Cxx = import "/capnp/c++.capnp"; + +$Cxx.namespace("capnp::compiler"); + +# TODO(someday): Here's a case where parameterized types might be nice, but note that it would +# need to support primitive parameters... +struct LocatedText { + value @0 :Text; + startByte @1 :UInt32; + endByte @2 :UInt32; +} + +struct LocatedInteger { + value @0 :UInt64; + startByte @1 :UInt32; + endByte @2 :UInt32; +} + +struct LocatedFloat { + value @0 :Float64; + startByte @1 :UInt32; + endByte @2 :UInt32; +} + +struct Expression { + # An expression. May evaluate to a type, a value, or a declaration (i.e. some named thing which + # is neither a type nor a value, like an annotation declaration). + + union { + unknown @0 :Void; # e.g. parse error; downstream should ignore + positiveInt @1 :UInt64; + negativeInt @2 :UInt64; + float @3 :Float64; + string @4 :Text; + binary @10 :Data; + + relativeName @5 :LocatedText; + # Just an identifier. + + absoluteName @15 :LocatedText; + # An identifier with leading '.'. + + import @16 :LocatedText; + # An import directive. + + embed @17 :LocatedText; + # An embed directive. + + list @6 :List(Expression); + # Bracketed list; members are never named. + + tuple @7 :List(Param); + # Parenthesized list, possibly with named members. + # + # Note that a parenthesized list with one unnamed member is just a parenthesized expression, + # not a tuple, and so will never be represented as a tuple. + + application :group { + # Application of a function to some parameters, e.g. "foo(bar, baz)". + + function @11 :Expression; + params @12 :List(Param); + } + + member :group { + # A named member of an aggregate, e.g. "foo.bar". + + parent @13 :Expression; + name @14 :LocatedText; + } + + # TODO(someday): Basic arithmetic? + } + + struct Param { + union { + unnamed @0 :Void; # Just a value. + named @1 :LocatedText; # "name = value" + } + value @2 :Expression; + } + + startByte @8 :UInt32; + endByte @9 :UInt32; +} + +struct Declaration { + # A declaration statement. + + name @0 :LocatedText; + + id :union { + unspecified @1 :Void; + uid @2 :LocatedInteger; + ordinal @3 :LocatedInteger; # limited to 16 bits + } + + parameters @57 :List(BrandParameter); + # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. + + struct BrandParameter { + name @0 :Text; + startByte @1 :UInt32; + endByte @2 :UInt32; + } + + nestedDecls @4 :List(Declaration); + + annotations @5 :List(AnnotationApplication); + struct AnnotationApplication { + name @0 :Expression; + + value :union { + none @1 :Void; # None specified; implies void value. + expression @2 :Expression; + } + } + + startByte @6 :UInt32; + endByte @7 :UInt32; + + docComment @8 :Text; + + union { + file @9 :Void; + + using :group { + target @10 :Expression; + } + + const :group { + type @11 :Expression; + value @12 :Expression; + } + + enum @13 :Void; + enumerant @14 :Void; + + struct @15 :Void; + field :group { + type @16 :Expression; + defaultValue :union { + none @17 :Void; + value @18 :Expression; + } + } + union @19 :Void; + group @20 :Void; + + interface :group { + superclasses @21 :List(Expression); + } + method :group { + params @22 :ParamList; + results :union { + none @23 :Void; + explicit @24 :ParamList; + } + } + + annotation :group { + type @25 :Expression; + + targetsFile @26 :Bool; + targetsConst @27 :Bool; + targetsEnum @28 :Bool; + targetsEnumerant @29 :Bool; + targetsStruct @30 :Bool; + targetsField @31 :Bool; + targetsUnion @32 :Bool; + targetsGroup @33 :Bool; + targetsInterface @34 :Bool; + targetsMethod @35 :Bool; + targetsParam @36 :Bool; + targetsAnnotation @37 :Bool; + } + + nakedId @38 :LocatedInteger; + nakedAnnotation @39 :AnnotationApplication; + # A floating UID or annotation (allowed at the file top level). + + # The following declaration types are not produced by the parser, but are declared here + # so that the compiler can handle symbol name lookups more uniformly. + # + # New union members added here will magically become visible in the global scope. + # E.g. "builtinFoo" becomes visible as "Foo". + builtinVoid @40 :Void; + builtinBool @41 :Void; + builtinInt8 @42 :Void; + builtinInt16 @43 :Void; + builtinInt32 @44 :Void; + builtinInt64 @45 :Void; + builtinUInt8 @46 :Void; + builtinUInt16 @47 :Void; + builtinUInt32 @48 :Void; + builtinUInt64 @49 :Void; + builtinFloat32 @50 :Void; + builtinFloat64 @51 :Void; + builtinText @52 :Void; + builtinData @53 :Void; + builtinList @54 :Void $builtinParams([(name = "Element")]); + builtinObject @55 :Void; # only for "renamed to AnyPointer" error message + builtinAnyPointer @56 :Void; + builtinAnyStruct @58 :Void; + builtinAnyList @59 :Void; + builtinCapability @60 :Void; + } + + annotation builtinParams @0x94099c3f9eb32d6b (field) :List(BrandParameter); + + struct ParamList { + # A list of method parameters or method returns. + + union { + namedList @0 :List(Param); + + type @1 :Expression; + # Specified some other struct type instead of a named list. + } + + startByte @2 :UInt32; + endByte @3 :UInt32; + } + struct Param { + name @0 :LocatedText; # If null, param failed to parse. + type @1 :Expression; + annotations @2 :List(AnnotationApplication); + defaultValue :union { + none @3 :Void; + value @4 :Expression; + } + + startByte @5 :UInt32; + endByte @6 :UInt32; + } +} + +struct ParsedFile { + root @0 :Declaration; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,2966 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: grammar.capnp + +#include "grammar.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<66> b_e75816b56529d464 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 29, 0, 0, 0, 1, 0, 1, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 74, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 76, 111, 99, + 97, 116, 101, 100, 84, 101, 120, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e75816b56529d464 = b_e75816b56529d464.words; +#if !CAPNP_LITE +static const uint16_t m_e75816b56529d464[] = {2, 1, 0}; +static const uint16_t i_e75816b56529d464[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_e75816b56529d464 = { + 0xe75816b56529d464, b_e75816b56529d464.words, 66, nullptr, m_e75816b56529d464, + 0, 3, i_e75816b56529d464, nullptr, nullptr, { &s_e75816b56529d464, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<66> b_991c7a3693d62cf2 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 242, 44, 214, 147, 54, 122, 28, 153, + 29, 0, 0, 0, 1, 0, 2, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 98, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 76, 111, 99, + 97, 116, 101, 100, 73, 110, 116, 101, + 103, 101, 114, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_991c7a3693d62cf2 = b_991c7a3693d62cf2.words; +#if !CAPNP_LITE +static const uint16_t m_991c7a3693d62cf2[] = {2, 1, 0}; +static const uint16_t i_991c7a3693d62cf2[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_991c7a3693d62cf2 = { + 0x991c7a3693d62cf2, b_991c7a3693d62cf2.words, 66, nullptr, m_991c7a3693d62cf2, + 0, 3, i_991c7a3693d62cf2, nullptr, nullptr, { &s_991c7a3693d62cf2, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<66> b_90f2a60678fd2367 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 103, 35, 253, 120, 6, 166, 242, 144, + 29, 0, 0, 0, 1, 0, 2, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 82, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 76, 111, 99, + 97, 116, 101, 100, 70, 108, 111, 97, + 116, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_90f2a60678fd2367 = b_90f2a60678fd2367.words; +#if !CAPNP_LITE +static const uint16_t m_90f2a60678fd2367[] = {2, 1, 0}; +static const uint16_t i_90f2a60678fd2367[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_90f2a60678fd2367 = { + 0x90f2a60678fd2367, b_90f2a60678fd2367.words, 66, nullptr, m_90f2a60678fd2367, + 0, 3, i_90f2a60678fd2367, nullptr, nullptr, { &s_90f2a60678fd2367, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<262> b_8e207d4dfe54d0de = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 29, 0, 0, 0, 1, 0, 3, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 2, 0, 7, 0, 0, 0, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 135, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 69, 120, 112, + 114, 101, 115, 115, 105, 111, 110, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 170, 219, 222, 26, 183, 70, 2, 201, + 1, 0, 0, 0, 50, 0, 0, 0, + 80, 97, 114, 97, 109, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 172, 1, 0, 0, 3, 0, 1, 0, + 184, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 1, 0, 0, 3, 0, 1, 0, + 192, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 188, 1, 0, 0, 3, 0, 1, 0, + 200, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 197, 1, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 1, 0, 0, 3, 0, 1, 0, + 204, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 201, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 196, 1, 0, 0, 3, 0, 1, 0, + 208, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 205, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 204, 1, 0, 0, 3, 0, 1, 0, + 216, 1, 0, 0, 2, 0, 1, 0, + 10, 0, 249, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 213, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 208, 1, 0, 0, 3, 0, 1, 0, + 236, 1, 0, 0, 2, 0, 1, 0, + 11, 0, 248, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 233, 1, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 228, 1, 0, 0, 3, 0, 1, 0, + 0, 2, 0, 0, 2, 0, 1, 0, + 14, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 253, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 252, 1, 0, 0, 3, 0, 1, 0, + 8, 2, 0, 0, 2, 0, 1, 0, + 15, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 2, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 3, 0, 1, 0, + 12, 2, 0, 0, 2, 0, 1, 0, + 5, 0, 247, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 0, 0, 3, 0, 1, 0, + 16, 2, 0, 0, 2, 0, 1, 0, + 12, 0, 246, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 122, 223, 176, 64, 112, 57, 232, 174, + 13, 2, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 245, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 89, 51, 121, 13, 64, 225, 40, 170, + 249, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 244, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 225, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 224, 1, 0, 0, 3, 0, 1, 0, + 236, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 243, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 233, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 228, 1, 0, 0, 3, 0, 1, 0, + 240, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 242, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 237, 1, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 232, 1, 0, 0, 3, 0, 1, 0, + 244, 1, 0, 0, 2, 0, 1, 0, + 117, 110, 107, 110, 111, 119, 110, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 111, 115, 105, 116, 105, 118, 101, + 73, 110, 116, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 101, 103, 97, 116, 105, 118, 101, + 73, 110, 116, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 105, 110, 103, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 108, 97, 116, 105, 118, 101, + 78, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 105, 115, 116, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 117, 112, 108, 101, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 170, 219, 222, 26, 183, 70, 2, 201, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 105, 110, 97, 114, 121, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 0, 0, 0, 0, 0, + 109, 101, 109, 98, 101, 114, 0, 0, + 97, 98, 115, 111, 108, 117, 116, 101, + 78, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 109, 112, 111, 114, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 109, 98, 101, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_8e207d4dfe54d0de = b_8e207d4dfe54d0de.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_8e207d4dfe54d0de[] = { + &s_8e207d4dfe54d0de, + &s_aa28e1400d793359, + &s_aee8397040b0df7a, + &s_c90246b71adedbaa, + &s_e75816b56529d464, +}; +static const uint16_t m_8e207d4dfe54d0de[] = {13, 11, 10, 15, 9, 3, 14, 6, 12, 2, 1, 5, 8, 4, 7, 0}; +static const uint16_t i_8e207d4dfe54d0de[] = {0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8, 9}; +const ::capnp::_::RawSchema s_8e207d4dfe54d0de = { + 0x8e207d4dfe54d0de, b_8e207d4dfe54d0de.words, 262, d_8e207d4dfe54d0de, m_8e207d4dfe54d0de, + 5, 16, i_8e207d4dfe54d0de, nullptr, nullptr, { &s_8e207d4dfe54d0de, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<65> b_c90246b71adedbaa = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 170, 219, 222, 26, 183, 70, 2, 201, + 40, 0, 0, 0, 1, 0, 1, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 2, 0, 7, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 114, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 69, 120, 112, + 114, 101, 115, 115, 105, 111, 110, 46, + 80, 97, 114, 97, 109, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 117, 110, 110, 97, 109, 101, 100, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 109, 101, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c90246b71adedbaa = b_c90246b71adedbaa.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c90246b71adedbaa[] = { + &s_8e207d4dfe54d0de, + &s_e75816b56529d464, +}; +static const uint16_t m_c90246b71adedbaa[] = {1, 0, 2}; +static const uint16_t i_c90246b71adedbaa[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_c90246b71adedbaa = { + 0xc90246b71adedbaa, b_c90246b71adedbaa.words, 65, d_c90246b71adedbaa, m_c90246b71adedbaa, + 2, 3, i_c90246b71adedbaa, nullptr, nullptr, { &s_c90246b71adedbaa, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<55> b_aee8397040b0df7a = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 122, 223, 176, 64, 112, 57, 232, 174, + 40, 0, 0, 0, 1, 0, 3, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 2, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 162, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 69, 120, 112, + 114, 101, 115, 115, 105, 111, 110, 46, + 97, 112, 112, 108, 105, 99, 97, 116, + 105, 111, 110, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 72, 0, 0, 0, 2, 0, 1, 0, + 102, 117, 110, 99, 116, 105, 111, 110, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 170, 219, 222, 26, 183, 70, 2, 201, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_aee8397040b0df7a = b_aee8397040b0df7a.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_aee8397040b0df7a[] = { + &s_8e207d4dfe54d0de, + &s_c90246b71adedbaa, +}; +static const uint16_t m_aee8397040b0df7a[] = {0, 1}; +static const uint16_t i_aee8397040b0df7a[] = {0, 1}; +const ::capnp::_::RawSchema s_aee8397040b0df7a = { + 0xaee8397040b0df7a, b_aee8397040b0df7a.words, 55, d_aee8397040b0df7a, m_aee8397040b0df7a, + 2, 2, i_aee8397040b0df7a, nullptr, nullptr, { &s_aee8397040b0df7a, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_aa28e1400d793359 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 89, 51, 121, 13, 64, 225, 40, 170, + 40, 0, 0, 0, 1, 0, 3, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 2, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 122, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 69, 120, 112, + 114, 101, 115, 115, 105, 111, 110, 46, + 109, 101, 109, 98, 101, 114, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 112, 97, 114, 101, 110, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_aa28e1400d793359 = b_aa28e1400d793359.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_aa28e1400d793359[] = { + &s_8e207d4dfe54d0de, + &s_e75816b56529d464, +}; +static const uint16_t m_aa28e1400d793359[] = {1, 0}; +static const uint16_t i_aa28e1400d793359[] = {0, 1}; +const ::capnp::_::RawSchema s_aa28e1400d793359 = { + 0xaa28e1400d793359, b_aa28e1400d793359.words, 49, d_aa28e1400d793359, m_aa28e1400d793359, + 2, 2, i_aa28e1400d793359, nullptr, nullptr, { &s_aa28e1400d793359, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<677> b_96efe787c17e83bb = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 29, 0, 0, 0, 1, 0, 2, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 8, 0, 7, 0, 0, 0, 34, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 74, 1, 0, 0, + 41, 0, 0, 0, 87, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 0, 0, 0, 55, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 0, 0, 0, 1, 0, 1, 0, + 117, 225, 28, 175, 68, 17, 231, 213, + 33, 0, 0, 0, 122, 0, 0, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 33, 0, 0, 0, 178, 0, 0, 0, + 107, 45, 179, 158, 63, 156, 9, 148, + 37, 0, 0, 0, 114, 0, 0, 0, + 205, 27, 216, 121, 122, 110, 246, 179, + 37, 0, 0, 0, 82, 0, 0, 0, + 165, 210, 151, 166, 169, 8, 254, 255, + 37, 0, 0, 0, 50, 0, 0, 0, + 66, 114, 97, 110, 100, 80, 97, 114, + 97, 109, 101, 116, 101, 114, 0, 0, + 65, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 65, 112, 112, 108, 105, 99, + 97, 116, 105, 111, 110, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 80, + 97, 114, 97, 109, 115, 0, 0, 0, + 80, 97, 114, 97, 109, 76, 105, 115, + 116, 0, 0, 0, 0, 0, 0, 0, + 80, 97, 114, 97, 109, 0, 0, 0, + 168, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 137, 4, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 4, 0, 0, 3, 0, 1, 0, + 144, 4, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 150, 174, 3, 193, 115, 201, 240, 137, + 141, 4, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 4, 0, 0, 3, 0, 1, 0, + 144, 4, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 140, 4, 0, 0, 3, 0, 1, 0, + 168, 4, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 4, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 164, 4, 0, 0, 3, 0, 1, 0, + 176, 4, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 173, 4, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 4, 0, 0, 3, 0, 1, 0, + 180, 4, 0, 0, 2, 0, 1, 0, + 7, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 4, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 4, 0, 0, 3, 0, 1, 0, + 188, 4, 0, 0, 2, 0, 1, 0, + 8, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 4, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 4, 0, 0, 3, 0, 1, 0, + 192, 4, 0, 0, 2, 0, 1, 0, + 9, 0, 254, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 207, 44, 254, 11, 168, 100, 49, 233, + 189, 4, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 0, 253, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 12, 13, 207, 141, 42, 50, 72, 179, + 165, 4, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 4, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 136, 4, 0, 0, 3, 0, 1, 0, + 148, 4, 0, 0, 2, 0, 1, 0, + 12, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 145, 4, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 144, 4, 0, 0, 3, 0, 1, 0, + 156, 4, 0, 0, 2, 0, 1, 0, + 13, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 4, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 4, 0, 0, 3, 0, 1, 0, + 160, 4, 0, 0, 2, 0, 1, 0, + 14, 0, 249, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 200, 88, 179, 143, 32, 34, 38, 143, + 157, 4, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 248, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 4, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 4, 0, 0, 3, 0, 1, 0, + 140, 4, 0, 0, 2, 0, 1, 0, + 16, 0, 247, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 137, 4, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 4, 0, 0, 3, 0, 1, 0, + 144, 4, 0, 0, 2, 0, 1, 0, + 17, 0, 246, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 211, 53, 2, 243, 234, 144, 42, 153, + 141, 4, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 245, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 185, 192, 23, 214, 71, 24, 151, 235, + 121, 4, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 244, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 127, 3, 152, 49, 110, 232, 185, 156, + 97, 4, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 0, 243, 255, 5, 0, 0, 0, + 0, 0, 1, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 4, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 4, 0, 0, 3, 0, 1, 0, + 84, 4, 0, 0, 2, 0, 1, 0, + 21, 0, 242, 255, 5, 0, 0, 0, + 0, 0, 1, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 4, 0, 0, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 4, 0, 0, 3, 0, 1, 0, + 92, 4, 0, 0, 2, 0, 1, 0, + 22, 0, 241, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 40, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 89, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 4, 0, 0, 3, 0, 1, 0, + 100, 4, 0, 0, 2, 0, 1, 0, + 23, 0, 240, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 41, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 4, 0, 0, 3, 0, 1, 0, + 108, 4, 0, 0, 2, 0, 1, 0, + 24, 0, 239, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 4, 0, 0, 3, 0, 1, 0, + 116, 4, 0, 0, 2, 0, 1, 0, + 25, 0, 238, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 43, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 4, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 4, 0, 0, 3, 0, 1, 0, + 124, 4, 0, 0, 2, 0, 1, 0, + 26, 0, 237, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 44, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 4, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 120, 4, 0, 0, 3, 0, 1, 0, + 132, 4, 0, 0, 2, 0, 1, 0, + 27, 0, 236, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 129, 4, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 4, 0, 0, 3, 0, 1, 0, + 140, 4, 0, 0, 2, 0, 1, 0, + 28, 0, 235, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 46, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 137, 4, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 136, 4, 0, 0, 3, 0, 1, 0, + 148, 4, 0, 0, 2, 0, 1, 0, + 29, 0, 234, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 47, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 145, 4, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 144, 4, 0, 0, 3, 0, 1, 0, + 156, 4, 0, 0, 2, 0, 1, 0, + 30, 0, 233, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 4, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 152, 4, 0, 0, 3, 0, 1, 0, + 164, 4, 0, 0, 2, 0, 1, 0, + 31, 0, 232, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 161, 4, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 4, 0, 0, 3, 0, 1, 0, + 172, 4, 0, 0, 2, 0, 1, 0, + 32, 0, 231, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 169, 4, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 4, 0, 0, 3, 0, 1, 0, + 180, 4, 0, 0, 2, 0, 1, 0, + 33, 0, 230, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 51, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 4, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 4, 0, 0, 3, 0, 1, 0, + 188, 4, 0, 0, 2, 0, 1, 0, + 34, 0, 229, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 4, 0, 0, 3, 0, 1, 0, + 196, 4, 0, 0, 2, 0, 1, 0, + 35, 0, 228, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 4, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 4, 0, 0, 3, 0, 1, 0, + 204, 4, 0, 0, 2, 0, 1, 0, + 36, 0, 227, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 201, 4, 0, 0, 98, 0, 0, 0, + 205, 4, 0, 0, 31, 0, 0, 0, + 248, 4, 0, 0, 3, 0, 1, 0, + 4, 5, 0, 0, 2, 0, 1, 0, + 37, 0, 226, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 5, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 0, 3, 0, 1, 0, + 12, 5, 0, 0, 2, 0, 1, 0, + 38, 0, 225, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 5, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 5, 0, 0, 3, 0, 1, 0, + 24, 5, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 1, 0, 57, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 5, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 5, 0, 0, 3, 0, 1, 0, + 48, 5, 0, 0, 2, 0, 1, 0, + 39, 0, 224, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 5, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 5, 0, 0, 3, 0, 1, 0, + 60, 5, 0, 0, 2, 0, 1, 0, + 40, 0, 223, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 59, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 5, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 56, 5, 0, 0, 3, 0, 1, 0, + 68, 5, 0, 0, 2, 0, 1, 0, + 41, 0, 222, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 65, 5, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 5, 0, 0, 3, 0, 1, 0, + 80, 5, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 110, 101, 115, 116, 101, 100, 68, 101, + 99, 108, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 111, 99, 67, 111, 109, 109, 101, + 110, 116, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 108, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 115, 105, 110, 103, 0, 0, 0, + 99, 111, 110, 115, 116, 0, 0, 0, + 101, 110, 117, 109, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 117, 109, 101, 114, 97, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 117, 99, 116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 101, 108, 100, 0, 0, 0, + 117, 110, 105, 111, 110, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 103, 114, 111, 117, 112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 109, 101, 116, 104, 111, 100, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 0, 0, 0, 0, 0, 0, + 110, 97, 107, 101, 100, 73, 100, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 242, 44, 214, 147, 54, 122, 28, 153, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 107, 101, 100, 65, 110, 110, + 111, 116, 97, 116, 105, 111, 110, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 86, + 111, 105, 100, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 66, + 111, 111, 108, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 73, + 110, 116, 56, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 73, + 110, 116, 49, 54, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 73, + 110, 116, 51, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 73, + 110, 116, 54, 52, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 85, + 73, 110, 116, 56, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 85, + 73, 110, 116, 49, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 85, + 73, 110, 116, 51, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 85, + 73, 110, 116, 54, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 70, + 108, 111, 97, 116, 51, 50, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 70, + 108, 111, 97, 116, 54, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 84, + 101, 120, 116, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 68, + 97, 116, 97, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 76, + 105, 115, 116, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 2, 0, + 107, 45, 179, 158, 63, 156, 9, 148, + 4, 0, 0, 0, 2, 0, 1, 0, + 28, 0, 0, 0, 0, 0, 1, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 23, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 66, 0, 0, 0, + 69, 108, 101, 109, 101, 110, 116, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 79, + 98, 106, 101, 99, 116, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 65, + 110, 121, 80, 111, 105, 110, 116, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 101, 116, 101, + 114, 115, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 117, 225, 28, 175, 68, 17, 231, 213, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 65, + 110, 121, 83, 116, 114, 117, 99, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 65, + 110, 121, 76, 105, 115, 116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 117, 105, 108, 116, 105, 110, 67, + 97, 112, 97, 98, 105, 108, 105, 116, + 121, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_96efe787c17e83bb = b_96efe787c17e83bb.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_96efe787c17e83bb[] = { + &s_89f0c973c103ae96, + &s_8f2622208fb358c8, + &s_96efe787c17e83bb, + &s_991c7a3693d62cf2, + &s_992a90eaf30235d3, + &s_9cb9e86e3198037f, + &s_b348322a8dcf0d0c, + &s_d00489d473826290, + &s_d5e71144af1ce175, + &s_e75816b56529d464, + &s_e93164a80bfe2ccf, + &s_eb971847d617c0b9, +}; +static const uint16_t m_96efe787c17e83bb[] = {18, 3, 40, 37, 39, 22, 41, 34, 31, 32, 24, 25, 26, 23, 35, 36, 33, 28, 29, 30, 27, 21, 9, 6, 5, 10, 11, 13, 7, 15, 1, 16, 17, 20, 19, 0, 2, 38, 4, 12, 14, 8}; +static const uint16_t i_96efe787c17e83bb[] = {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 0, 1, 2, 3, 4, 5, 6, 38}; +const ::capnp::_::RawSchema s_96efe787c17e83bb = { + 0x96efe787c17e83bb, b_96efe787c17e83bb.words, 677, d_96efe787c17e83bb, m_96efe787c17e83bb, + 12, 42, i_96efe787c17e83bb, nullptr, nullptr, { &s_96efe787c17e83bb, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<67> b_d5e71144af1ce175 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 117, 225, 28, 175, 68, 17, 231, 213, + 41, 0, 0, 0, 1, 0, 1, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 1, 0, 0, + 45, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 66, 114, 97, 110, 100, 80, 97, + 114, 97, 109, 101, 116, 101, 114, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d5e71144af1ce175 = b_d5e71144af1ce175.words; +#if !CAPNP_LITE +static const uint16_t m_d5e71144af1ce175[] = {2, 0, 1}; +static const uint16_t i_d5e71144af1ce175[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_d5e71144af1ce175 = { + 0xd5e71144af1ce175, b_d5e71144af1ce175.words, 67, nullptr, m_d5e71144af1ce175, + 0, 3, i_d5e71144af1ce175, nullptr, nullptr, { &s_d5e71144af1ce175, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<45> b_d00489d473826290 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 41, 0, 0, 0, 1, 0, 1, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 1, 0, 0, + 49, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 65, 110, 110, 111, 116, 97, 116, + 105, 111, 110, 65, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 249, 106, 223, 92, 217, 238, 90, 251, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, } +}; +::capnp::word const* const bp_d00489d473826290 = b_d00489d473826290.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d00489d473826290[] = { + &s_8e207d4dfe54d0de, + &s_fb5aeed95cdf6af9, +}; +static const uint16_t m_d00489d473826290[] = {0, 1}; +static const uint16_t i_d00489d473826290[] = {0, 1}; +const ::capnp::_::RawSchema s_d00489d473826290 = { + 0xd00489d473826290, b_d00489d473826290.words, 45, d_d00489d473826290, m_d00489d473826290, + 2, 2, i_d00489d473826290, nullptr, nullptr, { &s_d00489d473826290, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<53> b_fb5aeed95cdf6af9 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 249, 106, 223, 92, 217, 238, 90, 251, + 63, 0, 0, 0, 1, 0, 1, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 2, 0, 7, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 42, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 65, 110, 110, 111, 116, 97, 116, + 105, 111, 110, 65, 112, 112, 108, 105, + 99, 97, 116, 105, 111, 110, 46, 118, + 97, 108, 117, 101, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 56, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 120, 112, 114, 101, 115, 115, 105, + 111, 110, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_fb5aeed95cdf6af9 = b_fb5aeed95cdf6af9.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_fb5aeed95cdf6af9[] = { + &s_8e207d4dfe54d0de, + &s_d00489d473826290, +}; +static const uint16_t m_fb5aeed95cdf6af9[] = {1, 0}; +static const uint16_t i_fb5aeed95cdf6af9[] = {0, 1}; +const ::capnp::_::RawSchema s_fb5aeed95cdf6af9 = { + 0xfb5aeed95cdf6af9, b_fb5aeed95cdf6af9.words, 53, d_fb5aeed95cdf6af9, m_fb5aeed95cdf6af9, + 2, 2, i_fb5aeed95cdf6af9, nullptr, nullptr, { &s_fb5aeed95cdf6af9, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<28> b_94099c3f9eb32d6b = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 107, 45, 179, 158, 63, 156, 9, 148, + 41, 0, 0, 0, 5, 0, 32, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 186, 1, 0, 0, + 45, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 98, 117, 105, 108, 116, 105, 110, + 80, 97, 114, 97, 109, 115, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 117, 225, 28, 175, 68, 17, 231, 213, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_94099c3f9eb32d6b = b_94099c3f9eb32d6b.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_94099c3f9eb32d6b = { + 0x94099c3f9eb32d6b, b_94099c3f9eb32d6b.words, 28, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_94099c3f9eb32d6b, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<87> b_b3f66e7a79d81bcd = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 205, 27, 216, 121, 122, 110, 246, 179, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 1, 0, 7, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 154, 1, 0, 0, + 45, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 80, 97, 114, 97, 109, 76, 105, + 115, 116, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 16, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 3, 0, 1, 0, + 124, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 0, 0, 0, 3, 0, 1, 0, + 128, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 125, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 124, 0, 0, 0, 3, 0, 1, 0, + 136, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 0, 0, 0, 3, 0, 1, 0, + 140, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 100, 76, 105, 115, + 116, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 165, 210, 151, 166, 169, 8, 254, 255, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b3f66e7a79d81bcd = b_b3f66e7a79d81bcd.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_b3f66e7a79d81bcd[] = { + &s_8e207d4dfe54d0de, + &s_fffe08a9a697d2a5, +}; +static const uint16_t m_b3f66e7a79d81bcd[] = {3, 0, 2, 1}; +static const uint16_t i_b3f66e7a79d81bcd[] = {0, 1, 2, 3}; +const ::capnp::_::RawSchema s_b3f66e7a79d81bcd = { + 0xb3f66e7a79d81bcd, b_b3f66e7a79d81bcd.words, 87, d_b3f66e7a79d81bcd, m_b3f66e7a79d81bcd, + 2, 4, i_b3f66e7a79d81bcd, nullptr, nullptr, { &s_b3f66e7a79d81bcd, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<110> b_fffe08a9a697d2a5 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 165, 210, 151, 166, 169, 8, 254, 255, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 4, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 122, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 87, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 80, 97, 114, 97, 109, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 24, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 0, 0, 0, 3, 0, 1, 0, + 160, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 157, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 152, 0, 0, 0, 3, 0, 1, 0, + 164, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 161, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 0, 0, 0, 3, 0, 1, 0, + 188, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 71, 234, 136, 253, 21, 69, 16, 229, + 185, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 164, 0, 0, 0, 3, 0, 1, 0, + 176, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 173, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 0, 0, 0, 3, 0, 1, 0, + 180, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 100, 212, 41, 101, 181, 22, 88, 231, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 144, 98, 130, 115, 212, 137, 4, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 101, 102, 97, 117, 108, 116, 86, + 97, 108, 117, 101, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_fffe08a9a697d2a5 = b_fffe08a9a697d2a5.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_fffe08a9a697d2a5[] = { + &s_8e207d4dfe54d0de, + &s_d00489d473826290, + &s_e5104515fd88ea47, + &s_e75816b56529d464, +}; +static const uint16_t m_fffe08a9a697d2a5[] = {2, 3, 5, 0, 4, 1}; +static const uint16_t i_fffe08a9a697d2a5[] = {0, 1, 2, 3, 4, 5}; +const ::capnp::_::RawSchema s_fffe08a9a697d2a5 = { + 0xfffe08a9a697d2a5, b_fffe08a9a697d2a5.words, 110, d_fffe08a9a697d2a5, m_fffe08a9a697d2a5, + 4, 6, i_fffe08a9a697d2a5, nullptr, nullptr, { &s_fffe08a9a697d2a5, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<51> b_e5104515fd88ea47 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 71, 234, 136, 253, 21, 69, 16, 229, + 47, 0, 0, 0, 1, 0, 2, 0, + 165, 210, 151, 166, 169, 8, 254, 255, + 4, 0, 7, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 226, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 80, 97, 114, 97, 109, 46, 100, + 101, 102, 97, 117, 108, 116, 86, 97, + 108, 117, 101, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 3, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e5104515fd88ea47 = b_e5104515fd88ea47.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_e5104515fd88ea47[] = { + &s_8e207d4dfe54d0de, + &s_fffe08a9a697d2a5, +}; +static const uint16_t m_e5104515fd88ea47[] = {0, 1}; +static const uint16_t i_e5104515fd88ea47[] = {0, 1}; +const ::capnp::_::RawSchema s_e5104515fd88ea47 = { + 0xe5104515fd88ea47, b_e5104515fd88ea47.words, 51, d_e5104515fd88ea47, m_e5104515fd88ea47, + 2, 2, i_e5104515fd88ea47, nullptr, nullptr, { &s_e5104515fd88ea47, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<65> b_89f0c973c103ae96 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 150, 174, 3, 193, 115, 201, 240, 137, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 98, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 105, 100, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 117, 110, 115, 112, 101, 99, 105, 102, + 105, 101, 100, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 100, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 242, 44, 214, 147, 54, 122, 28, 153, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 114, 100, 105, 110, 97, 108, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 242, 44, 214, 147, 54, 122, 28, 153, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_89f0c973c103ae96 = b_89f0c973c103ae96.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_89f0c973c103ae96[] = { + &s_96efe787c17e83bb, + &s_991c7a3693d62cf2, +}; +static const uint16_t m_89f0c973c103ae96[] = {2, 1, 0}; +static const uint16_t i_89f0c973c103ae96[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_89f0c973c103ae96 = { + 0x89f0c973c103ae96, b_89f0c973c103ae96.words, 65, d_89f0c973c103ae96, m_89f0c973c103ae96, + 2, 3, i_89f0c973c103ae96, nullptr, nullptr, { &s_89f0c973c103ae96, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<34> b_e93164a80bfe2ccf = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 207, 44, 254, 11, 168, 100, 49, 233, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 122, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 117, 115, 105, 110, 103, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 116, 97, 114, 103, 101, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e93164a80bfe2ccf = b_e93164a80bfe2ccf.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_e93164a80bfe2ccf[] = { + &s_8e207d4dfe54d0de, + &s_96efe787c17e83bb, +}; +static const uint16_t m_e93164a80bfe2ccf[] = {0}; +static const uint16_t i_e93164a80bfe2ccf[] = {0}; +const ::capnp::_::RawSchema s_e93164a80bfe2ccf = { + 0xe93164a80bfe2ccf, b_e93164a80bfe2ccf.words, 34, d_e93164a80bfe2ccf, m_e93164a80bfe2ccf, + 2, 1, i_e93164a80bfe2ccf, nullptr, nullptr, { &s_e93164a80bfe2ccf, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_b348322a8dcf0d0c = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 12, 13, 207, 141, 42, 50, 72, 179, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 122, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 99, 111, 110, 115, 116, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b348322a8dcf0d0c = b_b348322a8dcf0d0c.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_b348322a8dcf0d0c[] = { + &s_8e207d4dfe54d0de, + &s_96efe787c17e83bb, +}; +static const uint16_t m_b348322a8dcf0d0c[] = {0, 1}; +static const uint16_t i_b348322a8dcf0d0c[] = {0, 1}; +const ::capnp::_::RawSchema s_b348322a8dcf0d0c = { + 0xb348322a8dcf0d0c, b_b348322a8dcf0d0c.words, 49, d_b348322a8dcf0d0c, m_b348322a8dcf0d0c, + 2, 2, i_b348322a8dcf0d0c, nullptr, nullptr, { &s_b348322a8dcf0d0c, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<43> b_8f2622208fb358c8 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 200, 88, 179, 143, 32, 34, 38, 143, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 122, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 102, 105, 101, 108, 100, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 31, 149, 23, 230, 29, 162, 209, 208, + 45, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 101, 102, 97, 117, 108, 116, 86, + 97, 108, 117, 101, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_8f2622208fb358c8 = b_8f2622208fb358c8.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_8f2622208fb358c8[] = { + &s_8e207d4dfe54d0de, + &s_96efe787c17e83bb, + &s_d0d1a21de617951f, +}; +static const uint16_t m_8f2622208fb358c8[] = {1, 0}; +static const uint16_t i_8f2622208fb358c8[] = {0, 1}; +const ::capnp::_::RawSchema s_8f2622208fb358c8 = { + 0x8f2622208fb358c8, b_8f2622208fb358c8.words, 43, d_8f2622208fb358c8, m_8f2622208fb358c8, + 3, 2, i_8f2622208fb358c8, nullptr, nullptr, { &s_8f2622208fb358c8, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<51> b_d0d1a21de617951f = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 31, 149, 23, 230, 29, 162, 209, 208, + 47, 0, 0, 0, 1, 0, 2, 0, + 200, 88, 179, 143, 32, 34, 38, 143, + 8, 0, 7, 0, 1, 0, 2, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 226, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 102, 105, 101, 108, 100, 46, 100, + 101, 102, 97, 117, 108, 116, 86, 97, + 108, 117, 101, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 6, 0, 0, 0, + 0, 0, 1, 0, 18, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d0d1a21de617951f = b_d0d1a21de617951f.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d0d1a21de617951f[] = { + &s_8e207d4dfe54d0de, + &s_8f2622208fb358c8, +}; +static const uint16_t m_d0d1a21de617951f[] = {0, 1}; +static const uint16_t i_d0d1a21de617951f[] = {0, 1}; +const ::capnp::_::RawSchema s_d0d1a21de617951f = { + 0xd0d1a21de617951f, b_d0d1a21de617951f.words, 51, d_d0d1a21de617951f, m_d0d1a21de617951f, + 2, 2, i_d0d1a21de617951f, nullptr, nullptr, { &s_d0d1a21de617951f, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<40> b_992a90eaf30235d3 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 211, 53, 2, 243, 234, 144, 42, 153, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 154, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 105, 110, 116, 101, 114, 102, 97, + 99, 101, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 21, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 40, 0, 0, 0, 2, 0, 1, 0, + 115, 117, 112, 101, 114, 99, 108, 97, + 115, 115, 101, 115, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_992a90eaf30235d3 = b_992a90eaf30235d3.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_992a90eaf30235d3[] = { + &s_8e207d4dfe54d0de, + &s_96efe787c17e83bb, +}; +static const uint16_t m_992a90eaf30235d3[] = {0}; +static const uint16_t i_992a90eaf30235d3[] = {0}; +const ::capnp::_::RawSchema s_992a90eaf30235d3 = { + 0x992a90eaf30235d3, b_992a90eaf30235d3.words, 40, d_992a90eaf30235d3, m_992a90eaf30235d3, + 2, 1, i_992a90eaf30235d3, nullptr, nullptr, { &s_992a90eaf30235d3, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<42> b_eb971847d617c0b9 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 185, 192, 23, 214, 71, 24, 151, 235, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 130, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 109, 101, 116, 104, 111, 100, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 115, 81, 214, 98, 125, 140, 35, 198, + 45, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 205, 27, 216, 121, 122, 110, 246, 179, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 117, 108, 116, 115, 0, } +}; +::capnp::word const* const bp_eb971847d617c0b9 = b_eb971847d617c0b9.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_eb971847d617c0b9[] = { + &s_96efe787c17e83bb, + &s_b3f66e7a79d81bcd, + &s_c6238c7d62d65173, +}; +static const uint16_t m_eb971847d617c0b9[] = {0, 1}; +static const uint16_t i_eb971847d617c0b9[] = {0, 1}; +const ::capnp::_::RawSchema s_eb971847d617c0b9 = { + 0xeb971847d617c0b9, b_eb971847d617c0b9.words, 42, d_eb971847d617c0b9, m_eb971847d617c0b9, + 3, 2, i_eb971847d617c0b9, nullptr, nullptr, { &s_eb971847d617c0b9, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<51> b_c6238c7d62d65173 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 115, 81, 214, 98, 125, 140, 35, 198, + 48, 0, 0, 0, 1, 0, 2, 0, + 185, 192, 23, 214, 71, 24, 151, 235, + 8, 0, 7, 0, 1, 0, 2, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 109, 101, 116, 104, 111, 100, 46, + 114, 101, 115, 117, 108, 116, 115, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 6, 0, 0, 0, + 0, 0, 1, 0, 24, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 56, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 120, 112, 108, 105, 99, 105, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 205, 27, 216, 121, 122, 110, 246, 179, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c6238c7d62d65173 = b_c6238c7d62d65173.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c6238c7d62d65173[] = { + &s_b3f66e7a79d81bcd, + &s_eb971847d617c0b9, +}; +static const uint16_t m_c6238c7d62d65173[] = {1, 0}; +static const uint16_t i_c6238c7d62d65173[] = {0, 1}; +const ::capnp::_::RawSchema s_c6238c7d62d65173 = { + 0xc6238c7d62d65173, b_c6238c7d62d65173.words, 51, d_c6238c7d62d65173, m_c6238c7d62d65173, + 2, 2, i_c6238c7d62d65173, nullptr, nullptr, { &s_c6238c7d62d65173, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<230> b_9cb9e86e3198037f = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 127, 3, 152, 49, 110, 232, 185, 156, + 41, 0, 0, 0, 1, 0, 2, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 8, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 162, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 223, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 68, 101, 99, + 108, 97, 114, 97, 116, 105, 111, 110, + 46, 97, 110, 110, 111, 116, 97, 116, + 105, 111, 110, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 25, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 93, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 1, 0, 0, 3, 0, 1, 0, + 100, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 96, 0, 0, 0, + 0, 0, 1, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 1, 0, 0, 3, 0, 1, 0, + 108, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 97, 0, 0, 0, + 0, 0, 1, 0, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 1, 0, 0, 3, 0, 1, 0, + 116, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 1, 0, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 1, 0, 0, 3, 0, 1, 0, + 124, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 99, 0, 0, 0, + 0, 0, 1, 0, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 1, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 124, 1, 0, 0, 3, 0, 1, 0, + 136, 1, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 100, 0, 0, 0, + 0, 0, 1, 0, 30, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 1, 0, 0, 3, 0, 1, 0, + 144, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 101, 0, 0, 0, + 0, 0, 1, 0, 31, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 140, 1, 0, 0, 3, 0, 1, 0, + 152, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 0, 0, 102, 0, 0, 0, + 0, 0, 1, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 149, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 1, 0, 0, 3, 0, 1, 0, + 160, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 0, 0, 103, 0, 0, 0, + 0, 0, 1, 0, 33, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 157, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 156, 1, 0, 0, 3, 0, 1, 0, + 168, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 0, 0, 104, 0, 0, 0, + 0, 0, 1, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 1, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 1, 0, 0, 3, 0, 1, 0, + 180, 1, 0, 0, 2, 0, 1, 0, + 10, 0, 0, 0, 105, 0, 0, 0, + 0, 0, 1, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 1, 0, 0, 3, 0, 1, 0, + 188, 1, 0, 0, 2, 0, 1, 0, + 11, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 1, 0, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 1, 0, 0, 3, 0, 1, 0, + 196, 1, 0, 0, 2, 0, 1, 0, + 12, 0, 0, 0, 107, 0, 0, 0, + 0, 0, 1, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 1, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 196, 1, 0, 0, 3, 0, 1, 0, + 208, 1, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 222, 208, 84, 254, 77, 125, 32, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 70, + 105, 108, 101, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 67, + 111, 110, 115, 116, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 69, + 110, 117, 109, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 69, + 110, 117, 109, 101, 114, 97, 110, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 83, + 116, 114, 117, 99, 116, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 70, + 105, 101, 108, 100, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 85, + 110, 105, 111, 110, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 71, + 114, 111, 117, 112, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 73, + 110, 116, 101, 114, 102, 97, 99, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 77, + 101, 116, 104, 111, 100, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 80, + 97, 114, 97, 109, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 65, + 110, 110, 111, 116, 97, 116, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9cb9e86e3198037f = b_9cb9e86e3198037f.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9cb9e86e3198037f[] = { + &s_8e207d4dfe54d0de, + &s_96efe787c17e83bb, +}; +static const uint16_t m_9cb9e86e3198037f[] = {12, 2, 3, 4, 6, 1, 8, 9, 10, 11, 5, 7, 0}; +static const uint16_t i_9cb9e86e3198037f[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +const ::capnp::_::RawSchema s_9cb9e86e3198037f = { + 0x9cb9e86e3198037f, b_9cb9e86e3198037f.words, 230, d_9cb9e86e3198037f, m_9cb9e86e3198037f, + 2, 13, i_9cb9e86e3198037f, nullptr, nullptr, { &s_9cb9e86e3198037f, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<34> b_84e4f3f5a807605c = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 92, 96, 7, 168, 245, 243, 228, 132, + 29, 0, 0, 0, 1, 0, 0, 0, + 198, 195, 187, 220, 104, 225, 107, 197, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 103, + 114, 97, 109, 109, 97, 114, 46, 99, + 97, 112, 110, 112, 58, 80, 97, 114, + 115, 101, 100, 70, 105, 108, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 114, 111, 111, 116, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 187, 131, 126, 193, 135, 231, 239, 150, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_84e4f3f5a807605c = b_84e4f3f5a807605c.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_84e4f3f5a807605c[] = { + &s_96efe787c17e83bb, +}; +static const uint16_t m_84e4f3f5a807605c[] = {0}; +static const uint16_t i_84e4f3f5a807605c[] = {0}; +const ::capnp::_::RawSchema s_84e4f3f5a807605c = { + 0x84e4f3f5a807605c, b_84e4f3f5a807605c.words, 34, d_84e4f3f5a807605c, m_84e4f3f5a807605c, + 1, 1, i_84e4f3f5a807605c, nullptr, nullptr, { &s_84e4f3f5a807605c, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { +namespace compiler { + +// LocatedText +constexpr uint16_t LocatedText::_capnpPrivate::dataWordSize; +constexpr uint16_t LocatedText::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind LocatedText::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* LocatedText::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// LocatedInteger +constexpr uint16_t LocatedInteger::_capnpPrivate::dataWordSize; +constexpr uint16_t LocatedInteger::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind LocatedInteger::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* LocatedInteger::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// LocatedFloat +constexpr uint16_t LocatedFloat::_capnpPrivate::dataWordSize; +constexpr uint16_t LocatedFloat::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind LocatedFloat::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* LocatedFloat::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Expression +constexpr uint16_t Expression::_capnpPrivate::dataWordSize; +constexpr uint16_t Expression::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Expression::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Expression::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Expression::Param +constexpr uint16_t Expression::Param::_capnpPrivate::dataWordSize; +constexpr uint16_t Expression::Param::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Expression::Param::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Expression::Param::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Expression::Application +constexpr uint16_t Expression::Application::_capnpPrivate::dataWordSize; +constexpr uint16_t Expression::Application::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Expression::Application::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Expression::Application::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Expression::Member +constexpr uint16_t Expression::Member::_capnpPrivate::dataWordSize; +constexpr uint16_t Expression::Member::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Expression::Member::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Expression::Member::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration +constexpr uint16_t Declaration::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::BrandParameter +constexpr uint16_t Declaration::BrandParameter::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::BrandParameter::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::BrandParameter::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::BrandParameter::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::AnnotationApplication +constexpr uint16_t Declaration::AnnotationApplication::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::AnnotationApplication::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::AnnotationApplication::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::AnnotationApplication::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::AnnotationApplication::Value +constexpr uint16_t Declaration::AnnotationApplication::Value::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::AnnotationApplication::Value::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::AnnotationApplication::Value::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::AnnotationApplication::Value::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::ParamList +constexpr uint16_t Declaration::ParamList::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::ParamList::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::ParamList::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::ParamList::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Param +constexpr uint16_t Declaration::Param::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Param::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Param::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Param::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Param::DefaultValue +constexpr uint16_t Declaration::Param::DefaultValue::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Param::DefaultValue::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Param::DefaultValue::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Param::DefaultValue::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Id +constexpr uint16_t Declaration::Id::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Id::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Id::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Id::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Using +constexpr uint16_t Declaration::Using::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Using::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Using::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Using::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Const +constexpr uint16_t Declaration::Const::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Const::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Const::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Const::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Field +constexpr uint16_t Declaration::Field::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Field::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Field::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Field::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Field::DefaultValue +constexpr uint16_t Declaration::Field::DefaultValue::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Field::DefaultValue::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Field::DefaultValue::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Field::DefaultValue::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Interface +constexpr uint16_t Declaration::Interface::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Interface::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Interface::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Interface::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Method +constexpr uint16_t Declaration::Method::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Method::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Method::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Method::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Method::Results +constexpr uint16_t Declaration::Method::Results::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Method::Results::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Method::Results::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Method::Results::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Declaration::Annotation +constexpr uint16_t Declaration::Annotation::_capnpPrivate::dataWordSize; +constexpr uint16_t Declaration::Annotation::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Declaration::Annotation::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Declaration::Annotation::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// ParsedFile +constexpr uint16_t ParsedFile::_capnpPrivate::dataWordSize; +constexpr uint16_t ParsedFile::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind ParsedFile::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* ParsedFile::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/grammar.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,6837 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: grammar.capnp + +#ifndef CAPNP_INCLUDED_c56be168dcbbc3c6_ +#define CAPNP_INCLUDED_c56be168dcbbc3c6_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(e75816b56529d464); +CAPNP_DECLARE_SCHEMA(991c7a3693d62cf2); +CAPNP_DECLARE_SCHEMA(90f2a60678fd2367); +CAPNP_DECLARE_SCHEMA(8e207d4dfe54d0de); +CAPNP_DECLARE_SCHEMA(c90246b71adedbaa); +CAPNP_DECLARE_SCHEMA(aee8397040b0df7a); +CAPNP_DECLARE_SCHEMA(aa28e1400d793359); +CAPNP_DECLARE_SCHEMA(96efe787c17e83bb); +CAPNP_DECLARE_SCHEMA(d5e71144af1ce175); +CAPNP_DECLARE_SCHEMA(d00489d473826290); +CAPNP_DECLARE_SCHEMA(fb5aeed95cdf6af9); +CAPNP_DECLARE_SCHEMA(94099c3f9eb32d6b); +CAPNP_DECLARE_SCHEMA(b3f66e7a79d81bcd); +CAPNP_DECLARE_SCHEMA(fffe08a9a697d2a5); +CAPNP_DECLARE_SCHEMA(e5104515fd88ea47); +CAPNP_DECLARE_SCHEMA(89f0c973c103ae96); +CAPNP_DECLARE_SCHEMA(e93164a80bfe2ccf); +CAPNP_DECLARE_SCHEMA(b348322a8dcf0d0c); +CAPNP_DECLARE_SCHEMA(8f2622208fb358c8); +CAPNP_DECLARE_SCHEMA(d0d1a21de617951f); +CAPNP_DECLARE_SCHEMA(992a90eaf30235d3); +CAPNP_DECLARE_SCHEMA(eb971847d617c0b9); +CAPNP_DECLARE_SCHEMA(c6238c7d62d65173); +CAPNP_DECLARE_SCHEMA(9cb9e86e3198037f); +CAPNP_DECLARE_SCHEMA(84e4f3f5a807605c); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace compiler { + +struct LocatedText { + LocatedText() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e75816b56529d464, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct LocatedInteger { + LocatedInteger() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(991c7a3693d62cf2, 2, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct LocatedFloat { + LocatedFloat() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(90f2a60678fd2367, 2, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Expression { + Expression() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNKNOWN, + POSITIVE_INT, + NEGATIVE_INT, + FLOAT, + STRING, + RELATIVE_NAME, + LIST, + TUPLE, + BINARY, + APPLICATION, + MEMBER, + ABSOLUTE_NAME, + IMPORT, + EMBED, + }; + struct Param; + struct Application; + struct Member; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8e207d4dfe54d0de, 3, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Expression::Param { + Param() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNNAMED, + NAMED, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c90246b71adedbaa, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Expression::Application { + Application() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(aee8397040b0df7a, 3, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Expression::Member { + Member() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(aa28e1400d793359, 3, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration { + Declaration() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + FILE, + USING, + CONST, + ENUM, + ENUMERANT, + STRUCT, + FIELD, + UNION, + GROUP, + INTERFACE, + METHOD, + ANNOTATION, + NAKED_ID, + NAKED_ANNOTATION, + BUILTIN_VOID, + BUILTIN_BOOL, + BUILTIN_INT8, + BUILTIN_INT16, + BUILTIN_INT32, + BUILTIN_INT64, + BUILTIN_U_INT8, + BUILTIN_U_INT16, + BUILTIN_U_INT32, + BUILTIN_U_INT64, + BUILTIN_FLOAT32, + BUILTIN_FLOAT64, + BUILTIN_TEXT, + BUILTIN_DATA, + BUILTIN_LIST, + BUILTIN_OBJECT, + BUILTIN_ANY_POINTER, + BUILTIN_ANY_STRUCT, + BUILTIN_ANY_LIST, + BUILTIN_CAPABILITY, + }; + struct BrandParameter; + struct AnnotationApplication; + struct ParamList; + struct Param; + struct Id; + struct Using; + struct Const; + struct Field; + struct Interface; + struct Method; + struct Annotation; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(96efe787c17e83bb, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::BrandParameter { + BrandParameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d5e71144af1ce175, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::AnnotationApplication { + AnnotationApplication() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Value; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d00489d473826290, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::AnnotationApplication::Value { + Value() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + EXPRESSION, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(fb5aeed95cdf6af9, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::ParamList { + ParamList() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NAMED_LIST, + TYPE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b3f66e7a79d81bcd, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Param { + Param() = delete; + + class Reader; + class Builder; + class Pipeline; + struct DefaultValue; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(fffe08a9a697d2a5, 2, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Param::DefaultValue { + DefaultValue() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + VALUE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e5104515fd88ea47, 2, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Id { + Id() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNSPECIFIED, + UID, + ORDINAL, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(89f0c973c103ae96, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Using { + Using() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e93164a80bfe2ccf, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Const { + Const() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b348322a8dcf0d0c, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Field { + Field() = delete; + + class Reader; + class Builder; + class Pipeline; + struct DefaultValue; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8f2622208fb358c8, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Field::DefaultValue { + DefaultValue() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + VALUE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d0d1a21de617951f, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Interface { + Interface() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(992a90eaf30235d3, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Method { + Method() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Results; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(eb971847d617c0b9, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Method::Results { + Results() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + EXPLICIT, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c6238c7d62d65173, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Declaration::Annotation { + Annotation() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9cb9e86e3198037f, 2, 8) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ParsedFile { + ParsedFile() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(84e4f3f5a807605c, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class LocatedText::Reader { +public: + typedef LocatedText Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasValue() const; + inline ::capnp::Text::Reader getValue() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class LocatedText::Builder { +public: + typedef LocatedText Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasValue(); + inline ::capnp::Text::Builder getValue(); + inline void setValue( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initValue(unsigned int size); + inline void adoptValue(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownValue(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class LocatedText::Pipeline { +public: + typedef LocatedText Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class LocatedInteger::Reader { +public: + typedef LocatedInteger Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getValue() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class LocatedInteger::Builder { +public: + typedef LocatedInteger Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getValue(); + inline void setValue( ::uint64_t value); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class LocatedInteger::Pipeline { +public: + typedef LocatedInteger Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class LocatedFloat::Reader { +public: + typedef LocatedFloat Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline double getValue() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class LocatedFloat::Builder { +public: + typedef LocatedFloat Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline double getValue(); + inline void setValue(double value); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class LocatedFloat::Pipeline { +public: + typedef LocatedFloat Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Expression::Reader { +public: + typedef Expression Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnknown() const; + inline ::capnp::Void getUnknown() const; + + inline bool isPositiveInt() const; + inline ::uint64_t getPositiveInt() const; + + inline bool isNegativeInt() const; + inline ::uint64_t getNegativeInt() const; + + inline bool isFloat() const; + inline double getFloat() const; + + inline bool isString() const; + inline bool hasString() const; + inline ::capnp::Text::Reader getString() const; + + inline bool isRelativeName() const; + inline bool hasRelativeName() const; + inline ::capnp::compiler::LocatedText::Reader getRelativeName() const; + + inline bool isList() const; + inline bool hasList() const; + inline ::capnp::List< ::capnp::compiler::Expression>::Reader getList() const; + + inline bool isTuple() const; + inline bool hasTuple() const; + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Reader getTuple() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + + inline bool isBinary() const; + inline bool hasBinary() const; + inline ::capnp::Data::Reader getBinary() const; + + inline bool isApplication() const; + inline typename Application::Reader getApplication() const; + + inline bool isMember() const; + inline typename Member::Reader getMember() const; + + inline bool isAbsoluteName() const; + inline bool hasAbsoluteName() const; + inline ::capnp::compiler::LocatedText::Reader getAbsoluteName() const; + + inline bool isImport() const; + inline bool hasImport() const; + inline ::capnp::compiler::LocatedText::Reader getImport() const; + + inline bool isEmbed() const; + inline bool hasEmbed() const; + inline ::capnp::compiler::LocatedText::Reader getEmbed() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Expression::Builder { +public: + typedef Expression Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnknown(); + inline ::capnp::Void getUnknown(); + inline void setUnknown( ::capnp::Void value = ::capnp::VOID); + + inline bool isPositiveInt(); + inline ::uint64_t getPositiveInt(); + inline void setPositiveInt( ::uint64_t value); + + inline bool isNegativeInt(); + inline ::uint64_t getNegativeInt(); + inline void setNegativeInt( ::uint64_t value); + + inline bool isFloat(); + inline double getFloat(); + inline void setFloat(double value); + + inline bool isString(); + inline bool hasString(); + inline ::capnp::Text::Builder getString(); + inline void setString( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initString(unsigned int size); + inline void adoptString(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownString(); + + inline bool isRelativeName(); + inline bool hasRelativeName(); + inline ::capnp::compiler::LocatedText::Builder getRelativeName(); + inline void setRelativeName( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initRelativeName(); + inline void adoptRelativeName(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownRelativeName(); + + inline bool isList(); + inline bool hasList(); + inline ::capnp::List< ::capnp::compiler::Expression>::Builder getList(); + inline void setList( ::capnp::List< ::capnp::compiler::Expression>::Reader value); + inline ::capnp::List< ::capnp::compiler::Expression>::Builder initList(unsigned int size); + inline void adoptList(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>> disownList(); + + inline bool isTuple(); + inline bool hasTuple(); + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder getTuple(); + inline void setTuple( ::capnp::List< ::capnp::compiler::Expression::Param>::Reader value); + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder initTuple(unsigned int size); + inline void adoptTuple(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>> disownTuple(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + + inline bool isBinary(); + inline bool hasBinary(); + inline ::capnp::Data::Builder getBinary(); + inline void setBinary( ::capnp::Data::Reader value); + inline ::capnp::Data::Builder initBinary(unsigned int size); + inline void adoptBinary(::capnp::Orphan< ::capnp::Data>&& value); + inline ::capnp::Orphan< ::capnp::Data> disownBinary(); + + inline bool isApplication(); + inline typename Application::Builder getApplication(); + inline typename Application::Builder initApplication(); + + inline bool isMember(); + inline typename Member::Builder getMember(); + inline typename Member::Builder initMember(); + + inline bool isAbsoluteName(); + inline bool hasAbsoluteName(); + inline ::capnp::compiler::LocatedText::Builder getAbsoluteName(); + inline void setAbsoluteName( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initAbsoluteName(); + inline void adoptAbsoluteName(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownAbsoluteName(); + + inline bool isImport(); + inline bool hasImport(); + inline ::capnp::compiler::LocatedText::Builder getImport(); + inline void setImport( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initImport(); + inline void adoptImport(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownImport(); + + inline bool isEmbed(); + inline bool hasEmbed(); + inline ::capnp::compiler::LocatedText::Builder getEmbed(); + inline void setEmbed( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initEmbed(); + inline void adoptEmbed(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownEmbed(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Expression::Pipeline { +public: + typedef Expression Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Expression::Param::Reader { +public: + typedef Param Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnnamed() const; + inline ::capnp::Void getUnnamed() const; + + inline bool isNamed() const; + inline bool hasNamed() const; + inline ::capnp::compiler::LocatedText::Reader getNamed() const; + + inline bool hasValue() const; + inline ::capnp::compiler::Expression::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Expression::Param::Builder { +public: + typedef Param Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnnamed(); + inline ::capnp::Void getUnnamed(); + inline void setUnnamed( ::capnp::Void value = ::capnp::VOID); + + inline bool isNamed(); + inline bool hasNamed(); + inline ::capnp::compiler::LocatedText::Builder getNamed(); + inline void setNamed( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initNamed(); + inline void adoptNamed(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownNamed(); + + inline bool hasValue(); + inline ::capnp::compiler::Expression::Builder getValue(); + inline void setValue( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Expression::Param::Pipeline { +public: + typedef Param Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Expression::Application::Reader { +public: + typedef Application Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasFunction() const; + inline ::capnp::compiler::Expression::Reader getFunction() const; + + inline bool hasParams() const; + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Expression::Application::Builder { +public: + typedef Application Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasFunction(); + inline ::capnp::compiler::Expression::Builder getFunction(); + inline void setFunction( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initFunction(); + inline void adoptFunction(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownFunction(); + + inline bool hasParams(); + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder getParams(); + inline void setParams( ::capnp::List< ::capnp::compiler::Expression::Param>::Reader value); + inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder initParams(unsigned int size); + inline void adoptParams(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Expression::Application::Pipeline { +public: + typedef Application Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getFunction(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Expression::Member::Reader { +public: + typedef Member Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasParent() const; + inline ::capnp::compiler::Expression::Reader getParent() const; + + inline bool hasName() const; + inline ::capnp::compiler::LocatedText::Reader getName() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Expression::Member::Builder { +public: + typedef Member Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasParent(); + inline ::capnp::compiler::Expression::Builder getParent(); + inline void setParent( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initParent(); + inline void adoptParent(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownParent(); + + inline bool hasName(); + inline ::capnp::compiler::LocatedText::Builder getName(); + inline void setName( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initName(); + inline void adoptName(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownName(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Expression::Member::Pipeline { +public: + typedef Member Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getParent(); + inline ::capnp::compiler::LocatedText::Pipeline getName(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Reader { +public: + typedef Declaration Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool hasName() const; + inline ::capnp::compiler::LocatedText::Reader getName() const; + + inline typename Id::Reader getId() const; + + inline bool hasNestedDecls() const; + inline ::capnp::List< ::capnp::compiler::Declaration>::Reader getNestedDecls() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader getAnnotations() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + + inline bool hasDocComment() const; + inline ::capnp::Text::Reader getDocComment() const; + + inline bool isFile() const; + inline ::capnp::Void getFile() const; + + inline bool isUsing() const; + inline typename Using::Reader getUsing() const; + + inline bool isConst() const; + inline typename Const::Reader getConst() const; + + inline bool isEnum() const; + inline ::capnp::Void getEnum() const; + + inline bool isEnumerant() const; + inline ::capnp::Void getEnumerant() const; + + inline bool isStruct() const; + inline ::capnp::Void getStruct() const; + + inline bool isField() const; + inline typename Field::Reader getField() const; + + inline bool isUnion() const; + inline ::capnp::Void getUnion() const; + + inline bool isGroup() const; + inline ::capnp::Void getGroup() const; + + inline bool isInterface() const; + inline typename Interface::Reader getInterface() const; + + inline bool isMethod() const; + inline typename Method::Reader getMethod() const; + + inline bool isAnnotation() const; + inline typename Annotation::Reader getAnnotation() const; + + inline bool isNakedId() const; + inline bool hasNakedId() const; + inline ::capnp::compiler::LocatedInteger::Reader getNakedId() const; + + inline bool isNakedAnnotation() const; + inline bool hasNakedAnnotation() const; + inline ::capnp::compiler::Declaration::AnnotationApplication::Reader getNakedAnnotation() const; + + inline bool isBuiltinVoid() const; + inline ::capnp::Void getBuiltinVoid() const; + + inline bool isBuiltinBool() const; + inline ::capnp::Void getBuiltinBool() const; + + inline bool isBuiltinInt8() const; + inline ::capnp::Void getBuiltinInt8() const; + + inline bool isBuiltinInt16() const; + inline ::capnp::Void getBuiltinInt16() const; + + inline bool isBuiltinInt32() const; + inline ::capnp::Void getBuiltinInt32() const; + + inline bool isBuiltinInt64() const; + inline ::capnp::Void getBuiltinInt64() const; + + inline bool isBuiltinUInt8() const; + inline ::capnp::Void getBuiltinUInt8() const; + + inline bool isBuiltinUInt16() const; + inline ::capnp::Void getBuiltinUInt16() const; + + inline bool isBuiltinUInt32() const; + inline ::capnp::Void getBuiltinUInt32() const; + + inline bool isBuiltinUInt64() const; + inline ::capnp::Void getBuiltinUInt64() const; + + inline bool isBuiltinFloat32() const; + inline ::capnp::Void getBuiltinFloat32() const; + + inline bool isBuiltinFloat64() const; + inline ::capnp::Void getBuiltinFloat64() const; + + inline bool isBuiltinText() const; + inline ::capnp::Void getBuiltinText() const; + + inline bool isBuiltinData() const; + inline ::capnp::Void getBuiltinData() const; + + inline bool isBuiltinList() const; + inline ::capnp::Void getBuiltinList() const; + + inline bool isBuiltinObject() const; + inline ::capnp::Void getBuiltinObject() const; + + inline bool isBuiltinAnyPointer() const; + inline ::capnp::Void getBuiltinAnyPointer() const; + + inline bool hasParameters() const; + inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Reader getParameters() const; + + inline bool isBuiltinAnyStruct() const; + inline ::capnp::Void getBuiltinAnyStruct() const; + + inline bool isBuiltinAnyList() const; + inline ::capnp::Void getBuiltinAnyList() const; + + inline bool isBuiltinCapability() const; + inline ::capnp::Void getBuiltinCapability() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Builder { +public: + typedef Declaration Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool hasName(); + inline ::capnp::compiler::LocatedText::Builder getName(); + inline void setName( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initName(); + inline void adoptName(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownName(); + + inline typename Id::Builder getId(); + inline typename Id::Builder initId(); + + inline bool hasNestedDecls(); + inline ::capnp::List< ::capnp::compiler::Declaration>::Builder getNestedDecls(); + inline void setNestedDecls( ::capnp::List< ::capnp::compiler::Declaration>::Reader value); + inline ::capnp::List< ::capnp::compiler::Declaration>::Builder initNestedDecls(unsigned int size); + inline void adoptNestedDecls(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration>> disownNestedDecls(); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader value); + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>> disownAnnotations(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + + inline bool hasDocComment(); + inline ::capnp::Text::Builder getDocComment(); + inline void setDocComment( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initDocComment(unsigned int size); + inline void adoptDocComment(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownDocComment(); + + inline bool isFile(); + inline ::capnp::Void getFile(); + inline void setFile( ::capnp::Void value = ::capnp::VOID); + + inline bool isUsing(); + inline typename Using::Builder getUsing(); + inline typename Using::Builder initUsing(); + + inline bool isConst(); + inline typename Const::Builder getConst(); + inline typename Const::Builder initConst(); + + inline bool isEnum(); + inline ::capnp::Void getEnum(); + inline void setEnum( ::capnp::Void value = ::capnp::VOID); + + inline bool isEnumerant(); + inline ::capnp::Void getEnumerant(); + inline void setEnumerant( ::capnp::Void value = ::capnp::VOID); + + inline bool isStruct(); + inline ::capnp::Void getStruct(); + inline void setStruct( ::capnp::Void value = ::capnp::VOID); + + inline bool isField(); + inline typename Field::Builder getField(); + inline typename Field::Builder initField(); + + inline bool isUnion(); + inline ::capnp::Void getUnion(); + inline void setUnion( ::capnp::Void value = ::capnp::VOID); + + inline bool isGroup(); + inline ::capnp::Void getGroup(); + inline void setGroup( ::capnp::Void value = ::capnp::VOID); + + inline bool isInterface(); + inline typename Interface::Builder getInterface(); + inline typename Interface::Builder initInterface(); + + inline bool isMethod(); + inline typename Method::Builder getMethod(); + inline typename Method::Builder initMethod(); + + inline bool isAnnotation(); + inline typename Annotation::Builder getAnnotation(); + inline typename Annotation::Builder initAnnotation(); + + inline bool isNakedId(); + inline bool hasNakedId(); + inline ::capnp::compiler::LocatedInteger::Builder getNakedId(); + inline void setNakedId( ::capnp::compiler::LocatedInteger::Reader value); + inline ::capnp::compiler::LocatedInteger::Builder initNakedId(); + inline void adoptNakedId(::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> disownNakedId(); + + inline bool isNakedAnnotation(); + inline bool hasNakedAnnotation(); + inline ::capnp::compiler::Declaration::AnnotationApplication::Builder getNakedAnnotation(); + inline void setNakedAnnotation( ::capnp::compiler::Declaration::AnnotationApplication::Reader value); + inline ::capnp::compiler::Declaration::AnnotationApplication::Builder initNakedAnnotation(); + inline void adoptNakedAnnotation(::capnp::Orphan< ::capnp::compiler::Declaration::AnnotationApplication>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Declaration::AnnotationApplication> disownNakedAnnotation(); + + inline bool isBuiltinVoid(); + inline ::capnp::Void getBuiltinVoid(); + inline void setBuiltinVoid( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinBool(); + inline ::capnp::Void getBuiltinBool(); + inline void setBuiltinBool( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinInt8(); + inline ::capnp::Void getBuiltinInt8(); + inline void setBuiltinInt8( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinInt16(); + inline ::capnp::Void getBuiltinInt16(); + inline void setBuiltinInt16( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinInt32(); + inline ::capnp::Void getBuiltinInt32(); + inline void setBuiltinInt32( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinInt64(); + inline ::capnp::Void getBuiltinInt64(); + inline void setBuiltinInt64( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinUInt8(); + inline ::capnp::Void getBuiltinUInt8(); + inline void setBuiltinUInt8( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinUInt16(); + inline ::capnp::Void getBuiltinUInt16(); + inline void setBuiltinUInt16( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinUInt32(); + inline ::capnp::Void getBuiltinUInt32(); + inline void setBuiltinUInt32( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinUInt64(); + inline ::capnp::Void getBuiltinUInt64(); + inline void setBuiltinUInt64( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinFloat32(); + inline ::capnp::Void getBuiltinFloat32(); + inline void setBuiltinFloat32( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinFloat64(); + inline ::capnp::Void getBuiltinFloat64(); + inline void setBuiltinFloat64( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinText(); + inline ::capnp::Void getBuiltinText(); + inline void setBuiltinText( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinData(); + inline ::capnp::Void getBuiltinData(); + inline void setBuiltinData( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinList(); + inline ::capnp::Void getBuiltinList(); + inline void setBuiltinList( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinObject(); + inline ::capnp::Void getBuiltinObject(); + inline void setBuiltinObject( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinAnyPointer(); + inline ::capnp::Void getBuiltinAnyPointer(); + inline void setBuiltinAnyPointer( ::capnp::Void value = ::capnp::VOID); + + inline bool hasParameters(); + inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Builder getParameters(); + inline void setParameters( ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Reader value); + inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Builder initParameters(unsigned int size); + inline void adoptParameters(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>> disownParameters(); + + inline bool isBuiltinAnyStruct(); + inline ::capnp::Void getBuiltinAnyStruct(); + inline void setBuiltinAnyStruct( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinAnyList(); + inline ::capnp::Void getBuiltinAnyList(); + inline void setBuiltinAnyList( ::capnp::Void value = ::capnp::VOID); + + inline bool isBuiltinCapability(); + inline ::capnp::Void getBuiltinCapability(); + inline void setBuiltinCapability( ::capnp::Void value = ::capnp::VOID); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Pipeline { +public: + typedef Declaration Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::LocatedText::Pipeline getName(); + inline typename Id::Pipeline getId(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::BrandParameter::Reader { +public: + typedef BrandParameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::BrandParameter::Builder { +public: + typedef BrandParameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::BrandParameter::Pipeline { +public: + typedef BrandParameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::AnnotationApplication::Reader { +public: + typedef AnnotationApplication Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::compiler::Expression::Reader getName() const; + + inline typename Value::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::AnnotationApplication::Builder { +public: + typedef AnnotationApplication Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::compiler::Expression::Builder getName(); + inline void setName( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initName(); + inline void adoptName(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownName(); + + inline typename Value::Builder getValue(); + inline typename Value::Builder initValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::AnnotationApplication::Pipeline { +public: + typedef AnnotationApplication Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getName(); + inline typename Value::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::AnnotationApplication::Value::Reader { +public: + typedef Value Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isExpression() const; + inline bool hasExpression() const; + inline ::capnp::compiler::Expression::Reader getExpression() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::AnnotationApplication::Value::Builder { +public: + typedef Value Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isExpression(); + inline bool hasExpression(); + inline ::capnp::compiler::Expression::Builder getExpression(); + inline void setExpression( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initExpression(); + inline void adoptExpression(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownExpression(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::AnnotationApplication::Value::Pipeline { +public: + typedef Value Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::ParamList::Reader { +public: + typedef ParamList Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNamedList() const; + inline bool hasNamedList() const; + inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Reader getNamedList() const; + + inline bool isType() const; + inline bool hasType() const; + inline ::capnp::compiler::Expression::Reader getType() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::ParamList::Builder { +public: + typedef ParamList Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNamedList(); + inline bool hasNamedList(); + inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Builder getNamedList(); + inline void setNamedList( ::capnp::List< ::capnp::compiler::Declaration::Param>::Reader value); + inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Builder initNamedList(unsigned int size); + inline void adoptNamedList(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::Param>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::Param>> disownNamedList(); + + inline bool isType(); + inline bool hasType(); + inline ::capnp::compiler::Expression::Builder getType(); + inline void setType( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownType(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::ParamList::Pipeline { +public: + typedef ParamList Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Param::Reader { +public: + typedef Param Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::compiler::LocatedText::Reader getName() const; + + inline bool hasType() const; + inline ::capnp::compiler::Expression::Reader getType() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader getAnnotations() const; + + inline typename DefaultValue::Reader getDefaultValue() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Param::Builder { +public: + typedef Param Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::compiler::LocatedText::Builder getName(); + inline void setName( ::capnp::compiler::LocatedText::Reader value); + inline ::capnp::compiler::LocatedText::Builder initName(); + inline void adoptName(::capnp::Orphan< ::capnp::compiler::LocatedText>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedText> disownName(); + + inline bool hasType(); + inline ::capnp::compiler::Expression::Builder getType(); + inline void setType( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownType(); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader value); + inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>> disownAnnotations(); + + inline typename DefaultValue::Builder getDefaultValue(); + inline typename DefaultValue::Builder initDefaultValue(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Param::Pipeline { +public: + typedef Param Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::LocatedText::Pipeline getName(); + inline ::capnp::compiler::Expression::Pipeline getType(); + inline typename DefaultValue::Pipeline getDefaultValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Param::DefaultValue::Reader { +public: + typedef DefaultValue Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isValue() const; + inline bool hasValue() const; + inline ::capnp::compiler::Expression::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Param::DefaultValue::Builder { +public: + typedef DefaultValue Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isValue(); + inline bool hasValue(); + inline ::capnp::compiler::Expression::Builder getValue(); + inline void setValue( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Param::DefaultValue::Pipeline { +public: + typedef DefaultValue Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Id::Reader { +public: + typedef Id Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnspecified() const; + inline ::capnp::Void getUnspecified() const; + + inline bool isUid() const; + inline bool hasUid() const; + inline ::capnp::compiler::LocatedInteger::Reader getUid() const; + + inline bool isOrdinal() const; + inline bool hasOrdinal() const; + inline ::capnp::compiler::LocatedInteger::Reader getOrdinal() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Id::Builder { +public: + typedef Id Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnspecified(); + inline ::capnp::Void getUnspecified(); + inline void setUnspecified( ::capnp::Void value = ::capnp::VOID); + + inline bool isUid(); + inline bool hasUid(); + inline ::capnp::compiler::LocatedInteger::Builder getUid(); + inline void setUid( ::capnp::compiler::LocatedInteger::Reader value); + inline ::capnp::compiler::LocatedInteger::Builder initUid(); + inline void adoptUid(::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> disownUid(); + + inline bool isOrdinal(); + inline bool hasOrdinal(); + inline ::capnp::compiler::LocatedInteger::Builder getOrdinal(); + inline void setOrdinal( ::capnp::compiler::LocatedInteger::Reader value); + inline ::capnp::compiler::LocatedInteger::Builder initOrdinal(); + inline void adoptOrdinal(::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value); + inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> disownOrdinal(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Id::Pipeline { +public: + typedef Id Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Using::Reader { +public: + typedef Using Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasTarget() const; + inline ::capnp::compiler::Expression::Reader getTarget() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Using::Builder { +public: + typedef Using Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasTarget(); + inline ::capnp::compiler::Expression::Builder getTarget(); + inline void setTarget( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownTarget(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Using::Pipeline { +public: + typedef Using Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getTarget(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Const::Reader { +public: + typedef Const Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::compiler::Expression::Reader getType() const; + + inline bool hasValue() const; + inline ::capnp::compiler::Expression::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Const::Builder { +public: + typedef Const Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::compiler::Expression::Builder getType(); + inline void setType( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownType(); + + inline bool hasValue(); + inline ::capnp::compiler::Expression::Builder getValue(); + inline void setValue( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Const::Pipeline { +public: + typedef Const Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getType(); + inline ::capnp::compiler::Expression::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Field::Reader { +public: + typedef Field Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::compiler::Expression::Reader getType() const; + + inline typename DefaultValue::Reader getDefaultValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Field::Builder { +public: + typedef Field Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::compiler::Expression::Builder getType(); + inline void setType( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownType(); + + inline typename DefaultValue::Builder getDefaultValue(); + inline typename DefaultValue::Builder initDefaultValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Field::Pipeline { +public: + typedef Field Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getType(); + inline typename DefaultValue::Pipeline getDefaultValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Field::DefaultValue::Reader { +public: + typedef DefaultValue Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isValue() const; + inline bool hasValue() const; + inline ::capnp::compiler::Expression::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Field::DefaultValue::Builder { +public: + typedef DefaultValue Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isValue(); + inline bool hasValue(); + inline ::capnp::compiler::Expression::Builder getValue(); + inline void setValue( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Field::DefaultValue::Pipeline { +public: + typedef DefaultValue Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Interface::Reader { +public: + typedef Interface Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasSuperclasses() const; + inline ::capnp::List< ::capnp::compiler::Expression>::Reader getSuperclasses() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Interface::Builder { +public: + typedef Interface Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasSuperclasses(); + inline ::capnp::List< ::capnp::compiler::Expression>::Builder getSuperclasses(); + inline void setSuperclasses( ::capnp::List< ::capnp::compiler::Expression>::Reader value); + inline ::capnp::List< ::capnp::compiler::Expression>::Builder initSuperclasses(unsigned int size); + inline void adoptSuperclasses(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>> disownSuperclasses(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Interface::Pipeline { +public: + typedef Interface Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Method::Reader { +public: + typedef Method Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasParams() const; + inline ::capnp::compiler::Declaration::ParamList::Reader getParams() const; + + inline typename Results::Reader getResults() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Method::Builder { +public: + typedef Method Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasParams(); + inline ::capnp::compiler::Declaration::ParamList::Builder getParams(); + inline void setParams( ::capnp::compiler::Declaration::ParamList::Reader value); + inline ::capnp::compiler::Declaration::ParamList::Builder initParams(); + inline void adoptParams(::capnp::Orphan< ::capnp::compiler::Declaration::ParamList>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList> disownParams(); + + inline typename Results::Builder getResults(); + inline typename Results::Builder initResults(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Method::Pipeline { +public: + typedef Method Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Declaration::ParamList::Pipeline getParams(); + inline typename Results::Pipeline getResults(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Method::Results::Reader { +public: + typedef Results Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isExplicit() const; + inline bool hasExplicit() const; + inline ::capnp::compiler::Declaration::ParamList::Reader getExplicit() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Method::Results::Builder { +public: + typedef Results Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isExplicit(); + inline bool hasExplicit(); + inline ::capnp::compiler::Declaration::ParamList::Builder getExplicit(); + inline void setExplicit( ::capnp::compiler::Declaration::ParamList::Reader value); + inline ::capnp::compiler::Declaration::ParamList::Builder initExplicit(); + inline void adoptExplicit(::capnp::Orphan< ::capnp::compiler::Declaration::ParamList>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList> disownExplicit(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Method::Results::Pipeline { +public: + typedef Results Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Declaration::Annotation::Reader { +public: + typedef Annotation Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::compiler::Expression::Reader getType() const; + + inline bool getTargetsFile() const; + + inline bool getTargetsConst() const; + + inline bool getTargetsEnum() const; + + inline bool getTargetsEnumerant() const; + + inline bool getTargetsStruct() const; + + inline bool getTargetsField() const; + + inline bool getTargetsUnion() const; + + inline bool getTargetsGroup() const; + + inline bool getTargetsInterface() const; + + inline bool getTargetsMethod() const; + + inline bool getTargetsParam() const; + + inline bool getTargetsAnnotation() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Declaration::Annotation::Builder { +public: + typedef Annotation Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::compiler::Expression::Builder getType(); + inline void setType( ::capnp::compiler::Expression::Reader value); + inline ::capnp::compiler::Expression::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::compiler::Expression>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Expression> disownType(); + + inline bool getTargetsFile(); + inline void setTargetsFile(bool value); + + inline bool getTargetsConst(); + inline void setTargetsConst(bool value); + + inline bool getTargetsEnum(); + inline void setTargetsEnum(bool value); + + inline bool getTargetsEnumerant(); + inline void setTargetsEnumerant(bool value); + + inline bool getTargetsStruct(); + inline void setTargetsStruct(bool value); + + inline bool getTargetsField(); + inline void setTargetsField(bool value); + + inline bool getTargetsUnion(); + inline void setTargetsUnion(bool value); + + inline bool getTargetsGroup(); + inline void setTargetsGroup(bool value); + + inline bool getTargetsInterface(); + inline void setTargetsInterface(bool value); + + inline bool getTargetsMethod(); + inline void setTargetsMethod(bool value); + + inline bool getTargetsParam(); + inline void setTargetsParam(bool value); + + inline bool getTargetsAnnotation(); + inline void setTargetsAnnotation(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Declaration::Annotation::Pipeline { +public: + typedef Annotation Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Expression::Pipeline getType(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ParsedFile::Reader { +public: + typedef ParsedFile Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasRoot() const; + inline ::capnp::compiler::Declaration::Reader getRoot() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ParsedFile::Builder { +public: + typedef ParsedFile Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasRoot(); + inline ::capnp::compiler::Declaration::Builder getRoot(); + inline void setRoot( ::capnp::compiler::Declaration::Reader value); + inline ::capnp::compiler::Declaration::Builder initRoot(); + inline void adoptRoot(::capnp::Orphan< ::capnp::compiler::Declaration>&& value); + inline ::capnp::Orphan< ::capnp::compiler::Declaration> disownRoot(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ParsedFile::Pipeline { +public: + typedef ParsedFile Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::compiler::Declaration::Pipeline getRoot(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline bool LocatedText::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool LocatedText::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader LocatedText::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder LocatedText::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void LocatedText::Builder::setValue( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder LocatedText::Builder::initValue(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void LocatedText::Builder::adoptValue( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> LocatedText::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t LocatedText::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedText::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void LocatedText::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t LocatedText::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedText::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void LocatedText::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t LocatedInteger::Reader::getValue() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t LocatedInteger::Builder::getValue() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void LocatedInteger::Builder::setValue( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t LocatedInteger::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedInteger::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void LocatedInteger::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t LocatedInteger::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedInteger::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void LocatedInteger::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline double LocatedFloat::Reader::getValue() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline double LocatedFloat::Builder::getValue() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void LocatedFloat::Builder::setValue(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t LocatedFloat::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedFloat::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void LocatedFloat::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t LocatedFloat::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t LocatedFloat::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void LocatedFloat::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::compiler::Expression::Which Expression::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Expression::Which Expression::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Expression::Reader::isUnknown() const { + return which() == Expression::UNKNOWN; +} +inline bool Expression::Builder::isUnknown() { + return which() == Expression::UNKNOWN; +} +inline ::capnp::Void Expression::Reader::getUnknown() const { + KJ_IREQUIRE((which() == Expression::UNKNOWN), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Expression::Builder::getUnknown() { + KJ_IREQUIRE((which() == Expression::UNKNOWN), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setUnknown( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::UNKNOWN); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Reader::isPositiveInt() const { + return which() == Expression::POSITIVE_INT; +} +inline bool Expression::Builder::isPositiveInt() { + return which() == Expression::POSITIVE_INT; +} +inline ::uint64_t Expression::Reader::getPositiveInt() const { + KJ_IREQUIRE((which() == Expression::POSITIVE_INT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Expression::Builder::getPositiveInt() { + KJ_IREQUIRE((which() == Expression::POSITIVE_INT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setPositiveInt( ::uint64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::POSITIVE_INT); + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Reader::isNegativeInt() const { + return which() == Expression::NEGATIVE_INT; +} +inline bool Expression::Builder::isNegativeInt() { + return which() == Expression::NEGATIVE_INT; +} +inline ::uint64_t Expression::Reader::getNegativeInt() const { + KJ_IREQUIRE((which() == Expression::NEGATIVE_INT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Expression::Builder::getNegativeInt() { + KJ_IREQUIRE((which() == Expression::NEGATIVE_INT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setNegativeInt( ::uint64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::NEGATIVE_INT); + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Reader::isFloat() const { + return which() == Expression::FLOAT; +} +inline bool Expression::Builder::isFloat() { + return which() == Expression::FLOAT; +} +inline double Expression::Reader::getFloat() const { + KJ_IREQUIRE((which() == Expression::FLOAT), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double Expression::Builder::getFloat() { + KJ_IREQUIRE((which() == Expression::FLOAT), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setFloat(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::FLOAT); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Reader::isString() const { + return which() == Expression::STRING; +} +inline bool Expression::Builder::isString() { + return which() == Expression::STRING; +} +inline bool Expression::Reader::hasString() const { + if (which() != Expression::STRING) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasString() { + if (which() != Expression::STRING) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Expression::Reader::getString() const { + KJ_IREQUIRE((which() == Expression::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Expression::Builder::getString() { + KJ_IREQUIRE((which() == Expression::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setString( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Expression::Builder::initString(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::STRING); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Expression::Builder::adoptString( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::STRING); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Expression::Builder::disownString() { + KJ_IREQUIRE((which() == Expression::STRING), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isRelativeName() const { + return which() == Expression::RELATIVE_NAME; +} +inline bool Expression::Builder::isRelativeName() { + return which() == Expression::RELATIVE_NAME; +} +inline bool Expression::Reader::hasRelativeName() const { + if (which() != Expression::RELATIVE_NAME) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasRelativeName() { + if (which() != Expression::RELATIVE_NAME) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Reader::getRelativeName() const { + KJ_IREQUIRE((which() == Expression::RELATIVE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::getRelativeName() { + KJ_IREQUIRE((which() == Expression::RELATIVE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setRelativeName( ::capnp::compiler::LocatedText::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::RELATIVE_NAME); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::initRelativeName() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::RELATIVE_NAME); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::adoptRelativeName( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::RELATIVE_NAME); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Builder::disownRelativeName() { + KJ_IREQUIRE((which() == Expression::RELATIVE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isList() const { + return which() == Expression::LIST; +} +inline bool Expression::Builder::isList() { + return which() == Expression::LIST; +} +inline bool Expression::Reader::hasList() const { + if (which() != Expression::LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasList() { + if (which() != Expression::LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Reader Expression::Reader::getList() const { + KJ_IREQUIRE((which() == Expression::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Builder Expression::Builder::getList() { + KJ_IREQUIRE((which() == Expression::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setList( ::capnp::List< ::capnp::compiler::Expression>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Builder Expression::Builder::initList(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::LIST); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Expression::Builder::adoptList( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>> Expression::Builder::disownList() { + KJ_IREQUIRE((which() == Expression::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isTuple() const { + return which() == Expression::TUPLE; +} +inline bool Expression::Builder::isTuple() { + return which() == Expression::TUPLE; +} +inline bool Expression::Reader::hasTuple() const { + if (which() != Expression::TUPLE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasTuple() { + if (which() != Expression::TUPLE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Reader Expression::Reader::getTuple() const { + KJ_IREQUIRE((which() == Expression::TUPLE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder Expression::Builder::getTuple() { + KJ_IREQUIRE((which() == Expression::TUPLE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setTuple( ::capnp::List< ::capnp::compiler::Expression::Param>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::TUPLE); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder Expression::Builder::initTuple(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::TUPLE); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Expression::Builder::adoptTuple( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::TUPLE); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>> Expression::Builder::disownTuple() { + KJ_IREQUIRE((which() == Expression::TUPLE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Expression::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Expression::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Expression::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Expression::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline void Expression::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Reader::isBinary() const { + return which() == Expression::BINARY; +} +inline bool Expression::Builder::isBinary() { + return which() == Expression::BINARY; +} +inline bool Expression::Reader::hasBinary() const { + if (which() != Expression::BINARY) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasBinary() { + if (which() != Expression::BINARY) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Data::Reader Expression::Reader::getBinary() const { + KJ_IREQUIRE((which() == Expression::BINARY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Data::Builder Expression::Builder::getBinary() { + KJ_IREQUIRE((which() == Expression::BINARY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setBinary( ::capnp::Data::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::BINARY); + ::capnp::_::PointerHelpers< ::capnp::Data>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Data::Builder Expression::Builder::initBinary(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::BINARY); + return ::capnp::_::PointerHelpers< ::capnp::Data>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Expression::Builder::adoptBinary( + ::capnp::Orphan< ::capnp::Data>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::BINARY); + ::capnp::_::PointerHelpers< ::capnp::Data>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Data> Expression::Builder::disownBinary() { + KJ_IREQUIRE((which() == Expression::BINARY), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isApplication() const { + return which() == Expression::APPLICATION; +} +inline bool Expression::Builder::isApplication() { + return which() == Expression::APPLICATION; +} +inline typename Expression::Application::Reader Expression::Reader::getApplication() const { + KJ_IREQUIRE((which() == Expression::APPLICATION), + "Must check which() before get()ing a union member."); + return typename Expression::Application::Reader(_reader); +} +inline typename Expression::Application::Builder Expression::Builder::getApplication() { + KJ_IREQUIRE((which() == Expression::APPLICATION), + "Must check which() before get()ing a union member."); + return typename Expression::Application::Builder(_builder); +} +inline typename Expression::Application::Builder Expression::Builder::initApplication() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::APPLICATION); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<1>() * ::capnp::POINTERS).clear(); + return typename Expression::Application::Builder(_builder); +} +inline bool Expression::Reader::isMember() const { + return which() == Expression::MEMBER; +} +inline bool Expression::Builder::isMember() { + return which() == Expression::MEMBER; +} +inline typename Expression::Member::Reader Expression::Reader::getMember() const { + KJ_IREQUIRE((which() == Expression::MEMBER), + "Must check which() before get()ing a union member."); + return typename Expression::Member::Reader(_reader); +} +inline typename Expression::Member::Builder Expression::Builder::getMember() { + KJ_IREQUIRE((which() == Expression::MEMBER), + "Must check which() before get()ing a union member."); + return typename Expression::Member::Builder(_builder); +} +inline typename Expression::Member::Builder Expression::Builder::initMember() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::MEMBER); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<1>() * ::capnp::POINTERS).clear(); + return typename Expression::Member::Builder(_builder); +} +inline bool Expression::Reader::isAbsoluteName() const { + return which() == Expression::ABSOLUTE_NAME; +} +inline bool Expression::Builder::isAbsoluteName() { + return which() == Expression::ABSOLUTE_NAME; +} +inline bool Expression::Reader::hasAbsoluteName() const { + if (which() != Expression::ABSOLUTE_NAME) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasAbsoluteName() { + if (which() != Expression::ABSOLUTE_NAME) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Reader::getAbsoluteName() const { + KJ_IREQUIRE((which() == Expression::ABSOLUTE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::getAbsoluteName() { + KJ_IREQUIRE((which() == Expression::ABSOLUTE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setAbsoluteName( ::capnp::compiler::LocatedText::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::ABSOLUTE_NAME); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::initAbsoluteName() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::ABSOLUTE_NAME); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::adoptAbsoluteName( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::ABSOLUTE_NAME); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Builder::disownAbsoluteName() { + KJ_IREQUIRE((which() == Expression::ABSOLUTE_NAME), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isImport() const { + return which() == Expression::IMPORT; +} +inline bool Expression::Builder::isImport() { + return which() == Expression::IMPORT; +} +inline bool Expression::Reader::hasImport() const { + if (which() != Expression::IMPORT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasImport() { + if (which() != Expression::IMPORT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Reader::getImport() const { + KJ_IREQUIRE((which() == Expression::IMPORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::getImport() { + KJ_IREQUIRE((which() == Expression::IMPORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setImport( ::capnp::compiler::LocatedText::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::IMPORT); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::initImport() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::IMPORT); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::adoptImport( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::IMPORT); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Builder::disownImport() { + KJ_IREQUIRE((which() == Expression::IMPORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Reader::isEmbed() const { + return which() == Expression::EMBED; +} +inline bool Expression::Builder::isEmbed() { + return which() == Expression::EMBED; +} +inline bool Expression::Reader::hasEmbed() const { + if (which() != Expression::EMBED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Builder::hasEmbed() { + if (which() != Expression::EMBED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Reader::getEmbed() const { + KJ_IREQUIRE((which() == Expression::EMBED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::getEmbed() { + KJ_IREQUIRE((which() == Expression::EMBED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::setEmbed( ::capnp::compiler::LocatedText::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::EMBED); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Builder::initEmbed() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::EMBED); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Builder::adoptEmbed( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::EMBED); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Builder::disownEmbed() { + KJ_IREQUIRE((which() == Expression::EMBED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::compiler::Expression::Param::Which Expression::Param::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Expression::Param::Which Expression::Param::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Expression::Param::Reader::isUnnamed() const { + return which() == Expression::Param::UNNAMED; +} +inline bool Expression::Param::Builder::isUnnamed() { + return which() == Expression::Param::UNNAMED; +} +inline ::capnp::Void Expression::Param::Reader::getUnnamed() const { + KJ_IREQUIRE((which() == Expression::Param::UNNAMED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Expression::Param::Builder::getUnnamed() { + KJ_IREQUIRE((which() == Expression::Param::UNNAMED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Expression::Param::Builder::setUnnamed( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::Param::UNNAMED); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Expression::Param::Reader::isNamed() const { + return which() == Expression::Param::NAMED; +} +inline bool Expression::Param::Builder::isNamed() { + return which() == Expression::Param::NAMED; +} +inline bool Expression::Param::Reader::hasNamed() const { + if (which() != Expression::Param::NAMED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Param::Builder::hasNamed() { + if (which() != Expression::Param::NAMED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Param::Reader::getNamed() const { + KJ_IREQUIRE((which() == Expression::Param::NAMED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Param::Builder::getNamed() { + KJ_IREQUIRE((which() == Expression::Param::NAMED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Param::Builder::setNamed( ::capnp::compiler::LocatedText::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::Param::NAMED); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Param::Builder::initNamed() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::Param::NAMED); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Param::Builder::adoptNamed( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Expression::Param::NAMED); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Param::Builder::disownNamed() { + KJ_IREQUIRE((which() == Expression::Param::NAMED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Param::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Param::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Expression::Param::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Expression::Param::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Expression::Param::Pipeline::getValue() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Expression::Param::Builder::setValue( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Expression::Param::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Expression::Param::Builder::adoptValue( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Expression::Param::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Expression::Application::Reader::hasFunction() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Application::Builder::hasFunction() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Expression::Application::Reader::getFunction() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Expression::Application::Builder::getFunction() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Expression::Application::Pipeline::getFunction() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Expression::Application::Builder::setFunction( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Expression::Application::Builder::initFunction() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Application::Builder::adoptFunction( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Expression::Application::Builder::disownFunction() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Application::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Application::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Reader Expression::Application::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder Expression::Application::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Expression::Application::Builder::setParams( ::capnp::List< ::capnp::compiler::Expression::Param>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Expression::Param>::Builder Expression::Application::Builder::initParams(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Expression::Application::Builder::adoptParams( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression::Param>> Expression::Application::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression::Param>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Expression::Member::Reader::hasParent() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Member::Builder::hasParent() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Expression::Member::Reader::getParent() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Expression::Member::Builder::getParent() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Expression::Member::Pipeline::getParent() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Expression::Member::Builder::setParent( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Expression::Member::Builder::initParent() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Expression::Member::Builder::adoptParent( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Expression::Member::Builder::disownParent() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Expression::Member::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Expression::Member::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Expression::Member::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Member::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::LocatedText::Pipeline Expression::Member::Pipeline::getName() { + return ::capnp::compiler::LocatedText::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Expression::Member::Builder::setName( ::capnp::compiler::LocatedText::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Expression::Member::Builder::initName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Expression::Member::Builder::adoptName( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Expression::Member::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::capnp::compiler::Declaration::Which Declaration::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::Which Declaration::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Declaration::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Declaration::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::LocatedText::Pipeline Declaration::Pipeline::getName() { + return ::capnp::compiler::LocatedText::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Declaration::Builder::setName( ::capnp::compiler::LocatedText::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Declaration::Builder::initName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::adoptName( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Declaration::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline typename Declaration::Id::Reader Declaration::Reader::getId() const { + return typename Declaration::Id::Reader(_reader); +} +inline typename Declaration::Id::Builder Declaration::Builder::getId() { + return typename Declaration::Id::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Declaration::Id::Pipeline Declaration::Pipeline::getId() { + return typename Declaration::Id::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Declaration::Id::Builder Declaration::Builder::initId() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<1>() * ::capnp::POINTERS).clear(); + return typename Declaration::Id::Builder(_builder); +} +inline bool Declaration::Reader::hasNestedDecls() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasNestedDecls() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Declaration>::Reader Declaration::Reader::getNestedDecls() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Declaration>::Builder Declaration::Builder::getNestedDecls() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setNestedDecls( ::capnp::List< ::capnp::compiler::Declaration>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Declaration>::Builder Declaration::Builder::initNestedDecls(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), size); +} +inline void Declaration::Builder::adoptNestedDecls( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration>> Declaration::Builder::disownNestedDecls() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration>>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader Declaration::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder Declaration::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setAnnotations( ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder Declaration::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Declaration::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>> Declaration::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Declaration::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Declaration::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::hasDocComment() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasDocComment() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Declaration::Reader::getDocComment() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Declaration::Builder::getDocComment() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setDocComment( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Declaration::Builder::initDocComment(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), size); +} +inline void Declaration::Builder::adoptDocComment( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Declaration::Builder::disownDocComment() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Reader::isFile() const { + return which() == Declaration::FILE; +} +inline bool Declaration::Builder::isFile() { + return which() == Declaration::FILE; +} +inline ::capnp::Void Declaration::Reader::getFile() const { + KJ_IREQUIRE((which() == Declaration::FILE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getFile() { + KJ_IREQUIRE((which() == Declaration::FILE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setFile( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::FILE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isUsing() const { + return which() == Declaration::USING; +} +inline bool Declaration::Builder::isUsing() { + return which() == Declaration::USING; +} +inline typename Declaration::Using::Reader Declaration::Reader::getUsing() const { + KJ_IREQUIRE((which() == Declaration::USING), + "Must check which() before get()ing a union member."); + return typename Declaration::Using::Reader(_reader); +} +inline typename Declaration::Using::Builder Declaration::Builder::getUsing() { + KJ_IREQUIRE((which() == Declaration::USING), + "Must check which() before get()ing a union member."); + return typename Declaration::Using::Builder(_builder); +} +inline typename Declaration::Using::Builder Declaration::Builder::initUsing() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::USING); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + return typename Declaration::Using::Builder(_builder); +} +inline bool Declaration::Reader::isConst() const { + return which() == Declaration::CONST; +} +inline bool Declaration::Builder::isConst() { + return which() == Declaration::CONST; +} +inline typename Declaration::Const::Reader Declaration::Reader::getConst() const { + KJ_IREQUIRE((which() == Declaration::CONST), + "Must check which() before get()ing a union member."); + return typename Declaration::Const::Reader(_reader); +} +inline typename Declaration::Const::Builder Declaration::Builder::getConst() { + KJ_IREQUIRE((which() == Declaration::CONST), + "Must check which() before get()ing a union member."); + return typename Declaration::Const::Builder(_builder); +} +inline typename Declaration::Const::Builder Declaration::Builder::initConst() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::CONST); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<6>() * ::capnp::POINTERS).clear(); + return typename Declaration::Const::Builder(_builder); +} +inline bool Declaration::Reader::isEnum() const { + return which() == Declaration::ENUM; +} +inline bool Declaration::Builder::isEnum() { + return which() == Declaration::ENUM; +} +inline ::capnp::Void Declaration::Reader::getEnum() const { + KJ_IREQUIRE((which() == Declaration::ENUM), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getEnum() { + KJ_IREQUIRE((which() == Declaration::ENUM), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setEnum( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::ENUM); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isEnumerant() const { + return which() == Declaration::ENUMERANT; +} +inline bool Declaration::Builder::isEnumerant() { + return which() == Declaration::ENUMERANT; +} +inline ::capnp::Void Declaration::Reader::getEnumerant() const { + KJ_IREQUIRE((which() == Declaration::ENUMERANT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getEnumerant() { + KJ_IREQUIRE((which() == Declaration::ENUMERANT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setEnumerant( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::ENUMERANT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isStruct() const { + return which() == Declaration::STRUCT; +} +inline bool Declaration::Builder::isStruct() { + return which() == Declaration::STRUCT; +} +inline ::capnp::Void Declaration::Reader::getStruct() const { + KJ_IREQUIRE((which() == Declaration::STRUCT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getStruct() { + KJ_IREQUIRE((which() == Declaration::STRUCT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setStruct( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::STRUCT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isField() const { + return which() == Declaration::FIELD; +} +inline bool Declaration::Builder::isField() { + return which() == Declaration::FIELD; +} +inline typename Declaration::Field::Reader Declaration::Reader::getField() const { + KJ_IREQUIRE((which() == Declaration::FIELD), + "Must check which() before get()ing a union member."); + return typename Declaration::Field::Reader(_reader); +} +inline typename Declaration::Field::Builder Declaration::Builder::getField() { + KJ_IREQUIRE((which() == Declaration::FIELD), + "Must check which() before get()ing a union member."); + return typename Declaration::Field::Builder(_builder); +} +inline typename Declaration::Field::Builder Declaration::Builder::initField() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::FIELD); + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<6>() * ::capnp::POINTERS).clear(); + return typename Declaration::Field::Builder(_builder); +} +inline bool Declaration::Reader::isUnion() const { + return which() == Declaration::UNION; +} +inline bool Declaration::Builder::isUnion() { + return which() == Declaration::UNION; +} +inline ::capnp::Void Declaration::Reader::getUnion() const { + KJ_IREQUIRE((which() == Declaration::UNION), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getUnion() { + KJ_IREQUIRE((which() == Declaration::UNION), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setUnion( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::UNION); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isGroup() const { + return which() == Declaration::GROUP; +} +inline bool Declaration::Builder::isGroup() { + return which() == Declaration::GROUP; +} +inline ::capnp::Void Declaration::Reader::getGroup() const { + KJ_IREQUIRE((which() == Declaration::GROUP), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getGroup() { + KJ_IREQUIRE((which() == Declaration::GROUP), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setGroup( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::GROUP); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isInterface() const { + return which() == Declaration::INTERFACE; +} +inline bool Declaration::Builder::isInterface() { + return which() == Declaration::INTERFACE; +} +inline typename Declaration::Interface::Reader Declaration::Reader::getInterface() const { + KJ_IREQUIRE((which() == Declaration::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Declaration::Interface::Reader(_reader); +} +inline typename Declaration::Interface::Builder Declaration::Builder::getInterface() { + KJ_IREQUIRE((which() == Declaration::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Declaration::Interface::Builder(_builder); +} +inline typename Declaration::Interface::Builder Declaration::Builder::initInterface() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::INTERFACE); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + return typename Declaration::Interface::Builder(_builder); +} +inline bool Declaration::Reader::isMethod() const { + return which() == Declaration::METHOD; +} +inline bool Declaration::Builder::isMethod() { + return which() == Declaration::METHOD; +} +inline typename Declaration::Method::Reader Declaration::Reader::getMethod() const { + KJ_IREQUIRE((which() == Declaration::METHOD), + "Must check which() before get()ing a union member."); + return typename Declaration::Method::Reader(_reader); +} +inline typename Declaration::Method::Builder Declaration::Builder::getMethod() { + KJ_IREQUIRE((which() == Declaration::METHOD), + "Must check which() before get()ing a union member."); + return typename Declaration::Method::Builder(_builder); +} +inline typename Declaration::Method::Builder Declaration::Builder::initMethod() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::METHOD); + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<6>() * ::capnp::POINTERS).clear(); + return typename Declaration::Method::Builder(_builder); +} +inline bool Declaration::Reader::isAnnotation() const { + return which() == Declaration::ANNOTATION; +} +inline bool Declaration::Builder::isAnnotation() { + return which() == Declaration::ANNOTATION; +} +inline typename Declaration::Annotation::Reader Declaration::Reader::getAnnotation() const { + KJ_IREQUIRE((which() == Declaration::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Declaration::Annotation::Reader(_reader); +} +inline typename Declaration::Annotation::Builder Declaration::Builder::getAnnotation() { + KJ_IREQUIRE((which() == Declaration::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Declaration::Annotation::Builder(_builder); +} +inline typename Declaration::Annotation::Builder Declaration::Builder::initAnnotation() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::ANNOTATION); + _builder.setDataField(::capnp::bounded<96>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<97>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<98>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<99>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<100>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<101>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<102>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<103>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<104>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<105>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<106>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<107>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<5>() * ::capnp::POINTERS).clear(); + return typename Declaration::Annotation::Builder(_builder); +} +inline bool Declaration::Reader::isNakedId() const { + return which() == Declaration::NAKED_ID; +} +inline bool Declaration::Builder::isNakedId() { + return which() == Declaration::NAKED_ID; +} +inline bool Declaration::Reader::hasNakedId() const { + if (which() != Declaration::NAKED_ID) return false; + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasNakedId() { + if (which() != Declaration::NAKED_ID) return false; + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedInteger::Reader Declaration::Reader::getNakedId() const { + KJ_IREQUIRE((which() == Declaration::NAKED_ID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Builder::getNakedId() { + KJ_IREQUIRE((which() == Declaration::NAKED_ID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setNakedId( ::capnp::compiler::LocatedInteger::Reader value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ID); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Builder::initNakedId() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ID); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::adoptNakedId( + ::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ID); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> Declaration::Builder::disownNakedId() { + KJ_IREQUIRE((which() == Declaration::NAKED_ID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Reader::isNakedAnnotation() const { + return which() == Declaration::NAKED_ANNOTATION; +} +inline bool Declaration::Builder::isNakedAnnotation() { + return which() == Declaration::NAKED_ANNOTATION; +} +inline bool Declaration::Reader::hasNakedAnnotation() const { + if (which() != Declaration::NAKED_ANNOTATION) return false; + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasNakedAnnotation() { + if (which() != Declaration::NAKED_ANNOTATION) return false; + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Declaration::AnnotationApplication::Reader Declaration::Reader::getNakedAnnotation() const { + KJ_IREQUIRE((which() == Declaration::NAKED_ANNOTATION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Declaration::AnnotationApplication::Builder Declaration::Builder::getNakedAnnotation() { + KJ_IREQUIRE((which() == Declaration::NAKED_ANNOTATION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setNakedAnnotation( ::capnp::compiler::Declaration::AnnotationApplication::Reader value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ANNOTATION); + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Declaration::AnnotationApplication::Builder Declaration::Builder::initNakedAnnotation() { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ANNOTATION); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::adoptNakedAnnotation( + ::capnp::Orphan< ::capnp::compiler::Declaration::AnnotationApplication>&& value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::NAKED_ANNOTATION); + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Declaration::AnnotationApplication> Declaration::Builder::disownNakedAnnotation() { + KJ_IREQUIRE((which() == Declaration::NAKED_ANNOTATION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::AnnotationApplication>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Reader::isBuiltinVoid() const { + return which() == Declaration::BUILTIN_VOID; +} +inline bool Declaration::Builder::isBuiltinVoid() { + return which() == Declaration::BUILTIN_VOID; +} +inline ::capnp::Void Declaration::Reader::getBuiltinVoid() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_VOID), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinVoid() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_VOID), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinVoid( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_VOID); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinBool() const { + return which() == Declaration::BUILTIN_BOOL; +} +inline bool Declaration::Builder::isBuiltinBool() { + return which() == Declaration::BUILTIN_BOOL; +} +inline ::capnp::Void Declaration::Reader::getBuiltinBool() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_BOOL), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinBool() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_BOOL), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinBool( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_BOOL); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinInt8() const { + return which() == Declaration::BUILTIN_INT8; +} +inline bool Declaration::Builder::isBuiltinInt8() { + return which() == Declaration::BUILTIN_INT8; +} +inline ::capnp::Void Declaration::Reader::getBuiltinInt8() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinInt8() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinInt8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_INT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinInt16() const { + return which() == Declaration::BUILTIN_INT16; +} +inline bool Declaration::Builder::isBuiltinInt16() { + return which() == Declaration::BUILTIN_INT16; +} +inline ::capnp::Void Declaration::Reader::getBuiltinInt16() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinInt16() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinInt16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_INT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinInt32() const { + return which() == Declaration::BUILTIN_INT32; +} +inline bool Declaration::Builder::isBuiltinInt32() { + return which() == Declaration::BUILTIN_INT32; +} +inline ::capnp::Void Declaration::Reader::getBuiltinInt32() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinInt32() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinInt32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_INT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinInt64() const { + return which() == Declaration::BUILTIN_INT64; +} +inline bool Declaration::Builder::isBuiltinInt64() { + return which() == Declaration::BUILTIN_INT64; +} +inline ::capnp::Void Declaration::Reader::getBuiltinInt64() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinInt64() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinInt64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_INT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinUInt8() const { + return which() == Declaration::BUILTIN_U_INT8; +} +inline bool Declaration::Builder::isBuiltinUInt8() { + return which() == Declaration::BUILTIN_U_INT8; +} +inline ::capnp::Void Declaration::Reader::getBuiltinUInt8() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinUInt8() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinUInt8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_U_INT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinUInt16() const { + return which() == Declaration::BUILTIN_U_INT16; +} +inline bool Declaration::Builder::isBuiltinUInt16() { + return which() == Declaration::BUILTIN_U_INT16; +} +inline ::capnp::Void Declaration::Reader::getBuiltinUInt16() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinUInt16() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinUInt16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_U_INT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinUInt32() const { + return which() == Declaration::BUILTIN_U_INT32; +} +inline bool Declaration::Builder::isBuiltinUInt32() { + return which() == Declaration::BUILTIN_U_INT32; +} +inline ::capnp::Void Declaration::Reader::getBuiltinUInt32() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinUInt32() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinUInt32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_U_INT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinUInt64() const { + return which() == Declaration::BUILTIN_U_INT64; +} +inline bool Declaration::Builder::isBuiltinUInt64() { + return which() == Declaration::BUILTIN_U_INT64; +} +inline ::capnp::Void Declaration::Reader::getBuiltinUInt64() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinUInt64() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_U_INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinUInt64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_U_INT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinFloat32() const { + return which() == Declaration::BUILTIN_FLOAT32; +} +inline bool Declaration::Builder::isBuiltinFloat32() { + return which() == Declaration::BUILTIN_FLOAT32; +} +inline ::capnp::Void Declaration::Reader::getBuiltinFloat32() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_FLOAT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinFloat32() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_FLOAT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinFloat32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_FLOAT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinFloat64() const { + return which() == Declaration::BUILTIN_FLOAT64; +} +inline bool Declaration::Builder::isBuiltinFloat64() { + return which() == Declaration::BUILTIN_FLOAT64; +} +inline ::capnp::Void Declaration::Reader::getBuiltinFloat64() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_FLOAT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinFloat64() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_FLOAT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinFloat64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_FLOAT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinText() const { + return which() == Declaration::BUILTIN_TEXT; +} +inline bool Declaration::Builder::isBuiltinText() { + return which() == Declaration::BUILTIN_TEXT; +} +inline ::capnp::Void Declaration::Reader::getBuiltinText() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_TEXT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinText() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_TEXT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinText( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_TEXT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinData() const { + return which() == Declaration::BUILTIN_DATA; +} +inline bool Declaration::Builder::isBuiltinData() { + return which() == Declaration::BUILTIN_DATA; +} +inline ::capnp::Void Declaration::Reader::getBuiltinData() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_DATA), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinData() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_DATA), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinData( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_DATA); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinList() const { + return which() == Declaration::BUILTIN_LIST; +} +inline bool Declaration::Builder::isBuiltinList() { + return which() == Declaration::BUILTIN_LIST; +} +inline ::capnp::Void Declaration::Reader::getBuiltinList() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_LIST), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinList() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_LIST), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinList( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_LIST); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinObject() const { + return which() == Declaration::BUILTIN_OBJECT; +} +inline bool Declaration::Builder::isBuiltinObject() { + return which() == Declaration::BUILTIN_OBJECT; +} +inline ::capnp::Void Declaration::Reader::getBuiltinObject() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_OBJECT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinObject() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_OBJECT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinObject( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_OBJECT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinAnyPointer() const { + return which() == Declaration::BUILTIN_ANY_POINTER; +} +inline bool Declaration::Builder::isBuiltinAnyPointer() { + return which() == Declaration::BUILTIN_ANY_POINTER; +} +inline ::capnp::Void Declaration::Reader::getBuiltinAnyPointer() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_POINTER), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinAnyPointer() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_POINTER), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinAnyPointer( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_ANY_POINTER); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::hasParameters() const { + return !_reader.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Builder::hasParameters() { + return !_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Reader Declaration::Reader::getParameters() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::get(_reader.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Builder Declaration::Builder::getParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::get(_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS)); +} +inline void Declaration::Builder::setParameters( ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::set(_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>::Builder Declaration::Builder::initParameters(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::init(_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS), size); +} +inline void Declaration::Builder::adoptParameters( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::adopt(_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>> Declaration::Builder::disownParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::BrandParameter>>::disown(_builder.getPointerField( + ::capnp::bounded<7>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Reader::isBuiltinAnyStruct() const { + return which() == Declaration::BUILTIN_ANY_STRUCT; +} +inline bool Declaration::Builder::isBuiltinAnyStruct() { + return which() == Declaration::BUILTIN_ANY_STRUCT; +} +inline ::capnp::Void Declaration::Reader::getBuiltinAnyStruct() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_STRUCT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinAnyStruct() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_STRUCT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinAnyStruct( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_ANY_STRUCT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinAnyList() const { + return which() == Declaration::BUILTIN_ANY_LIST; +} +inline bool Declaration::Builder::isBuiltinAnyList() { + return which() == Declaration::BUILTIN_ANY_LIST; +} +inline ::capnp::Void Declaration::Reader::getBuiltinAnyList() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_LIST), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinAnyList() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_ANY_LIST), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinAnyList( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_ANY_LIST); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Reader::isBuiltinCapability() const { + return which() == Declaration::BUILTIN_CAPABILITY; +} +inline bool Declaration::Builder::isBuiltinCapability() { + return which() == Declaration::BUILTIN_CAPABILITY; +} +inline ::capnp::Void Declaration::Reader::getBuiltinCapability() const { + KJ_IREQUIRE((which() == Declaration::BUILTIN_CAPABILITY), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Builder::getBuiltinCapability() { + KJ_IREQUIRE((which() == Declaration::BUILTIN_CAPABILITY), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Builder::setBuiltinCapability( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, Declaration::BUILTIN_CAPABILITY); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::BrandParameter::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::BrandParameter::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Declaration::BrandParameter::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Declaration::BrandParameter::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::BrandParameter::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Declaration::BrandParameter::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Declaration::BrandParameter::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Declaration::BrandParameter::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Declaration::BrandParameter::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::BrandParameter::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::BrandParameter::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Declaration::BrandParameter::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::BrandParameter::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Declaration::BrandParameter::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::AnnotationApplication::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::AnnotationApplication::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::AnnotationApplication::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::AnnotationApplication::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::AnnotationApplication::Pipeline::getName() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Declaration::AnnotationApplication::Builder::setName( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::AnnotationApplication::Builder::initName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::AnnotationApplication::Builder::adoptName( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::AnnotationApplication::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline typename Declaration::AnnotationApplication::Value::Reader Declaration::AnnotationApplication::Reader::getValue() const { + return typename Declaration::AnnotationApplication::Value::Reader(_reader); +} +inline typename Declaration::AnnotationApplication::Value::Builder Declaration::AnnotationApplication::Builder::getValue() { + return typename Declaration::AnnotationApplication::Value::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Declaration::AnnotationApplication::Value::Pipeline Declaration::AnnotationApplication::Pipeline::getValue() { + return typename Declaration::AnnotationApplication::Value::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Declaration::AnnotationApplication::Value::Builder Declaration::AnnotationApplication::Builder::initValue() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<1>() * ::capnp::POINTERS).clear(); + return typename Declaration::AnnotationApplication::Value::Builder(_builder); +} +inline ::capnp::compiler::Declaration::AnnotationApplication::Value::Which Declaration::AnnotationApplication::Value::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::AnnotationApplication::Value::Which Declaration::AnnotationApplication::Value::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::AnnotationApplication::Value::Reader::isNone() const { + return which() == Declaration::AnnotationApplication::Value::NONE; +} +inline bool Declaration::AnnotationApplication::Value::Builder::isNone() { + return which() == Declaration::AnnotationApplication::Value::NONE; +} +inline ::capnp::Void Declaration::AnnotationApplication::Value::Reader::getNone() const { + KJ_IREQUIRE((which() == Declaration::AnnotationApplication::Value::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::AnnotationApplication::Value::Builder::getNone() { + KJ_IREQUIRE((which() == Declaration::AnnotationApplication::Value::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::AnnotationApplication::Value::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::AnnotationApplication::Value::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::AnnotationApplication::Value::Reader::isExpression() const { + return which() == Declaration::AnnotationApplication::Value::EXPRESSION; +} +inline bool Declaration::AnnotationApplication::Value::Builder::isExpression() { + return which() == Declaration::AnnotationApplication::Value::EXPRESSION; +} +inline bool Declaration::AnnotationApplication::Value::Reader::hasExpression() const { + if (which() != Declaration::AnnotationApplication::Value::EXPRESSION) return false; + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::AnnotationApplication::Value::Builder::hasExpression() { + if (which() != Declaration::AnnotationApplication::Value::EXPRESSION) return false; + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::AnnotationApplication::Value::Reader::getExpression() const { + KJ_IREQUIRE((which() == Declaration::AnnotationApplication::Value::EXPRESSION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::AnnotationApplication::Value::Builder::getExpression() { + KJ_IREQUIRE((which() == Declaration::AnnotationApplication::Value::EXPRESSION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::AnnotationApplication::Value::Builder::setExpression( ::capnp::compiler::Expression::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::AnnotationApplication::Value::EXPRESSION); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::AnnotationApplication::Value::Builder::initExpression() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::AnnotationApplication::Value::EXPRESSION); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::AnnotationApplication::Value::Builder::adoptExpression( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::AnnotationApplication::Value::EXPRESSION); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::AnnotationApplication::Value::Builder::disownExpression() { + KJ_IREQUIRE((which() == Declaration::AnnotationApplication::Value::EXPRESSION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::capnp::compiler::Declaration::ParamList::Which Declaration::ParamList::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::ParamList::Which Declaration::ParamList::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::ParamList::Reader::isNamedList() const { + return which() == Declaration::ParamList::NAMED_LIST; +} +inline bool Declaration::ParamList::Builder::isNamedList() { + return which() == Declaration::ParamList::NAMED_LIST; +} +inline bool Declaration::ParamList::Reader::hasNamedList() const { + if (which() != Declaration::ParamList::NAMED_LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::ParamList::Builder::hasNamedList() { + if (which() != Declaration::ParamList::NAMED_LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Reader Declaration::ParamList::Reader::getNamedList() const { + KJ_IREQUIRE((which() == Declaration::ParamList::NAMED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Builder Declaration::ParamList::Builder::getNamedList() { + KJ_IREQUIRE((which() == Declaration::ParamList::NAMED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::ParamList::Builder::setNamedList( ::capnp::List< ::capnp::compiler::Declaration::Param>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::NAMED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Declaration::Param>::Builder Declaration::ParamList::Builder::initNamedList(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::NAMED_LIST); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Declaration::ParamList::Builder::adoptNamedList( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::Param>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::NAMED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::Param>> Declaration::ParamList::Builder::disownNamedList() { + KJ_IREQUIRE((which() == Declaration::ParamList::NAMED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::Param>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Declaration::ParamList::Reader::isType() const { + return which() == Declaration::ParamList::TYPE; +} +inline bool Declaration::ParamList::Builder::isType() { + return which() == Declaration::ParamList::TYPE; +} +inline bool Declaration::ParamList::Reader::hasType() const { + if (which() != Declaration::ParamList::TYPE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::ParamList::Builder::hasType() { + if (which() != Declaration::ParamList::TYPE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::ParamList::Reader::getType() const { + KJ_IREQUIRE((which() == Declaration::ParamList::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::ParamList::Builder::getType() { + KJ_IREQUIRE((which() == Declaration::ParamList::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::ParamList::Builder::setType( ::capnp::compiler::Expression::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::TYPE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::ParamList::Builder::initType() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::TYPE); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::ParamList::Builder::adoptType( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::ParamList::TYPE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::ParamList::Builder::disownType() { + KJ_IREQUIRE((which() == Declaration::ParamList::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Declaration::ParamList::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::ParamList::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Declaration::ParamList::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Declaration::ParamList::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::ParamList::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Declaration::ParamList::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Param::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Param::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedText::Reader Declaration::Param::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedText::Builder Declaration::Param::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::LocatedText::Pipeline Declaration::Param::Pipeline::getName() { + return ::capnp::compiler::LocatedText::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Declaration::Param::Builder::setName( ::capnp::compiler::LocatedText::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedText::Builder Declaration::Param::Builder::initName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Declaration::Param::Builder::adoptName( + ::capnp::Orphan< ::capnp::compiler::LocatedText>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedText> Declaration::Param::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedText>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Param::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Param::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Param::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Param::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Param::Pipeline::getType() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Declaration::Param::Builder::setType( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Param::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::Param::Builder::adoptType( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Param::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Param::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Param::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader Declaration::Param::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder Declaration::Param::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Declaration::Param::Builder::setAnnotations( ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>::Builder Declaration::Param::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), size); +} +inline void Declaration::Param::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>> Declaration::Param::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Declaration::AnnotationApplication>>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline typename Declaration::Param::DefaultValue::Reader Declaration::Param::Reader::getDefaultValue() const { + return typename Declaration::Param::DefaultValue::Reader(_reader); +} +inline typename Declaration::Param::DefaultValue::Builder Declaration::Param::Builder::getDefaultValue() { + return typename Declaration::Param::DefaultValue::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Declaration::Param::DefaultValue::Pipeline Declaration::Param::Pipeline::getDefaultValue() { + return typename Declaration::Param::DefaultValue::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Declaration::Param::DefaultValue::Builder Declaration::Param::Builder::initDefaultValue() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Declaration::Param::DefaultValue::Builder(_builder); +} +inline ::uint32_t Declaration::Param::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::Param::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Declaration::Param::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Declaration::Param::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Declaration::Param::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Declaration::Param::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::compiler::Declaration::Param::DefaultValue::Which Declaration::Param::DefaultValue::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::Param::DefaultValue::Which Declaration::Param::DefaultValue::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Param::DefaultValue::Reader::isNone() const { + return which() == Declaration::Param::DefaultValue::NONE; +} +inline bool Declaration::Param::DefaultValue::Builder::isNone() { + return which() == Declaration::Param::DefaultValue::NONE; +} +inline ::capnp::Void Declaration::Param::DefaultValue::Reader::getNone() const { + KJ_IREQUIRE((which() == Declaration::Param::DefaultValue::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Param::DefaultValue::Builder::getNone() { + KJ_IREQUIRE((which() == Declaration::Param::DefaultValue::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Param::DefaultValue::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Param::DefaultValue::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Param::DefaultValue::Reader::isValue() const { + return which() == Declaration::Param::DefaultValue::VALUE; +} +inline bool Declaration::Param::DefaultValue::Builder::isValue() { + return which() == Declaration::Param::DefaultValue::VALUE; +} +inline bool Declaration::Param::DefaultValue::Reader::hasValue() const { + if (which() != Declaration::Param::DefaultValue::VALUE) return false; + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Param::DefaultValue::Builder::hasValue() { + if (which() != Declaration::Param::DefaultValue::VALUE) return false; + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Param::DefaultValue::Reader::getValue() const { + KJ_IREQUIRE((which() == Declaration::Param::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Param::DefaultValue::Builder::getValue() { + KJ_IREQUIRE((which() == Declaration::Param::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Declaration::Param::DefaultValue::Builder::setValue( ::capnp::compiler::Expression::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Param::DefaultValue::VALUE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Param::DefaultValue::Builder::initValue() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Param::DefaultValue::VALUE); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Declaration::Param::DefaultValue::Builder::adoptValue( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Param::DefaultValue::VALUE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Param::DefaultValue::Builder::disownValue() { + KJ_IREQUIRE((which() == Declaration::Param::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline ::capnp::compiler::Declaration::Id::Which Declaration::Id::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::Id::Which Declaration::Id::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Id::Reader::isUnspecified() const { + return which() == Declaration::Id::UNSPECIFIED; +} +inline bool Declaration::Id::Builder::isUnspecified() { + return which() == Declaration::Id::UNSPECIFIED; +} +inline ::capnp::Void Declaration::Id::Reader::getUnspecified() const { + KJ_IREQUIRE((which() == Declaration::Id::UNSPECIFIED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Id::Builder::getUnspecified() { + KJ_IREQUIRE((which() == Declaration::Id::UNSPECIFIED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Id::Builder::setUnspecified( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::UNSPECIFIED); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Id::Reader::isUid() const { + return which() == Declaration::Id::UID; +} +inline bool Declaration::Id::Builder::isUid() { + return which() == Declaration::Id::UID; +} +inline bool Declaration::Id::Reader::hasUid() const { + if (which() != Declaration::Id::UID) return false; + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Id::Builder::hasUid() { + if (which() != Declaration::Id::UID) return false; + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedInteger::Reader Declaration::Id::Reader::getUid() const { + KJ_IREQUIRE((which() == Declaration::Id::UID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Id::Builder::getUid() { + KJ_IREQUIRE((which() == Declaration::Id::UID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::Id::Builder::setUid( ::capnp::compiler::LocatedInteger::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::UID); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Id::Builder::initUid() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::UID); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::Id::Builder::adoptUid( + ::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::UID); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> Declaration::Id::Builder::disownUid() { + KJ_IREQUIRE((which() == Declaration::Id::UID), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Id::Reader::isOrdinal() const { + return which() == Declaration::Id::ORDINAL; +} +inline bool Declaration::Id::Builder::isOrdinal() { + return which() == Declaration::Id::ORDINAL; +} +inline bool Declaration::Id::Reader::hasOrdinal() const { + if (which() != Declaration::Id::ORDINAL) return false; + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Id::Builder::hasOrdinal() { + if (which() != Declaration::Id::ORDINAL) return false; + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::LocatedInteger::Reader Declaration::Id::Reader::getOrdinal() const { + KJ_IREQUIRE((which() == Declaration::Id::ORDINAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Id::Builder::getOrdinal() { + KJ_IREQUIRE((which() == Declaration::Id::ORDINAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::Id::Builder::setOrdinal( ::capnp::compiler::LocatedInteger::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::ORDINAL); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::LocatedInteger::Builder Declaration::Id::Builder::initOrdinal() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::ORDINAL); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Declaration::Id::Builder::adoptOrdinal( + ::capnp::Orphan< ::capnp::compiler::LocatedInteger>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Declaration::Id::ORDINAL); + ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::LocatedInteger> Declaration::Id::Builder::disownOrdinal() { + KJ_IREQUIRE((which() == Declaration::Id::ORDINAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::LocatedInteger>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Using::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Using::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Using::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Using::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Using::Pipeline::getTarget() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(5)); +} +#endif // !CAPNP_LITE +inline void Declaration::Using::Builder::setTarget( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Using::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Using::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Using::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Const::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Const::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Const::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Const::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Const::Pipeline::getType() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(5)); +} +#endif // !CAPNP_LITE +inline void Declaration::Const::Builder::setType( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Const::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Const::Builder::adoptType( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Const::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Const::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Const::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Const::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Const::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Const::Pipeline::getValue() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(6)); +} +#endif // !CAPNP_LITE +inline void Declaration::Const::Builder::setValue( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Const::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline void Declaration::Const::Builder::adoptValue( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Const::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Field::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Field::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Field::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Field::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Field::Pipeline::getType() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(5)); +} +#endif // !CAPNP_LITE +inline void Declaration::Field::Builder::setType( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Field::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Field::Builder::adoptType( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Field::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline typename Declaration::Field::DefaultValue::Reader Declaration::Field::Reader::getDefaultValue() const { + return typename Declaration::Field::DefaultValue::Reader(_reader); +} +inline typename Declaration::Field::DefaultValue::Builder Declaration::Field::Builder::getDefaultValue() { + return typename Declaration::Field::DefaultValue::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Declaration::Field::DefaultValue::Pipeline Declaration::Field::Pipeline::getDefaultValue() { + return typename Declaration::Field::DefaultValue::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Declaration::Field::DefaultValue::Builder Declaration::Field::Builder::initDefaultValue() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<6>() * ::capnp::POINTERS).clear(); + return typename Declaration::Field::DefaultValue::Builder(_builder); +} +inline ::capnp::compiler::Declaration::Field::DefaultValue::Which Declaration::Field::DefaultValue::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::Field::DefaultValue::Which Declaration::Field::DefaultValue::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Field::DefaultValue::Reader::isNone() const { + return which() == Declaration::Field::DefaultValue::NONE; +} +inline bool Declaration::Field::DefaultValue::Builder::isNone() { + return which() == Declaration::Field::DefaultValue::NONE; +} +inline ::capnp::Void Declaration::Field::DefaultValue::Reader::getNone() const { + KJ_IREQUIRE((which() == Declaration::Field::DefaultValue::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Field::DefaultValue::Builder::getNone() { + KJ_IREQUIRE((which() == Declaration::Field::DefaultValue::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Field::DefaultValue::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Field::DefaultValue::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Field::DefaultValue::Reader::isValue() const { + return which() == Declaration::Field::DefaultValue::VALUE; +} +inline bool Declaration::Field::DefaultValue::Builder::isValue() { + return which() == Declaration::Field::DefaultValue::VALUE; +} +inline bool Declaration::Field::DefaultValue::Reader::hasValue() const { + if (which() != Declaration::Field::DefaultValue::VALUE) return false; + return !_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Field::DefaultValue::Builder::hasValue() { + if (which() != Declaration::Field::DefaultValue::VALUE) return false; + return !_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Field::DefaultValue::Reader::getValue() const { + KJ_IREQUIRE((which() == Declaration::Field::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Field::DefaultValue::Builder::getValue() { + KJ_IREQUIRE((which() == Declaration::Field::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline void Declaration::Field::DefaultValue::Builder::setValue( ::capnp::compiler::Expression::Reader value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Field::DefaultValue::VALUE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Field::DefaultValue::Builder::initValue() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Field::DefaultValue::VALUE); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline void Declaration::Field::DefaultValue::Builder::adoptValue( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Field::DefaultValue::VALUE); + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Field::DefaultValue::Builder::disownValue() { + KJ_IREQUIRE((which() == Declaration::Field::DefaultValue::VALUE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Interface::Reader::hasSuperclasses() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Interface::Builder::hasSuperclasses() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Reader Declaration::Interface::Reader::getSuperclasses() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Builder Declaration::Interface::Builder::getSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Interface::Builder::setSuperclasses( ::capnp::List< ::capnp::compiler::Expression>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Expression>::Builder Declaration::Interface::Builder::initSuperclasses(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), size); +} +inline void Declaration::Interface::Builder::adoptSuperclasses( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Expression>> Declaration::Interface::Builder::disownSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Expression>>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Method::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Method::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Declaration::ParamList::Reader Declaration::Method::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Declaration::ParamList::Builder Declaration::Method::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Declaration::ParamList::Pipeline Declaration::Method::Pipeline::getParams() { + return ::capnp::compiler::Declaration::ParamList::Pipeline(_typeless.getPointerField(5)); +} +#endif // !CAPNP_LITE +inline void Declaration::Method::Builder::setParams( ::capnp::compiler::Declaration::ParamList::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Declaration::ParamList::Builder Declaration::Method::Builder::initParams() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Method::Builder::adoptParams( + ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList> Declaration::Method::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline typename Declaration::Method::Results::Reader Declaration::Method::Reader::getResults() const { + return typename Declaration::Method::Results::Reader(_reader); +} +inline typename Declaration::Method::Results::Builder Declaration::Method::Builder::getResults() { + return typename Declaration::Method::Results::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Declaration::Method::Results::Pipeline Declaration::Method::Pipeline::getResults() { + return typename Declaration::Method::Results::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Declaration::Method::Results::Builder Declaration::Method::Builder::initResults() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<6>() * ::capnp::POINTERS).clear(); + return typename Declaration::Method::Results::Builder(_builder); +} +inline ::capnp::compiler::Declaration::Method::Results::Which Declaration::Method::Results::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Declaration::Method::Results::Which Declaration::Method::Results::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Method::Results::Reader::isNone() const { + return which() == Declaration::Method::Results::NONE; +} +inline bool Declaration::Method::Results::Builder::isNone() { + return which() == Declaration::Method::Results::NONE; +} +inline ::capnp::Void Declaration::Method::Results::Reader::getNone() const { + KJ_IREQUIRE((which() == Declaration::Method::Results::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Declaration::Method::Results::Builder::getNone() { + KJ_IREQUIRE((which() == Declaration::Method::Results::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Declaration::Method::Results::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Method::Results::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Method::Results::Reader::isExplicit() const { + return which() == Declaration::Method::Results::EXPLICIT; +} +inline bool Declaration::Method::Results::Builder::isExplicit() { + return which() == Declaration::Method::Results::EXPLICIT; +} +inline bool Declaration::Method::Results::Reader::hasExplicit() const { + if (which() != Declaration::Method::Results::EXPLICIT) return false; + return !_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Method::Results::Builder::hasExplicit() { + if (which() != Declaration::Method::Results::EXPLICIT) return false; + return !_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Declaration::ParamList::Reader Declaration::Method::Results::Reader::getExplicit() const { + KJ_IREQUIRE((which() == Declaration::Method::Results::EXPLICIT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::get(_reader.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Declaration::ParamList::Builder Declaration::Method::Results::Builder::getExplicit() { + KJ_IREQUIRE((which() == Declaration::Method::Results::EXPLICIT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::get(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline void Declaration::Method::Results::Builder::setExplicit( ::capnp::compiler::Declaration::ParamList::Reader value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Method::Results::EXPLICIT); + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::set(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Declaration::ParamList::Builder Declaration::Method::Results::Builder::initExplicit() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Method::Results::EXPLICIT); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::init(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} +inline void Declaration::Method::Results::Builder::adoptExplicit( + ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList>&& value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Declaration::Method::Results::EXPLICIT); + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::adopt(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Declaration::ParamList> Declaration::Method::Results::Builder::disownExplicit() { + KJ_IREQUIRE((which() == Declaration::Method::Results::EXPLICIT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration::ParamList>::disown(_builder.getPointerField( + ::capnp::bounded<6>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Annotation::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Declaration::Annotation::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Expression::Reader Declaration::Annotation::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Expression::Builder Declaration::Annotation::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Expression::Pipeline Declaration::Annotation::Pipeline::getType() { + return ::capnp::compiler::Expression::Pipeline(_typeless.getPointerField(5)); +} +#endif // !CAPNP_LITE +inline void Declaration::Annotation::Builder::setType( ::capnp::compiler::Expression::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Expression::Builder Declaration::Annotation::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Declaration::Annotation::Builder::adoptType( + ::capnp::Orphan< ::capnp::compiler::Expression>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Expression> Declaration::Annotation::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Expression>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Declaration::Annotation::Reader::getTargetsFile() const { + return _reader.getDataField( + ::capnp::bounded<96>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsFile() { + return _builder.getDataField( + ::capnp::bounded<96>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsFile(bool value) { + _builder.setDataField( + ::capnp::bounded<96>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsConst() const { + return _reader.getDataField( + ::capnp::bounded<97>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsConst() { + return _builder.getDataField( + ::capnp::bounded<97>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsConst(bool value) { + _builder.setDataField( + ::capnp::bounded<97>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsEnum() const { + return _reader.getDataField( + ::capnp::bounded<98>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsEnum() { + return _builder.getDataField( + ::capnp::bounded<98>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsEnum(bool value) { + _builder.setDataField( + ::capnp::bounded<98>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsEnumerant() const { + return _reader.getDataField( + ::capnp::bounded<99>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsEnumerant() { + return _builder.getDataField( + ::capnp::bounded<99>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsEnumerant(bool value) { + _builder.setDataField( + ::capnp::bounded<99>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsStruct() const { + return _reader.getDataField( + ::capnp::bounded<100>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsStruct() { + return _builder.getDataField( + ::capnp::bounded<100>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsStruct(bool value) { + _builder.setDataField( + ::capnp::bounded<100>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsField() const { + return _reader.getDataField( + ::capnp::bounded<101>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsField() { + return _builder.getDataField( + ::capnp::bounded<101>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsField(bool value) { + _builder.setDataField( + ::capnp::bounded<101>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsUnion() const { + return _reader.getDataField( + ::capnp::bounded<102>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsUnion() { + return _builder.getDataField( + ::capnp::bounded<102>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsUnion(bool value) { + _builder.setDataField( + ::capnp::bounded<102>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsGroup() const { + return _reader.getDataField( + ::capnp::bounded<103>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsGroup() { + return _builder.getDataField( + ::capnp::bounded<103>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsGroup(bool value) { + _builder.setDataField( + ::capnp::bounded<103>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsInterface() const { + return _reader.getDataField( + ::capnp::bounded<104>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsInterface() { + return _builder.getDataField( + ::capnp::bounded<104>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsInterface(bool value) { + _builder.setDataField( + ::capnp::bounded<104>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsMethod() const { + return _reader.getDataField( + ::capnp::bounded<105>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsMethod() { + return _builder.getDataField( + ::capnp::bounded<105>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsMethod(bool value) { + _builder.setDataField( + ::capnp::bounded<105>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsParam() const { + return _reader.getDataField( + ::capnp::bounded<106>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsParam() { + return _builder.getDataField( + ::capnp::bounded<106>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsParam(bool value) { + _builder.setDataField( + ::capnp::bounded<106>() * ::capnp::ELEMENTS, value); +} + +inline bool Declaration::Annotation::Reader::getTargetsAnnotation() const { + return _reader.getDataField( + ::capnp::bounded<107>() * ::capnp::ELEMENTS); +} + +inline bool Declaration::Annotation::Builder::getTargetsAnnotation() { + return _builder.getDataField( + ::capnp::bounded<107>() * ::capnp::ELEMENTS); +} +inline void Declaration::Annotation::Builder::setTargetsAnnotation(bool value) { + _builder.setDataField( + ::capnp::bounded<107>() * ::capnp::ELEMENTS, value); +} + +inline bool ParsedFile::Reader::hasRoot() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool ParsedFile::Builder::hasRoot() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::compiler::Declaration::Reader ParsedFile::Reader::getRoot() const { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::compiler::Declaration::Builder ParsedFile::Builder::getRoot() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::compiler::Declaration::Pipeline ParsedFile::Pipeline::getRoot() { + return ::capnp::compiler::Declaration::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void ParsedFile::Builder::setRoot( ::capnp::compiler::Declaration::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::compiler::Declaration::Builder ParsedFile::Builder::initRoot() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void ParsedFile::Builder::adoptRoot( + ::capnp::Orphan< ::capnp::compiler::Declaration>&& value) { + ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::compiler::Declaration> ParsedFile::Builder::disownRoot() { + return ::capnp::_::PointerHelpers< ::capnp::compiler::Declaration>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_c56be168dcbbc3c6_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,373 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "lexer.h" +#include "../message.h" +#include + +namespace capnp { +namespace compiler { +namespace { + +class TestFailingErrorReporter: public ErrorReporter { +public: + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + KJ_FAIL_EXPECT("Parse failed.", startByte, endByte, message); + } + + bool hadErrors() override { + // Not used by lexer. + return false; + } +}; + +template +kj::String doLex(kj::StringPtr constText) { + // Parse the given string into the given Cap'n Proto struct type using lex(), then stringify the + // result and return that string. Additionally, single quotes in the input are converted to + // double quotes, and double quotes in the output are converted to single quotes, to reduce the + // amount of escaping needed in the test strings. + // + // Comparing stringifications against golden strings is ugly and brittle. If we had a + // text-format parser we could use that. Except that said parser would probably be built on + // the very lexer being tested here, so... maybe this is the best we can reasonably do. + + kj::String text = heapString(constText); + for (char& c: text) { + // Make it easier to write input strings below. + if (c == '\'') c = '\"'; + } + MallocMessageBuilder message; + auto file = message.initRoot(); + TestFailingErrorReporter errorReporter; + EXPECT_TRUE(lex(text, file, errorReporter)); + kj::String result = kj::str(file); + for (char& c: result) { + // Make it easier to write golden strings below. + if (c == '\"') c = '\''; + } + return result; +} + +TEST(Lexer, Tokens) { + EXPECT_STREQ( + "(tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3), " + "(identifier = 'bar', startByte = 4, endByte = 7)" + "])", + doLex("foo bar").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3), " + "(identifier = 'bar', startByte = 15, endByte = 18)" + "])", + doLex("foo # comment\n bar").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(stringLiteral = 'foo ', startByte = 2, endByte = 11), " + "(integerLiteral = 123, startByte = 12, endByte = 15), " + "(floatLiteral = 2.75, startByte = 16, endByte = 20), " + "(floatLiteral = 60000, startByte = 21, endByte = 24), " + "(operator = '+', startByte = 25, endByte = 26), " + "(operator = '-=', startByte = 27, endByte = 29)" + "])", + doLex(" 'foo\\x20' 123 2.75 6e4 + -= ").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(parenthesizedList = [" + "[" + "(identifier = 'foo', startByte = 1, endByte = 4), " + "(identifier = 'bar', startByte = 5, endByte = 8)" + "], [" + "(identifier = 'baz', startByte = 10, endByte = 13), " + "(identifier = 'qux', startByte = 14, endByte = 17)" + "], [" + "(identifier = 'corge', startByte = 19, endByte = 24), " + "(identifier = 'grault', startByte = 25, endByte = 31)" + "]" + "], startByte = 0, endByte = 32)" + "])", + doLex("(foo bar, baz qux, corge grault)").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(parenthesizedList = [" + "[" + "(identifier = 'foo', startByte = 1, endByte = 4), " + "(identifier = 'bar', startByte = 5, endByte = 8)" + "]" + "], startByte = 0, endByte = 9)" + "])", + doLex("(foo bar)").cStr()); + + // Empty parentheses should result in an empty list-of-lists, *not* a list containing an empty + // list. + EXPECT_STREQ( + "(tokens = [" + "(parenthesizedList = [], startByte = 0, endByte = 4)" + "])", + doLex("( )").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(bracketedList = [" + "[" + "(identifier = 'foo', startByte = 1, endByte = 4), " + "(identifier = 'bar', startByte = 5, endByte = 8)" + "], [" + "(identifier = 'baz', startByte = 10, endByte = 13), " + "(identifier = 'qux', startByte = 14, endByte = 17)" + "], [" + "(identifier = 'corge', startByte = 19, endByte = 24), " + "(identifier = 'grault', startByte = 25, endByte = 31)" + "]" + "], startByte = 0, endByte = 32)" + "])", + doLex("[foo bar, baz qux, corge grault]").cStr()); + + // Trailing commas should not create an empty final list item, but be stripped by the lexer. + EXPECT_STREQ( + "(tokens = [" + "(bracketedList = [" + "[" + "(identifier = 'foo', startByte = 1, endByte = 4)" + "], [" + "(identifier = 'bar', startByte = 6, endByte = 9)" + "]" + "], startByte = 0, endByte = 11)" + "])", + doLex("[foo, bar,]").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(bracketedList = [" + "[" + "(identifier = 'foo', startByte = 1, endByte = 4)" + "], [" + "(parenthesizedList = [" + "[" + "(identifier = 'bar', startByte = 7, endByte = 10)" + "], [" + "(identifier = 'baz', startByte = 12, endByte = 15)" + "]" + "], startByte = 6, endByte = 16)" + "]" + "], startByte = 0, endByte = 17), " + "(identifier = 'qux', startByte = 18, endByte = 21)" + "])", + doLex("[foo, (bar, baz)] qux").cStr()); + + EXPECT_STREQ( + "(tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3), " + "(identifier = 'bar', startByte = 7, endByte = 10)" + "])", + doLex("foo\n\r\t\vbar").cStr()); +} + +TEST(Lexer, Statements) { + EXPECT_STREQ( + "(statements = [" + "(tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3), " + "(identifier = 'bar', startByte = 4, endByte = 7)" + "], line = void, startByte = 0, endByte = 8)" + "])", + doLex("foo bar;").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], line = void, startByte = 0, endByte = 4), " + "(tokens = [" + "(identifier = 'bar', startByte = 5, endByte = 8)" + "], line = void, startByte = 5, endByte = 9), " + "(tokens = [" + "(identifier = 'baz', startByte = 10, endByte = 13)" + "], line = void, startByte = 10, endByte = 14)" + "])", + doLex("foo; bar; baz; ").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "block = [" + "(tokens = [" + "(identifier = 'bar', startByte = 5, endByte = 8)" + "], line = void, startByte = 5, endByte = 9), " + "(tokens = [" + "(identifier = 'baz', startByte = 10, endByte = 13)" + "], line = void, startByte = 10, endByte = 14)" + "], " + "startByte = 0, endByte = 15" + "), " + "(tokens = [" + "(identifier = 'qux', startByte = 16, endByte = 19)" + "], line = void, startByte = 16, endByte = 20)" + "])", + doLex("foo {bar; baz;} qux;").cStr()); +} + +TEST(Lexer, DocComments) { + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "docComment = 'blah blah\\n', " + "startByte = 0, endByte = 16" + ")" + "])", + doLex("foo; # blah blah").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "docComment = 'blah blah\\n', " + "startByte = 0, endByte = 15" + ")" + "])", + doLex("foo; #blah blah").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "docComment = ' blah blah\\n', " + "startByte = 0, endByte = 17" + ")" + "])", + doLex("foo; # blah blah").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "docComment = 'blah blah\\n', " + "startByte = 0, endByte = 16" + ")" + "])", + doLex("foo;\n# blah blah").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "startByte = 0, endByte = 4" + ")" + "])", + doLex("foo;\n\n# blah blah").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "line = void, " + "docComment = 'bar baz\\nqux corge\\n', " + "startByte = 0, endByte = 30" + ")" + "])", + doLex("foo;\n # bar baz\n # qux corge\n\n# grault\n# garply").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "block = [" + "(tokens = [" + "(identifier = 'bar', startByte = 17, endByte = 20)" + "], line = void, docComment = 'hi\\n', startByte = 17, endByte = 27), " + "(tokens = [" + "(identifier = 'baz', startByte = 28, endByte = 31)" + "], line = void, startByte = 28, endByte = 32)" + "], " + "docComment = 'blah blah\\n', " + "startByte = 0, endByte = 44" + "), " + "(tokens = [" + "(identifier = 'qux', startByte = 44, endByte = 47)" + "], line = void, startByte = 44, endByte = 48)" + "])", + doLex("foo {# blah blah\nbar; # hi\n baz;} # ignored\nqux;").cStr()); + + EXPECT_STREQ( + "(statements = [" + "(" + "tokens = [" + "(identifier = 'foo', startByte = 0, endByte = 3)" + "], " + "block = [" + "(tokens = [" + "(identifier = 'bar', startByte = 5, endByte = 8)" + "], line = void, startByte = 5, endByte = 9), " + "(tokens = [" + "(identifier = 'baz', startByte = 10, endByte = 13)" + "], line = void, startByte = 10, endByte = 14)" + "], " + "docComment = 'late comment\\n', " + "startByte = 0, endByte = 31" + "), " + "(tokens = [" + "(identifier = 'qux', startByte = 31, endByte = 34)" + "], line = void, startByte = 31, endByte = 35)" + "])", + doLex("foo {bar; baz;}\n# late comment\nqux;").cStr()); +} + +TEST(Lexer, Utf8Bom) { + EXPECT_STREQ( + "(tokens = [" + "(identifier = 'foo', startByte = 3, endByte = 6), " + "(identifier = 'bar', startByte = 7, endByte = 10), " + "(identifier = 'baz', startByte = 13, endByte = 16)" + "])", + doLex("\xef\xbb\xbf""foo bar\xef\xbb\xbf""baz").cStr()); +} + +} // namespace +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,300 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "lexer.h" +#include +#include + +namespace capnp { +namespace compiler { + +namespace p = kj::parse; + +bool lex(kj::ArrayPtr input, LexedStatements::Builder result, + ErrorReporter& errorReporter) { + Lexer lexer(Orphanage::getForMessageContaining(result), errorReporter); + + auto parser = p::sequence(lexer.getParsers().statementSequence, p::endOfInput); + + Lexer::ParserInput parserInput(input.begin(), input.end()); + kj::Maybe>> parseOutput = parser(parserInput); + + KJ_IF_MAYBE(output, parseOutput) { + auto l = result.initStatements(output->size()); + for (uint i = 0; i < output->size(); i++) { + l.adoptWithCaveats(i, kj::mv((*output)[i])); + } + return true; + } else { + uint32_t best = parserInput.getBest(); + errorReporter.addError(best, best, kj::str("Parse error.")); + return false; + } +} + +bool lex(kj::ArrayPtr input, LexedTokens::Builder result, + ErrorReporter& errorReporter) { + Lexer lexer(Orphanage::getForMessageContaining(result), errorReporter); + + auto parser = p::sequence(lexer.getParsers().tokenSequence, p::endOfInput); + + Lexer::ParserInput parserInput(input.begin(), input.end()); + kj::Maybe>> parseOutput = parser(parserInput); + + KJ_IF_MAYBE(output, parseOutput) { + auto l = result.initTokens(output->size()); + for (uint i = 0; i < output->size(); i++) { + l.adoptWithCaveats(i, kj::mv((*output)[i])); + } + return true; + } else { + uint32_t best = parserInput.getBest(); + errorReporter.addError(best, best, kj::str("Parse error.")); + return false; + } +} + +namespace { + +typedef p::Span Location; + +Token::Builder initTok(Orphan& t, const Location& loc) { + auto builder = t.get(); + builder.setStartByte(loc.begin()); + builder.setEndByte(loc.end()); + return builder; +} + +void buildTokenSequenceList(List>::Builder builder, + kj::Array>>&& items) { + for (uint i = 0; i < items.size(); i++) { + auto& item = items[i]; + auto itemBuilder = builder.init(i, item.size()); + for (uint j = 0; j < item.size(); j++) { + itemBuilder.adoptWithCaveats(j, kj::mv(item[j])); + } + } +} + +void attachDocComment(Statement::Builder statement, kj::Array&& comment) { + size_t size = 0; + for (auto& line: comment) { + size += line.size() + 1; // include newline + } + Text::Builder builder = statement.initDocComment(size); + char* pos = builder.begin(); + for (auto& line: comment) { + memcpy(pos, line.begin(), line.size()); + pos += line.size(); + *pos++ = '\n'; + } + KJ_ASSERT(pos == builder.end()); +} + +constexpr auto discardComment = + sequence(p::exactChar<'#'>(), p::discard(p::many(p::discard(p::anyOfChars("\n").invert()))), + p::oneOf(p::exactChar<'\n'>(), p::endOfInput)); +constexpr auto saveComment = + sequence(p::exactChar<'#'>(), p::discard(p::optional(p::exactChar<' '>())), + p::charsToString(p::many(p::anyOfChars("\n").invert())), + p::oneOf(p::exactChar<'\n'>(), p::endOfInput)); + +constexpr auto utf8Bom = + sequence(p::exactChar<'\xef'>(), p::exactChar<'\xbb'>(), p::exactChar<'\xbf'>()); + +constexpr auto bomsAndWhitespace = + sequence(p::discardWhitespace, + p::discard(p::many(sequence(utf8Bom, p::discardWhitespace)))); + +constexpr auto commentsAndWhitespace = + sequence(bomsAndWhitespace, + p::discard(p::many(sequence(discardComment, bomsAndWhitespace)))); + +constexpr auto discardLineWhitespace = + p::discard(p::many(p::discard(p::whitespaceChar.invert().orAny("\r\n").invert()))); +constexpr auto newline = p::oneOf( + p::exactChar<'\n'>(), + sequence(p::exactChar<'\r'>(), p::discard(p::optional(p::exactChar<'\n'>())))); + +constexpr auto docComment = p::optional(p::sequence( + discardLineWhitespace, + p::discard(p::optional(newline)), + p::oneOrMore(p::sequence(discardLineWhitespace, saveComment)))); +// Parses a set of comment lines preceded by at most one newline and with no intervening blank +// lines. + +} // namespace + +Lexer::Lexer(Orphanage orphanageParam, ErrorReporter& errorReporter) + : orphanage(orphanageParam) { + + // Note that because passing an lvalue to a parser constructor uses it by-referencee, it's safe + // for us to use parsers.tokenSequence even though we haven't yet constructed it. + auto& tokenSequence = parsers.tokenSequence; + + auto& commaDelimitedList = arena.copy(p::transform( + p::sequence(tokenSequence, p::many(p::sequence(p::exactChar<','>(), tokenSequence))), + [](kj::Array>&& first, kj::Array>>&& rest) + -> kj::Array>> { + if (first == nullptr && rest == nullptr) { + // Completely empty list. + return nullptr; + } else { + uint restSize = rest.size(); + if (restSize > 0 && rest[restSize - 1] == nullptr) { + // Allow for trailing commas by shortening the list by one item if the final token is + // nullptr + restSize--; + } + auto result = kj::heapArrayBuilder>>(1 + restSize); // first+rest + result.add(kj::mv(first)); + for (uint i = 0; i < restSize ; i++) { + result.add(kj::mv(rest[i])); + } + return result.finish(); + } + })); + + auto& token = arena.copy(p::oneOf( + p::transformWithLocation(p::identifier, + [this](Location loc, kj::String name) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setIdentifier(name); + return t; + }), + p::transformWithLocation(p::doubleQuotedString, + [this](Location loc, kj::String text) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setStringLiteral(text); + return t; + }), + p::transformWithLocation(p::doubleQuotedHexBinary, + [this](Location loc, kj::Array data) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setBinaryLiteral(data); + return t; + }), + p::transformWithLocation(p::integer, + [this](Location loc, uint64_t i) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setIntegerLiteral(i); + return t; + }), + p::transformWithLocation(p::number, + [this](Location loc, double x) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setFloatLiteral(x); + return t; + }), + p::transformWithLocation( + p::charsToString(p::oneOrMore(p::anyOfChars("!$%&*+-./:<=>?@^|~"))), + [this](Location loc, kj::String text) -> Orphan { + auto t = orphanage.newOrphan(); + initTok(t, loc).setOperator(text); + return t; + }), + p::transformWithLocation( + sequence(p::exactChar<'('>(), commaDelimitedList, p::exactChar<')'>()), + [this](Location loc, kj::Array>>&& items) -> Orphan { + auto t = orphanage.newOrphan(); + buildTokenSequenceList( + initTok(t, loc).initParenthesizedList(items.size()), kj::mv(items)); + return t; + }), + p::transformWithLocation( + sequence(p::exactChar<'['>(), commaDelimitedList, p::exactChar<']'>()), + [this](Location loc, kj::Array>>&& items) -> Orphan { + auto t = orphanage.newOrphan(); + buildTokenSequenceList( + initTok(t, loc).initBracketedList(items.size()), kj::mv(items)); + return t; + }), + p::transformOrReject(p::transformWithLocation( + p::oneOf(sequence(p::exactChar<'\xff'>(), p::exactChar<'\xfe'>()), + sequence(p::exactChar<'\xfe'>(), p::exactChar<'\xff'>()), + sequence(p::exactChar<'\x00'>())), + [&errorReporter](Location loc) -> kj::Maybe> { + errorReporter.addError(loc.begin(), loc.end(), + "Non-UTF-8 input detected. Cap'n Proto schema files must be UTF-8 text."); + return nullptr; + }), [](kj::Maybe> param) { return param; }))); + parsers.tokenSequence = arena.copy(p::sequence( + commentsAndWhitespace, p::many(p::sequence(token, commentsAndWhitespace)))); + + auto& statementSequence = parsers.statementSequence; + + auto& statementEnd = arena.copy(p::oneOf( + transform(p::sequence(p::exactChar<';'>(), docComment), + [this](kj::Maybe>&& comment) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + KJ_IF_MAYBE(c, comment) { + attachDocComment(builder, kj::mv(*c)); + } + builder.setLine(); + return result; + }), + transform( + p::sequence(p::exactChar<'{'>(), docComment, statementSequence, p::exactChar<'}'>(), + docComment), + [this](kj::Maybe>&& comment, + kj::Array>&& statements, + kj::Maybe>&& lateComment) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + KJ_IF_MAYBE(c, comment) { + attachDocComment(builder, kj::mv(*c)); + } else KJ_IF_MAYBE(c, lateComment) { + attachDocComment(builder, kj::mv(*c)); + } + auto list = builder.initBlock(statements.size()); + for (uint i = 0; i < statements.size(); i++) { + list.adoptWithCaveats(i, kj::mv(statements[i])); + } + return result; + }) + )); + + auto& statement = arena.copy(p::transformWithLocation(p::sequence(tokenSequence, statementEnd), + [](Location loc, kj::Array>&& tokens, Orphan&& statement) { + auto builder = statement.get(); + auto tokensBuilder = builder.initTokens(tokens.size()); + for (uint i = 0; i < tokens.size(); i++) { + tokensBuilder.adoptWithCaveats(i, kj::mv(tokens[i])); + } + builder.setStartByte(loc.begin()); + builder.setEndByte(loc.end()); + return kj::mv(statement); + })); + + parsers.statementSequence = arena.copy(sequence( + commentsAndWhitespace, many(sequence(statement, commentsAndWhitespace)))); + + parsers.token = token; + parsers.statement = statement; + parsers.emptySpace = commentsAndWhitespace; +} + +Lexer::~Lexer() noexcept(false) {} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,67 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xa73956d2621fc3ee; + +using Cxx = import "/capnp/c++.capnp"; + +$Cxx.namespace("capnp::compiler"); + +struct Token { + union { + identifier @0 :Text; + stringLiteral @1 :Text; + binaryLiteral @9 :Data; + integerLiteral @2 :UInt64; + floatLiteral @3 :Float64; + operator @4 :Text; + parenthesizedList @5 :List(List(Token)); + bracketedList @6 :List(List(Token)); + } + + startByte @7 :UInt32; + endByte @8 :UInt32; +} + +struct Statement { + tokens @0 :List(Token); + union { + line @1 :Void; + block @2 :List(Statement); + } + + docComment @3 :Text; + + startByte @4 :UInt32; + endByte @5 :UInt32; +} + +struct LexedTokens { + # Lexer output when asked to parse tokens that don't form statements. + + tokens @0 :List(Token); +} + +struct LexedStatements { + # Lexer output when asked to parse statements. + + statements @0 :List(Statement); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,500 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: lexer.capnp + +#include "lexer.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<195> b_91cc55cd57de5419 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 25, 84, 222, 87, 205, 85, 204, 145, + 27, 0, 0, 0, 1, 0, 3, 0, + 238, 195, 31, 98, 210, 86, 57, 167, + 1, 0, 7, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 10, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 55, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 108, + 101, 120, 101, 114, 46, 99, 97, 112, + 110, 112, 58, 84, 111, 107, 101, 110, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 40, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 1, 0, 0, 3, 0, 1, 0, + 20, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 1, 0, 0, 3, 0, 1, 0, + 28, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 253, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 1, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 24, 1, 0, 0, 3, 0, 1, 0, + 36, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 252, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 1, 0, 0, 3, 0, 1, 0, + 44, 1, 0, 0, 2, 0, 1, 0, + 5, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 1, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 1, 0, 0, 3, 0, 1, 0, + 52, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 1, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 52, 1, 0, 0, 3, 0, 1, 0, + 96, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 249, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 93, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 92, 1, 0, 0, 3, 0, 1, 0, + 136, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 1, 0, 0, 3, 0, 1, 0, + 144, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 136, 1, 0, 0, 3, 0, 1, 0, + 148, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 248, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 145, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 144, 1, 0, 0, 3, 0, 1, 0, + 156, 1, 0, 0, 2, 0, 1, 0, + 105, 100, 101, 110, 116, 105, 102, 105, + 101, 114, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 105, 110, 103, 76, 105, + 116, 101, 114, 97, 108, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 101, 103, 101, 114, 76, + 105, 116, 101, 114, 97, 108, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 76, 105, 116, + 101, 114, 97, 108, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 112, 101, 114, 97, 116, 111, 114, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 101, 110, 116, 104, 101, + 115, 105, 122, 101, 100, 76, 105, 115, + 116, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 25, 84, 222, 87, 205, 85, 204, 145, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 99, 107, 101, 116, 101, + 100, 76, 105, 115, 116, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 25, 84, 222, 87, 205, 85, 204, 145, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 105, 110, 97, 114, 121, 76, 105, + 116, 101, 114, 97, 108, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_91cc55cd57de5419 = b_91cc55cd57de5419.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_91cc55cd57de5419[] = { + &s_91cc55cd57de5419, +}; +static const uint16_t m_91cc55cd57de5419[] = {9, 6, 8, 3, 0, 2, 4, 5, 7, 1}; +static const uint16_t i_91cc55cd57de5419[] = {0, 1, 2, 3, 4, 5, 6, 9, 7, 8}; +const ::capnp::_::RawSchema s_91cc55cd57de5419 = { + 0x91cc55cd57de5419, b_91cc55cd57de5419.words, 195, d_91cc55cd57de5419, m_91cc55cd57de5419, + 1, 10, i_91cc55cd57de5419, nullptr, nullptr, { &s_91cc55cd57de5419, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<119> b_c6725e678d60fa37 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 55, 250, 96, 141, 103, 94, 114, 198, + 27, 0, 0, 0, 1, 0, 2, 0, + 238, 195, 31, 98, 210, 86, 57, 167, + 3, 0, 7, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 42, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 87, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 108, + 101, 120, 101, 114, 46, 99, 97, 112, + 110, 112, 58, 83, 116, 97, 116, 101, + 109, 101, 110, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 24, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 0, 0, 0, 3, 0, 1, 0, + 176, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 173, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 0, 0, 0, 3, 0, 1, 0, + 180, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 172, 0, 0, 0, 3, 0, 1, 0, + 200, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 3, 0, 1, 0, + 208, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 205, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 204, 0, 0, 0, 3, 0, 1, 0, + 216, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 213, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 208, 0, 0, 0, 3, 0, 1, 0, + 220, 0, 0, 0, 2, 0, 1, 0, + 116, 111, 107, 101, 110, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 25, 84, 222, 87, 205, 85, 204, 145, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 105, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 108, 111, 99, 107, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 55, 250, 96, 141, 103, 94, 114, 198, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 111, 99, 67, 111, 109, 109, 101, + 110, 116, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 97, 114, 116, 66, 121, 116, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 100, 66, 121, 116, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c6725e678d60fa37 = b_c6725e678d60fa37.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c6725e678d60fa37[] = { + &s_91cc55cd57de5419, + &s_c6725e678d60fa37, +}; +static const uint16_t m_c6725e678d60fa37[] = {2, 3, 5, 1, 4, 0}; +static const uint16_t i_c6725e678d60fa37[] = {1, 2, 0, 3, 4, 5}; +const ::capnp::_::RawSchema s_c6725e678d60fa37 = { + 0xc6725e678d60fa37, b_c6725e678d60fa37.words, 119, d_c6725e678d60fa37, m_c6725e678d60fa37, + 2, 6, i_c6725e678d60fa37, nullptr, nullptr, { &s_c6725e678d60fa37, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<38> b_9e69a92512b19d18 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 24, 157, 177, 18, 37, 169, 105, 158, + 27, 0, 0, 0, 1, 0, 0, 0, + 238, 195, 31, 98, 210, 86, 57, 167, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 58, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 108, + 101, 120, 101, 114, 46, 99, 97, 112, + 110, 112, 58, 76, 101, 120, 101, 100, + 84, 111, 107, 101, 110, 115, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 36, 0, 0, 0, 2, 0, 1, 0, + 116, 111, 107, 101, 110, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 25, 84, 222, 87, 205, 85, 204, 145, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9e69a92512b19d18 = b_9e69a92512b19d18.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9e69a92512b19d18[] = { + &s_91cc55cd57de5419, +}; +static const uint16_t m_9e69a92512b19d18[] = {0}; +static const uint16_t i_9e69a92512b19d18[] = {0}; +const ::capnp::_::RawSchema s_9e69a92512b19d18 = { + 0x9e69a92512b19d18, b_9e69a92512b19d18.words, 38, d_9e69a92512b19d18, m_9e69a92512b19d18, + 1, 1, i_9e69a92512b19d18, nullptr, nullptr, { &s_9e69a92512b19d18, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<40> b_a11f97b9d6c73dd4 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 212, 61, 199, 214, 185, 151, 31, 161, + 27, 0, 0, 0, 1, 0, 0, 0, + 238, 195, 31, 98, 210, 86, 57, 167, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 90, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 99, 111, + 109, 112, 105, 108, 101, 114, 47, 108, + 101, 120, 101, 114, 46, 99, 97, 112, + 110, 112, 58, 76, 101, 120, 101, 100, + 83, 116, 97, 116, 101, 109, 101, 110, + 116, 115, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 40, 0, 0, 0, 2, 0, 1, 0, + 115, 116, 97, 116, 101, 109, 101, 110, + 116, 115, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 55, 250, 96, 141, 103, 94, 114, 198, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_a11f97b9d6c73dd4 = b_a11f97b9d6c73dd4.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_a11f97b9d6c73dd4[] = { + &s_c6725e678d60fa37, +}; +static const uint16_t m_a11f97b9d6c73dd4[] = {0}; +static const uint16_t i_a11f97b9d6c73dd4[] = {0}; +const ::capnp::_::RawSchema s_a11f97b9d6c73dd4 = { + 0xa11f97b9d6c73dd4, b_a11f97b9d6c73dd4.words, 40, d_a11f97b9d6c73dd4, m_a11f97b9d6c73dd4, + 1, 1, i_a11f97b9d6c73dd4, nullptr, nullptr, { &s_a11f97b9d6c73dd4, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { +namespace compiler { + +// Token +constexpr uint16_t Token::_capnpPrivate::dataWordSize; +constexpr uint16_t Token::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Token::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Token::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Statement +constexpr uint16_t Statement::_capnpPrivate::dataWordSize; +constexpr uint16_t Statement::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Statement::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Statement::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// LexedTokens +constexpr uint16_t LexedTokens::_capnpPrivate::dataWordSize; +constexpr uint16_t LexedTokens::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind LexedTokens::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* LexedTokens::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// LexedStatements +constexpr uint16_t LexedStatements::_capnpPrivate::dataWordSize; +constexpr uint16_t LexedStatements::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind LexedStatements::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* LexedStatements::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1242 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: lexer.capnp + +#ifndef CAPNP_INCLUDED_a73956d2621fc3ee_ +#define CAPNP_INCLUDED_a73956d2621fc3ee_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(91cc55cd57de5419); +CAPNP_DECLARE_SCHEMA(c6725e678d60fa37); +CAPNP_DECLARE_SCHEMA(9e69a92512b19d18); +CAPNP_DECLARE_SCHEMA(a11f97b9d6c73dd4); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace compiler { + +struct Token { + Token() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + IDENTIFIER, + STRING_LITERAL, + INTEGER_LITERAL, + FLOAT_LITERAL, + OPERATOR, + PARENTHESIZED_LIST, + BRACKETED_LIST, + BINARY_LITERAL, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(91cc55cd57de5419, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Statement { + Statement() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + LINE, + BLOCK, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c6725e678d60fa37, 2, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct LexedTokens { + LexedTokens() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9e69a92512b19d18, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct LexedStatements { + LexedStatements() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(a11f97b9d6c73dd4, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class Token::Reader { +public: + typedef Token Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isIdentifier() const; + inline bool hasIdentifier() const; + inline ::capnp::Text::Reader getIdentifier() const; + + inline bool isStringLiteral() const; + inline bool hasStringLiteral() const; + inline ::capnp::Text::Reader getStringLiteral() const; + + inline bool isIntegerLiteral() const; + inline ::uint64_t getIntegerLiteral() const; + + inline bool isFloatLiteral() const; + inline double getFloatLiteral() const; + + inline bool isOperator() const; + inline bool hasOperator() const; + inline ::capnp::Text::Reader getOperator() const; + + inline bool isParenthesizedList() const; + inline bool hasParenthesizedList() const; + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader getParenthesizedList() const; + + inline bool isBracketedList() const; + inline bool hasBracketedList() const; + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader getBracketedList() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + + inline bool isBinaryLiteral() const; + inline bool hasBinaryLiteral() const; + inline ::capnp::Data::Reader getBinaryLiteral() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Token::Builder { +public: + typedef Token Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isIdentifier(); + inline bool hasIdentifier(); + inline ::capnp::Text::Builder getIdentifier(); + inline void setIdentifier( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initIdentifier(unsigned int size); + inline void adoptIdentifier(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownIdentifier(); + + inline bool isStringLiteral(); + inline bool hasStringLiteral(); + inline ::capnp::Text::Builder getStringLiteral(); + inline void setStringLiteral( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initStringLiteral(unsigned int size); + inline void adoptStringLiteral(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownStringLiteral(); + + inline bool isIntegerLiteral(); + inline ::uint64_t getIntegerLiteral(); + inline void setIntegerLiteral( ::uint64_t value); + + inline bool isFloatLiteral(); + inline double getFloatLiteral(); + inline void setFloatLiteral(double value); + + inline bool isOperator(); + inline bool hasOperator(); + inline ::capnp::Text::Builder getOperator(); + inline void setOperator( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initOperator(unsigned int size); + inline void adoptOperator(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownOperator(); + + inline bool isParenthesizedList(); + inline bool hasParenthesizedList(); + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder getParenthesizedList(); + inline void setParenthesizedList( ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader value); + inline void setParenthesizedList(::kj::ArrayPtr::Reader> value); + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder initParenthesizedList(unsigned int size); + inline void adoptParenthesizedList(::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>> disownParenthesizedList(); + + inline bool isBracketedList(); + inline bool hasBracketedList(); + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder getBracketedList(); + inline void setBracketedList( ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader value); + inline void setBracketedList(::kj::ArrayPtr::Reader> value); + inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder initBracketedList(unsigned int size); + inline void adoptBracketedList(::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>> disownBracketedList(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + + inline bool isBinaryLiteral(); + inline bool hasBinaryLiteral(); + inline ::capnp::Data::Builder getBinaryLiteral(); + inline void setBinaryLiteral( ::capnp::Data::Reader value); + inline ::capnp::Data::Builder initBinaryLiteral(unsigned int size); + inline void adoptBinaryLiteral(::capnp::Orphan< ::capnp::Data>&& value); + inline ::capnp::Orphan< ::capnp::Data> disownBinaryLiteral(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Token::Pipeline { +public: + typedef Token Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Statement::Reader { +public: + typedef Statement Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool hasTokens() const; + inline ::capnp::List< ::capnp::compiler::Token>::Reader getTokens() const; + + inline bool isLine() const; + inline ::capnp::Void getLine() const; + + inline bool isBlock() const; + inline bool hasBlock() const; + inline ::capnp::List< ::capnp::compiler::Statement>::Reader getBlock() const; + + inline bool hasDocComment() const; + inline ::capnp::Text::Reader getDocComment() const; + + inline ::uint32_t getStartByte() const; + + inline ::uint32_t getEndByte() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Statement::Builder { +public: + typedef Statement Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool hasTokens(); + inline ::capnp::List< ::capnp::compiler::Token>::Builder getTokens(); + inline void setTokens( ::capnp::List< ::capnp::compiler::Token>::Reader value); + inline ::capnp::List< ::capnp::compiler::Token>::Builder initTokens(unsigned int size); + inline void adoptTokens(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>> disownTokens(); + + inline bool isLine(); + inline ::capnp::Void getLine(); + inline void setLine( ::capnp::Void value = ::capnp::VOID); + + inline bool isBlock(); + inline bool hasBlock(); + inline ::capnp::List< ::capnp::compiler::Statement>::Builder getBlock(); + inline void setBlock( ::capnp::List< ::capnp::compiler::Statement>::Reader value); + inline ::capnp::List< ::capnp::compiler::Statement>::Builder initBlock(unsigned int size); + inline void adoptBlock(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>> disownBlock(); + + inline bool hasDocComment(); + inline ::capnp::Text::Builder getDocComment(); + inline void setDocComment( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initDocComment(unsigned int size); + inline void adoptDocComment(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownDocComment(); + + inline ::uint32_t getStartByte(); + inline void setStartByte( ::uint32_t value); + + inline ::uint32_t getEndByte(); + inline void setEndByte( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Statement::Pipeline { +public: + typedef Statement Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class LexedTokens::Reader { +public: + typedef LexedTokens Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasTokens() const; + inline ::capnp::List< ::capnp::compiler::Token>::Reader getTokens() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class LexedTokens::Builder { +public: + typedef LexedTokens Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasTokens(); + inline ::capnp::List< ::capnp::compiler::Token>::Builder getTokens(); + inline void setTokens( ::capnp::List< ::capnp::compiler::Token>::Reader value); + inline ::capnp::List< ::capnp::compiler::Token>::Builder initTokens(unsigned int size); + inline void adoptTokens(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>> disownTokens(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class LexedTokens::Pipeline { +public: + typedef LexedTokens Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class LexedStatements::Reader { +public: + typedef LexedStatements Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasStatements() const; + inline ::capnp::List< ::capnp::compiler::Statement>::Reader getStatements() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class LexedStatements::Builder { +public: + typedef LexedStatements Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasStatements(); + inline ::capnp::List< ::capnp::compiler::Statement>::Builder getStatements(); + inline void setStatements( ::capnp::List< ::capnp::compiler::Statement>::Reader value); + inline ::capnp::List< ::capnp::compiler::Statement>::Builder initStatements(unsigned int size); + inline void adoptStatements(::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>> disownStatements(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class LexedStatements::Pipeline { +public: + typedef LexedStatements Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::compiler::Token::Which Token::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Token::Which Token::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Token::Reader::isIdentifier() const { + return which() == Token::IDENTIFIER; +} +inline bool Token::Builder::isIdentifier() { + return which() == Token::IDENTIFIER; +} +inline bool Token::Reader::hasIdentifier() const { + if (which() != Token::IDENTIFIER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasIdentifier() { + if (which() != Token::IDENTIFIER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Token::Reader::getIdentifier() const { + KJ_IREQUIRE((which() == Token::IDENTIFIER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Token::Builder::getIdentifier() { + KJ_IREQUIRE((which() == Token::IDENTIFIER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setIdentifier( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::IDENTIFIER); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Token::Builder::initIdentifier(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::IDENTIFIER); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptIdentifier( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::IDENTIFIER); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Token::Builder::disownIdentifier() { + KJ_IREQUIRE((which() == Token::IDENTIFIER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Token::Reader::isStringLiteral() const { + return which() == Token::STRING_LITERAL; +} +inline bool Token::Builder::isStringLiteral() { + return which() == Token::STRING_LITERAL; +} +inline bool Token::Reader::hasStringLiteral() const { + if (which() != Token::STRING_LITERAL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasStringLiteral() { + if (which() != Token::STRING_LITERAL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Token::Reader::getStringLiteral() const { + KJ_IREQUIRE((which() == Token::STRING_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Token::Builder::getStringLiteral() { + KJ_IREQUIRE((which() == Token::STRING_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setStringLiteral( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::STRING_LITERAL); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Token::Builder::initStringLiteral(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::STRING_LITERAL); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptStringLiteral( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::STRING_LITERAL); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Token::Builder::disownStringLiteral() { + KJ_IREQUIRE((which() == Token::STRING_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Token::Reader::isIntegerLiteral() const { + return which() == Token::INTEGER_LITERAL; +} +inline bool Token::Builder::isIntegerLiteral() { + return which() == Token::INTEGER_LITERAL; +} +inline ::uint64_t Token::Reader::getIntegerLiteral() const { + KJ_IREQUIRE((which() == Token::INTEGER_LITERAL), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Token::Builder::getIntegerLiteral() { + KJ_IREQUIRE((which() == Token::INTEGER_LITERAL), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Token::Builder::setIntegerLiteral( ::uint64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::INTEGER_LITERAL); + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Token::Reader::isFloatLiteral() const { + return which() == Token::FLOAT_LITERAL; +} +inline bool Token::Builder::isFloatLiteral() { + return which() == Token::FLOAT_LITERAL; +} +inline double Token::Reader::getFloatLiteral() const { + KJ_IREQUIRE((which() == Token::FLOAT_LITERAL), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double Token::Builder::getFloatLiteral() { + KJ_IREQUIRE((which() == Token::FLOAT_LITERAL), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Token::Builder::setFloatLiteral(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::FLOAT_LITERAL); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Token::Reader::isOperator() const { + return which() == Token::OPERATOR; +} +inline bool Token::Builder::isOperator() { + return which() == Token::OPERATOR; +} +inline bool Token::Reader::hasOperator() const { + if (which() != Token::OPERATOR) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasOperator() { + if (which() != Token::OPERATOR) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Token::Reader::getOperator() const { + KJ_IREQUIRE((which() == Token::OPERATOR), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Token::Builder::getOperator() { + KJ_IREQUIRE((which() == Token::OPERATOR), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setOperator( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::OPERATOR); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Token::Builder::initOperator(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::OPERATOR); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptOperator( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::OPERATOR); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Token::Builder::disownOperator() { + KJ_IREQUIRE((which() == Token::OPERATOR), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Token::Reader::isParenthesizedList() const { + return which() == Token::PARENTHESIZED_LIST; +} +inline bool Token::Builder::isParenthesizedList() { + return which() == Token::PARENTHESIZED_LIST; +} +inline bool Token::Reader::hasParenthesizedList() const { + if (which() != Token::PARENTHESIZED_LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasParenthesizedList() { + if (which() != Token::PARENTHESIZED_LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader Token::Reader::getParenthesizedList() const { + KJ_IREQUIRE((which() == Token::PARENTHESIZED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder Token::Builder::getParenthesizedList() { + KJ_IREQUIRE((which() == Token::PARENTHESIZED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setParenthesizedList( ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::PARENTHESIZED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline void Token::Builder::setParenthesizedList(::kj::ArrayPtr::Reader> value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::PARENTHESIZED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder Token::Builder::initParenthesizedList(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::PARENTHESIZED_LIST); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptParenthesizedList( + ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::PARENTHESIZED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>> Token::Builder::disownParenthesizedList() { + KJ_IREQUIRE((which() == Token::PARENTHESIZED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Token::Reader::isBracketedList() const { + return which() == Token::BRACKETED_LIST; +} +inline bool Token::Builder::isBracketedList() { + return which() == Token::BRACKETED_LIST; +} +inline bool Token::Reader::hasBracketedList() const { + if (which() != Token::BRACKETED_LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasBracketedList() { + if (which() != Token::BRACKETED_LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader Token::Reader::getBracketedList() const { + KJ_IREQUIRE((which() == Token::BRACKETED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder Token::Builder::getBracketedList() { + KJ_IREQUIRE((which() == Token::BRACKETED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setBracketedList( ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BRACKETED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline void Token::Builder::setBracketedList(::kj::ArrayPtr::Reader> value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BRACKETED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>::Builder Token::Builder::initBracketedList(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BRACKETED_LIST); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptBracketedList( + ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BRACKETED_LIST); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>> Token::Builder::disownBracketedList() { + KJ_IREQUIRE((which() == Token::BRACKETED_LIST), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::List< ::capnp::compiler::Token>>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Token::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Token::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Token::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Token::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Token::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline void Token::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, value); +} + +inline bool Token::Reader::isBinaryLiteral() const { + return which() == Token::BINARY_LITERAL; +} +inline bool Token::Builder::isBinaryLiteral() { + return which() == Token::BINARY_LITERAL; +} +inline bool Token::Reader::hasBinaryLiteral() const { + if (which() != Token::BINARY_LITERAL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Token::Builder::hasBinaryLiteral() { + if (which() != Token::BINARY_LITERAL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Data::Reader Token::Reader::getBinaryLiteral() const { + KJ_IREQUIRE((which() == Token::BINARY_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Data::Builder Token::Builder::getBinaryLiteral() { + KJ_IREQUIRE((which() == Token::BINARY_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Token::Builder::setBinaryLiteral( ::capnp::Data::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BINARY_LITERAL); + ::capnp::_::PointerHelpers< ::capnp::Data>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Data::Builder Token::Builder::initBinaryLiteral(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BINARY_LITERAL); + return ::capnp::_::PointerHelpers< ::capnp::Data>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Token::Builder::adoptBinaryLiteral( + ::capnp::Orphan< ::capnp::Data>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Token::BINARY_LITERAL); + ::capnp::_::PointerHelpers< ::capnp::Data>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Data> Token::Builder::disownBinaryLiteral() { + KJ_IREQUIRE((which() == Token::BINARY_LITERAL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::compiler::Statement::Which Statement::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::compiler::Statement::Which Statement::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Statement::Reader::hasTokens() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Statement::Builder::hasTokens() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Token>::Reader Statement::Reader::getTokens() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Token>::Builder Statement::Builder::getTokens() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Statement::Builder::setTokens( ::capnp::List< ::capnp::compiler::Token>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Token>::Builder Statement::Builder::initTokens(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Statement::Builder::adoptTokens( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>> Statement::Builder::disownTokens() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Statement::Reader::isLine() const { + return which() == Statement::LINE; +} +inline bool Statement::Builder::isLine() { + return which() == Statement::LINE; +} +inline ::capnp::Void Statement::Reader::getLine() const { + KJ_IREQUIRE((which() == Statement::LINE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Statement::Builder::getLine() { + KJ_IREQUIRE((which() == Statement::LINE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Statement::Builder::setLine( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Statement::LINE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Statement::Reader::isBlock() const { + return which() == Statement::BLOCK; +} +inline bool Statement::Builder::isBlock() { + return which() == Statement::BLOCK; +} +inline bool Statement::Reader::hasBlock() const { + if (which() != Statement::BLOCK) return false; + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Statement::Builder::hasBlock() { + if (which() != Statement::BLOCK) return false; + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Reader Statement::Reader::getBlock() const { + KJ_IREQUIRE((which() == Statement::BLOCK), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Builder Statement::Builder::getBlock() { + KJ_IREQUIRE((which() == Statement::BLOCK), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Statement::Builder::setBlock( ::capnp::List< ::capnp::compiler::Statement>::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Statement::BLOCK); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Builder Statement::Builder::initBlock(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Statement::BLOCK); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Statement::Builder::adoptBlock( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Statement::BLOCK); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>> Statement::Builder::disownBlock() { + KJ_IREQUIRE((which() == Statement::BLOCK), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Statement::Reader::hasDocComment() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Statement::Builder::hasDocComment() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Statement::Reader::getDocComment() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Statement::Builder::getDocComment() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Statement::Builder::setDocComment( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Statement::Builder::initDocComment(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), size); +} +inline void Statement::Builder::adoptDocComment( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Statement::Builder::disownDocComment() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Statement::Reader::getStartByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Statement::Builder::getStartByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Statement::Builder::setStartByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Statement::Reader::getEndByte() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Statement::Builder::getEndByte() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Statement::Builder::setEndByte( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool LexedTokens::Reader::hasTokens() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool LexedTokens::Builder::hasTokens() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Token>::Reader LexedTokens::Reader::getTokens() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Token>::Builder LexedTokens::Builder::getTokens() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void LexedTokens::Builder::setTokens( ::capnp::List< ::capnp::compiler::Token>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Token>::Builder LexedTokens::Builder::initTokens(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void LexedTokens::Builder::adoptTokens( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Token>> LexedTokens::Builder::disownTokens() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Token>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool LexedStatements::Reader::hasStatements() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool LexedStatements::Builder::hasStatements() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Reader LexedStatements::Reader::getStatements() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Builder LexedStatements::Builder::getStatements() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void LexedStatements::Builder::setStatements( ::capnp::List< ::capnp::compiler::Statement>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::compiler::Statement>::Builder LexedStatements::Builder::initStatements(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void LexedStatements::Builder::adoptStatements( + ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::compiler::Statement>> LexedStatements::Builder::disownStatements() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::compiler::Statement>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_a73956d2621fc3ee_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/lexer.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,102 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPILER_LEXER_H_ +#define CAPNP_COMPILER_LEXER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include +#include "error-reporter.h" + +namespace capnp { +namespace compiler { + +bool lex(kj::ArrayPtr input, LexedStatements::Builder result, + ErrorReporter& errorReporter); +bool lex(kj::ArrayPtr input, LexedTokens::Builder result, ErrorReporter& errorReporter); +// Lex the given source code, placing the results in `result`. Returns true if there +// were no errors, false if there were. Even when errors are present, the file may have partial +// content which can be fed into later stages of parsing in order to find more errors. +// +// There are two versions, one that parses a list of statements, and one which just parses tokens +// that might form a part of one statement. In other words, in the later case, the input should +// not contain semicolons or curly braces, unless they are in string literals of course. + +class Lexer { + // Advanced lexer interface. This interface exposes the inner parsers so that you can embed them + // into your own parsers. + +public: + Lexer(Orphanage orphanage, ErrorReporter& errorReporter); + // `orphanage` is used to allocate Cap'n Proto message objects in the result. `inputStart` is + // a pointer to the beginning of the input, used to compute byte offsets. + + ~Lexer() noexcept(false); + + class ParserInput: public kj::parse::IteratorInput { + // Like IteratorInput except that positions are measured as byte offsets + // rather than pointers. + + public: + ParserInput(const char* begin, const char* end) + : IteratorInput(begin, end), begin(begin) {} + explicit ParserInput(ParserInput& parent) + : IteratorInput(parent), begin(parent.begin) {} + + inline uint32_t getBest() { + return IteratorInput::getBest() - begin; + } + inline uint32_t getPosition() { + return IteratorInput::getPosition() - begin; + } + + private: + const char* begin; + }; + + template + using Parser = kj::parse::ParserRef; + + struct Parsers { + Parser> emptySpace; + Parser> token; + Parser>> tokenSequence; + Parser> statement; + Parser>> statementSequence; + }; + + const Parsers& getParsers() { return parsers; } + +private: + Orphanage orphanage; + kj::Arena arena; + Parsers parsers; +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_LEXER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/md5-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/md5-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,63 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "md5.h" +#include + +namespace capnp { +namespace compiler { +namespace { + +static kj::String doMd5(kj::StringPtr text) { + Md5 md5; + md5.update(text); + return kj::str(md5.finishAsHex().cStr()); +} + +TEST(Md5, Sum) { + EXPECT_STREQ("acbd18db4cc2f85cedef654fccc4a4d8", doMd5("foo").cStr()); + EXPECT_STREQ("37b51d194a7513e45b56f6524f2d51f2", doMd5("bar").cStr()); + EXPECT_STREQ("3858f62230ac3c915f300c664312c63f", doMd5("foobar").cStr()); + + { + Md5 md5; + md5.update("foo"); + md5.update("bar"); + EXPECT_STREQ("3858f62230ac3c915f300c664312c63f", md5.finishAsHex().cStr()); + } + + EXPECT_STREQ("ebf2442d167a30ca4453f99abd8cddf4", doMd5( + "Hello, this is a long string that is more than 64 bytes because the md5 code uses a " + "buffer of 64 bytes.").cStr()); + + { + Md5 md5; + md5.update("Hello, this is a long string "); + md5.update("that is more than 64 bytes "); + md5.update("because the md5 code uses a "); + md5.update("buffer of 64 bytes."); + EXPECT_STREQ("ebf2442d167a30ca4453f99abd8cddf4", md5.finishAsHex().cStr()); + } +} + +} // namespace +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/md5.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/md5.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,324 @@ +// This file was modified by Kenton Varda from code placed in the public domain. +// The code, which was originally C, was modified to give it a C++ interface. +// The original code bore the following notice: + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include "md5.h" +#include +#include + +namespace capnp { +namespace compiler { + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx.block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx.block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +const kj::byte* Md5::body(const kj::byte* ptr, size_t size) +{ + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + a = ctx.a; + b = ctx.b; + c = ctx.c; + d = ctx.d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx.a = a; + ctx.b = b; + ctx.c = c; + ctx.d = d; + + return ptr; +} + +Md5::Md5() +{ + ctx.a = 0x67452301; + ctx.b = 0xefcdab89; + ctx.c = 0x98badcfe; + ctx.d = 0x10325476; + + ctx.lo = 0; + ctx.hi = 0; +} + +void Md5::update(kj::ArrayPtr dataArray) +{ + KJ_REQUIRE(!finished, "already called Md5::finish()"); + + const kj::byte* data = dataArray.begin(); + unsigned long size = dataArray.size(); + + MD5_u32plus saved_lo; + unsigned long used, free; + + saved_lo = ctx.lo; + if ((ctx.lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx.hi++; + ctx.hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + free = 64 - used; + + if (size < free) { + memcpy(&ctx.buffer[used], data, size); + return; + } + + memcpy(&ctx.buffer[used], data, free); + data = data + free; + size -= free; + body(ctx.buffer, 64); + } + + if (size >= 64) { + data = body(data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx.buffer, data, size); +} + +kj::ArrayPtr Md5::finish() +{ + if (!finished) { + unsigned long used, free; + + used = ctx.lo & 0x3f; + + ctx.buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + memset(&ctx.buffer[used], 0, free); + body(ctx.buffer, 64); + used = 0; + free = 64; + } + + memset(&ctx.buffer[used], 0, free - 8); + + ctx.lo <<= 3; + ctx.buffer[56] = ctx.lo; + ctx.buffer[57] = ctx.lo >> 8; + ctx.buffer[58] = ctx.lo >> 16; + ctx.buffer[59] = ctx.lo >> 24; + ctx.buffer[60] = ctx.hi; + ctx.buffer[61] = ctx.hi >> 8; + ctx.buffer[62] = ctx.hi >> 16; + ctx.buffer[63] = ctx.hi >> 24; + + body(ctx.buffer, 64); + + // Store final result into ctx.buffer. + ctx.buffer[0] = ctx.a; + ctx.buffer[1] = ctx.a >> 8; + ctx.buffer[2] = ctx.a >> 16; + ctx.buffer[3] = ctx.a >> 24; + ctx.buffer[4] = ctx.b; + ctx.buffer[5] = ctx.b >> 8; + ctx.buffer[6] = ctx.b >> 16; + ctx.buffer[7] = ctx.b >> 24; + ctx.buffer[8] = ctx.c; + ctx.buffer[9] = ctx.c >> 8; + ctx.buffer[10] = ctx.c >> 16; + ctx.buffer[11] = ctx.c >> 24; + ctx.buffer[12] = ctx.d; + ctx.buffer[13] = ctx.d >> 8; + ctx.buffer[14] = ctx.d >> 16; + ctx.buffer[15] = ctx.d >> 24; + + finished = true; + } + + return kj::arrayPtr(ctx.buffer, 16); +} + +kj::StringPtr Md5::finishAsHex() { + static const char hexDigits[] = "0123456789abcdef"; + + kj::ArrayPtr bytes = finish(); + + char* chars = reinterpret_cast(ctx.buffer + 16); + char* pos = chars; + for (auto byte: bytes) { + *pos++ = hexDigits[byte / 16]; + *pos++ = hexDigits[byte % 16]; + } + *pos++ = '\0'; + + return kj::StringPtr(chars, 32); +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/md5.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/md5.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,80 @@ +// This file was modified by Kenton Varda from code placed in the public domain. +// The code, which was originally C, was modified to give it a C++ interface. +// The original code bore the following notice: + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +// TODO(someday): Put in KJ? + +#ifndef CAPNP_COMPILER_MD5_H +#define CAPNP_COMPILER_MD5_H + +#include +#include + +namespace capnp { +namespace compiler { + +class Md5 { +public: + Md5(); + + void update(kj::ArrayPtr data); + inline void update(kj::ArrayPtr data) { + return update(data.asBytes()); + } + inline void update(kj::StringPtr data) { + return update(data.asArray()); + } + inline void update(const char* data) { + return update(kj::StringPtr(data)); + } + + kj::ArrayPtr finish(); + kj::StringPtr finishAsHex(); + +private: + /* Any 32-bit or wider unsigned integer data type will do */ + typedef unsigned int MD5_u32plus; + + bool finished = false; + + typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + kj::byte buffer[64]; + MD5_u32plus block[16]; + } MD5_CTX; + + MD5_CTX ctx; + + const kj::byte* body(const kj::byte* ptr, size_t size); +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_MD5_H diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/module-loader.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/module-loader.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,379 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "module-loader.h" +#include "lexer.h" +#include "parser.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#endif + +namespace capnp { +namespace compiler { + +namespace { + +class MmapDisposer: public kj::ArrayDisposer { +protected: + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const { +#if _WIN32 + KJ_ASSERT(UnmapViewOfFile(firstElement)); +#else + munmap(firstElement, elementSize * elementCount); +#endif + } +}; + +KJ_CONSTEXPR(static const) MmapDisposer mmapDisposer = MmapDisposer(); + +kj::Array mmapForRead(kj::StringPtr filename) { + int fd; + // We already established that the file exists, so this should not fail. + KJ_SYSCALL(fd = open(filename.cStr(), O_RDONLY), filename); + kj::AutoCloseFd closer(fd); + + struct stat stats; + KJ_SYSCALL(fstat(fd, &stats)); + + if (S_ISREG(stats.st_mode)) { + if (stats.st_size == 0) { + // mmap()ing zero bytes will fail. + return nullptr; + } + + // Regular file. Just mmap() it. +#if _WIN32 + HANDLE handle = reinterpret_cast(_get_osfhandle(fd)); + KJ_ASSERT(handle != INVALID_HANDLE_VALUE); + HANDLE mappingHandle = CreateFileMapping( + handle, NULL, PAGE_READONLY, 0, stats.st_size, NULL); + KJ_ASSERT(mappingHandle != INVALID_HANDLE_VALUE); + KJ_DEFER(KJ_ASSERT(CloseHandle(mappingHandle))); + const void* mapping = MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, stats.st_size); +#else // _WIN32 + const void* mapping = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) { + KJ_FAIL_SYSCALL("mmap", errno, filename); + } +#endif // _WIN32, else + + return kj::Array( + reinterpret_cast(mapping), stats.st_size, mmapDisposer); + } else { + // This could be a stream of some sort, like a pipe. Fall back to read(). + // TODO(cleanup): This does a lot of copies. Not sure I care. + kj::Vector data(8192); + + byte buffer[4096]; + for (;;) { + kj::miniposix::ssize_t n; + KJ_SYSCALL(n = read(fd, buffer, sizeof(buffer))); + if (n == 0) break; + data.addAll(buffer, buffer + n); + } + + return data.releaseAsArray(); + } +} + +static char* canonicalizePath(char* path) { + // Taken from some old C code of mine. + + // Preconditions: + // - path has already been determined to be relative, perhaps because the pointer actually points + // into the middle of some larger path string, in which case it must point to the character + // immediately after a '/'. + + // Invariants: + // - src points to the beginning of a path component. + // - dst points to the location where the path component should end up, if it is not special. + // - src == path or src[-1] == '/'. + // - dst == path or dst[-1] == '/'. + + char* src = path; + char* dst = path; + char* locked = dst; // dst cannot backtrack past this + char* partEnd; + bool hasMore; + + for (;;) { + while (*src == '/') { + // Skip duplicate slash. + ++src; + } + + partEnd = strchr(src, '/'); + hasMore = partEnd != NULL; + if (hasMore) { + *partEnd = '\0'; + } else { + partEnd = src + strlen(src); + } + + if (strcmp(src, ".") == 0) { + // Skip it. + } else if (strcmp(src, "..") == 0) { + if (dst > locked) { + // Backtrack over last path component. + --dst; + while (dst > locked && dst[-1] != '/') --dst; + } else { + locked += 3; + goto copy; + } + } else { + // Copy if needed. + copy: + if (dst < src) { + memmove(dst, src, partEnd - src); + dst += partEnd - src; + } else { + dst = partEnd; + } + *dst++ = '/'; + } + + if (hasMore) { + src = partEnd + 1; + } else { + // Oops, we have to remove the trailing '/'. + if (dst == path) { + // Oops, there is no trailing '/'. We have to return ".". + strcpy(path, "."); + return path + 1; + } else { + // Remove the trailing '/'. Note that this means that opening the file will work even + // if it is not a directory, where normally it should fail on non-directories when a + // trailing '/' is present. If this is a problem, we need to add some sort of special + // handling for this case where we stat() it separately to check if it is a directory, + // because Ekam findInput will not accept a trailing '/'. + --dst; + *dst = '\0'; + return dst; + } + } + } +} + +kj::String canonicalizePath(kj::StringPtr path) { + KJ_STACK_ARRAY(char, result, path.size() + 1, 128, 512); + strcpy(result.begin(), path.begin()); + + char* start = path.startsWith("/") ? result.begin() + 1 : result.begin(); + char* end = canonicalizePath(start); + return kj::heapString(result.slice(0, end - result.begin())); +} + +kj::String catPath(kj::StringPtr base, kj::StringPtr add) { + if (add.size() > 0 && add[0] == '/') { + return kj::heapString(add); + } + + const char* pos = base.end(); + while (pos > base.begin() && pos[-1] != '/') { + --pos; + } + + return kj::str(base.slice(0, pos - base.begin()), add); +} + +} // namespace + + +class ModuleLoader::Impl { +public: + Impl(GlobalErrorReporter& errorReporter): errorReporter(errorReporter) {} + + void addImportPath(kj::String path) { + searchPath.add(kj::heapString(kj::mv(path))); + } + + kj::Maybe loadModule(kj::StringPtr localName, kj::StringPtr sourceName); + kj::Maybe loadModuleFromSearchPath(kj::StringPtr sourceName); + kj::Maybe> readEmbed(kj::StringPtr localName, kj::StringPtr sourceName); + kj::Maybe> readEmbedFromSearchPath(kj::StringPtr sourceName); + GlobalErrorReporter& getErrorReporter() { return errorReporter; } + +private: + GlobalErrorReporter& errorReporter; + kj::Vector searchPath; + std::map> modules; +}; + +class ModuleLoader::ModuleImpl final: public Module { +public: + ModuleImpl(ModuleLoader::Impl& loader, kj::String localName, kj::String sourceName) + : loader(loader), localName(kj::mv(localName)), sourceName(kj::mv(sourceName)) {} + + kj::StringPtr getLocalName() { + return localName; + } + + kj::StringPtr getSourceName() override { + return sourceName; + } + + Orphan loadContent(Orphanage orphanage) override { + kj::Array content = mmapForRead(localName).releaseAsChars(); + + lineBreaks = nullptr; // In case loadContent() is called multiple times. + lineBreaks = lineBreaksSpace.construct(content); + + MallocMessageBuilder lexedBuilder; + auto statements = lexedBuilder.initRoot(); + lex(content, statements, *this); + + auto parsed = orphanage.newOrphan(); + parseFile(statements.getStatements(), parsed.get(), *this); + return parsed; + } + + kj::Maybe importRelative(kj::StringPtr importPath) override { + if (importPath.size() > 0 && importPath[0] == '/') { + return loader.loadModuleFromSearchPath(importPath.slice(1)); + } else { + return loader.loadModule(catPath(localName, importPath), catPath(sourceName, importPath)); + } + } + + kj::Maybe> embedRelative(kj::StringPtr embedPath) override { + if (embedPath.size() > 0 && embedPath[0] == '/') { + return loader.readEmbedFromSearchPath(embedPath.slice(1)); + } else { + return loader.readEmbed(catPath(localName, embedPath), catPath(sourceName, embedPath)); + } + } + + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + auto& lines = *KJ_REQUIRE_NONNULL(lineBreaks, + "Can't report errors until loadContent() is called."); + + loader.getErrorReporter().addError( + localName, lines.toSourcePos(startByte), lines.toSourcePos(endByte), message); + } + + bool hadErrors() override { + return loader.getErrorReporter().hadErrors(); + } + +private: + ModuleLoader::Impl& loader; + kj::String localName; + kj::String sourceName; + + kj::SpaceFor lineBreaksSpace; + kj::Maybe> lineBreaks; +}; + +// ======================================================================================= + +kj::Maybe ModuleLoader::Impl::loadModule( + kj::StringPtr localName, kj::StringPtr sourceName) { + kj::String canonicalLocalName = canonicalizePath(localName); + kj::String canonicalSourceName = canonicalizePath(sourceName); + + auto iter = modules.find(canonicalLocalName); + if (iter != modules.end()) { + // Return existing file. + return *iter->second; + } + + if (access(canonicalLocalName.cStr(), F_OK) < 0) { + // No such file. + return nullptr; + } + + auto module = kj::heap( + *this, kj::mv(canonicalLocalName), kj::mv(canonicalSourceName)); + auto& result = *module; + modules.insert(std::make_pair(result.getLocalName(), kj::mv(module))); + return result; +} + +kj::Maybe ModuleLoader::Impl::loadModuleFromSearchPath(kj::StringPtr sourceName) { + for (auto& search: searchPath) { + kj::String candidate = kj::str(search, "/", sourceName); + char* end = canonicalizePath(candidate.begin() + (candidate[0] == '/')); + + KJ_IF_MAYBE(module, loadModule( + kj::heapString(candidate.slice(0, end - candidate.begin())), sourceName)) { + return *module; + } + } + return nullptr; +} + +kj::Maybe> ModuleLoader::Impl::readEmbed( + kj::StringPtr localName, kj::StringPtr sourceName) { + kj::String canonicalLocalName = canonicalizePath(localName); + kj::String canonicalSourceName = canonicalizePath(sourceName); + + if (access(canonicalLocalName.cStr(), F_OK) < 0) { + // No such file. + return nullptr; + } + + return mmapForRead(localName); +} + +kj::Maybe> ModuleLoader::Impl::readEmbedFromSearchPath( + kj::StringPtr sourceName) { + for (auto& search: searchPath) { + kj::String candidate = kj::str(search, "/", sourceName); + char* end = canonicalizePath(candidate.begin() + (candidate[0] == '/')); + + KJ_IF_MAYBE(module, readEmbed( + kj::heapString(candidate.slice(0, end - candidate.begin())), sourceName)) { + return kj::mv(*module); + } + } + return nullptr; +} + +// ======================================================================================= + +ModuleLoader::ModuleLoader(GlobalErrorReporter& errorReporter) + : impl(kj::heap(errorReporter)) {} +ModuleLoader::~ModuleLoader() noexcept(false) {} + +void ModuleLoader::addImportPath(kj::String path) { impl->addImportPath(kj::mv(path)); } + +kj::Maybe ModuleLoader::loadModule(kj::StringPtr localName, kj::StringPtr sourceName) { + return impl->loadModule(localName, sourceName); +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/module-loader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/module-loader.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,65 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPILER_MODULE_LOADER_H_ +#define CAPNP_COMPILER_MODULE_LOADER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "compiler.h" +#include "error-reporter.h" +#include +#include +#include + +namespace capnp { +namespace compiler { + +class ModuleLoader { +public: + explicit ModuleLoader(GlobalErrorReporter& errorReporter); + // Create a ModuleLoader that reports error messages to the given reporter. + + KJ_DISALLOW_COPY(ModuleLoader); + + ~ModuleLoader() noexcept(false); + + void addImportPath(kj::String path); + // Add a directory to the list of paths that is searched for imports that start with a '/'. + + kj::Maybe loadModule(kj::StringPtr localName, kj::StringPtr sourceName); + // Tries to load the module with the given filename. `localName` is the path to the file on + // disk (as you'd pass to open(2)), and `sourceName` is the canonical name it should be given + // in the schema (this is used e.g. to decide output file locations). Often, these are the same. + +private: + class Impl; + kj::Own impl; + + class ModuleImpl; +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_MODULE_LOADER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/node-translator.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/node-translator.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,3208 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "node-translator.h" +#include "parser.h" // only for generateGroupId() +#include +#include +#include +#include +#include +#include + +namespace capnp { +namespace compiler { + +bool shouldDetectIssue344() { + return getenv("CAPNP_IGNORE_ISSUE_344") == nullptr; +} + +class NodeTranslator::StructLayout { + // Massive, disgusting class which implements the layout algorithm, which decides the offset + // for each field. + +public: + template + struct HoleSet { + inline HoleSet(): holes{0, 0, 0, 0, 0, 0} {} + + // Represents a set of "holes" within a segment of allocated space, up to one hole of each + // power-of-two size between 1 bit and 32 bits. + // + // The amount of "used" space in a struct's data segment can always be represented as a + // combination of a word count and a HoleSet. The HoleSet represents the space lost to + // "padding". + // + // There can never be more than one hole of any particular size. Why is this? Well, consider + // that every data field has a power-of-two size, every field must be aligned to a multiple of + // its size, and the maximum size of a single field is 64 bits. If we need to add a new field + // of N bits, there are two possibilities: + // 1. A hole of size N or larger exists. In this case, we find the smallest hole that is at + // least N bits. Let's say that that hole has size M. We allocate the first N bits of the + // hole to the new field. The remaining M - N bits become a series of holes of sizes N*2, + // N*4, ..., M / 2. We know no holes of these sizes existed before because we chose M to be + // the smallest available hole larger than N. So, there is still no more than one hole of + // each size, and no hole larger than any hole that existed previously. + // 2. No hole equal or larger N exists. In that case we extend the data section's size by one + // word, creating a new 64-bit hole at the end. We then allocate N bits from it, creating + // a series of holes between N and 64 bits, as described in point (1). Thus, again, there + // is still at most one hole of each size, and the largest hole is 32 bits. + + UIntType holes[6]; + // The offset of each hole as a multiple of its size. A value of zero indicates that no hole + // exists. Notice that it is impossible for any actual hole to have an offset of zero, because + // the first field allocated is always placed at the very beginning of the section. So either + // the section has a size of zero (in which case there are no holes), or offset zero is + // already allocated and therefore cannot be a hole. + + kj::Maybe tryAllocate(UIntType lgSize) { + // Try to find space for a field of size 2^lgSize within the set of holes. If found, + // remove it from the holes, and return its offset (as a multiple of its size). If there + // is no such space, returns zero (no hole can be at offset zero, as explained above). + + if (lgSize >= kj::size(holes)) { + return nullptr; + } else if (holes[lgSize] != 0) { + UIntType result = holes[lgSize]; + holes[lgSize] = 0; + return result; + } else { + KJ_IF_MAYBE(next, tryAllocate(lgSize + 1)) { + UIntType result = *next * 2; + holes[lgSize] = result + 1; + return result; + } else { + return nullptr; + } + } + } + + uint assertHoleAndAllocate(UIntType lgSize) { + KJ_ASSERT(holes[lgSize] != 0); + uint result = holes[lgSize]; + holes[lgSize] = 0; + return result; + } + + void addHolesAtEnd(UIntType lgSize, UIntType offset, + UIntType limitLgSize = sizeof(HoleSet::holes) / sizeof(HoleSet::holes[0])) { + // Add new holes of progressively larger sizes in the range [lgSize, limitLgSize) starting + // from the given offset. The idea is that you just allocated an lgSize-sized field from + // an limitLgSize-sized space, such as a newly-added word on the end of the data segment. + + KJ_DREQUIRE(limitLgSize <= kj::size(holes)); + + while (lgSize < limitLgSize) { + KJ_DREQUIRE(holes[lgSize] == 0); + KJ_DREQUIRE(offset % 2 == 1); + holes[lgSize] = offset; + ++lgSize; + offset = (offset + 1) / 2; + } + } + + bool tryExpand(UIntType oldLgSize, uint oldOffset, uint expansionFactor) { + // Try to expand the value at the given location by combining it with subsequent holes, so + // as to expand the location to be 2^expansionFactor times the size that it started as. + // (In other words, the new lgSize is oldLgSize + expansionFactor.) + + if (expansionFactor == 0) { + // No expansion requested. + return true; + } + if (holes[oldLgSize] != oldOffset + 1) { + // The space immediately after the location is not a hole. + return false; + } + + // We can expand the location by one factor by combining it with a hole. Try to further + // expand from there to the number of factors requested. + if (tryExpand(oldLgSize + 1, oldOffset >> 1, expansionFactor - 1)) { + // Success. Consume the hole. + holes[oldLgSize] = 0; + return true; + } else { + return false; + } + } + + kj::Maybe smallestAtLeast(uint size) { + // Return the size of the smallest hole that is equal to or larger than the given size. + + for (uint i = size; i < kj::size(holes); i++) { + if (holes[i] != 0) { + return i; + } + } + return nullptr; + } + + uint getFirstWordUsed() { + // Computes the lg of the amount of space used in the first word of the section. + + // If there is a 32-bit hole with a 32-bit offset, no more than the first 32 bits are used. + // If no more than the first 32 bits are used, and there is a 16-bit hole with a 16-bit + // offset, then no more than the first 16 bits are used. And so on. + for (uint i = kj::size(holes); i > 0; i--) { + if (holes[i - 1] != 1) { + return i; + } + } + return 0; + } + }; + + struct StructOrGroup { + // Abstract interface for scopes in which fields can be added. + + virtual void addVoid() = 0; + virtual uint addData(uint lgSize) = 0; + virtual uint addPointer() = 0; + virtual bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) = 0; + // Try to expand the given previously-allocated space by 2^expansionFactor. Succeeds -- + // returning true -- if the following space happens to be empty, making this expansion possible. + // Otherwise, returns false. + }; + + struct Top: public StructOrGroup { + uint dataWordCount = 0; + uint pointerCount = 0; + // Size of the struct so far. + + HoleSet holes; + + void addVoid() override {} + + uint addData(uint lgSize) override { + KJ_IF_MAYBE(hole, holes.tryAllocate(lgSize)) { + return *hole; + } else { + uint offset = dataWordCount++ << (6 - lgSize); + holes.addHolesAtEnd(lgSize, offset + 1); + return offset; + } + } + + uint addPointer() override { + return pointerCount++; + } + + bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) override { + return holes.tryExpand(oldLgSize, oldOffset, expansionFactor); + } + + Top() = default; + KJ_DISALLOW_COPY(Top); + }; + + struct Union { + struct DataLocation { + uint lgSize; + uint offset; + + bool tryExpandTo(Union& u, uint newLgSize) { + if (newLgSize <= lgSize) { + return true; + } else if (u.parent.tryExpandData(lgSize, offset, newLgSize - lgSize)) { + offset >>= (newLgSize - lgSize); + lgSize = newLgSize; + return true; + } else { + return false; + } + } + }; + + StructOrGroup& parent; + uint groupCount = 0; + kj::Maybe discriminantOffset; + kj::Vector dataLocations; + kj::Vector pointerLocations; + + inline Union(StructOrGroup& parent): parent(parent) {} + KJ_DISALLOW_COPY(Union); + + uint addNewDataLocation(uint lgSize) { + // Add a whole new data location to the union with the given size. + + uint offset = parent.addData(lgSize); + dataLocations.add(DataLocation { lgSize, offset }); + return offset; + } + + uint addNewPointerLocation() { + // Add a whole new pointer location to the union with the given size. + + return pointerLocations.add(parent.addPointer()); + } + + void newGroupAddingFirstMember() { + if (++groupCount == 2) { + addDiscriminant(); + } + } + + bool addDiscriminant() { + if (discriminantOffset == nullptr) { + discriminantOffset = parent.addData(4); // 2^4 = 16 bits + return true; + } else { + return false; + } + } + }; + + struct Group final: public StructOrGroup { + public: + class DataLocationUsage { + public: + DataLocationUsage(): isUsed(false) {} + explicit DataLocationUsage(uint lgSize): isUsed(true), lgSizeUsed(lgSize) {} + + kj::Maybe smallestHoleAtLeast(Union::DataLocation& location, uint lgSize) { + // Find the smallest single hole that is at least the given size. This is used to find the + // optimal place to allocate each field -- it is placed in the smallest slot where it fits, + // to reduce fragmentation. Returns the size of the hole, if found. + + if (!isUsed) { + // The location is effectively one big hole. + if (lgSize <= location.lgSize) { + return location.lgSize; + } else { + return nullptr; + } + } else if (lgSize >= lgSizeUsed) { + // Requested size is at least our current usage, so clearly won't fit in any current + // holes, but if the location's size is larger than what we're using, we'd be able to + // expand. + if (lgSize < location.lgSize) { + return lgSize; + } else { + return nullptr; + } + } else KJ_IF_MAYBE(result, holes.smallestAtLeast(lgSize)) { + // There's a hole. + return *result; + } else { + // The requested size is smaller than what we're already using, but there are no holes + // available. If we could double our size, then we could allocate in the new space. + + if (lgSizeUsed < location.lgSize) { + // We effectively create a new hole the same size as the current usage. + return lgSizeUsed; + } else { + return nullptr; + } + } + } + + uint allocateFromHole(Group& group, Union::DataLocation& location, uint lgSize) { + // Allocate the given space from an existing hole, given smallestHoleAtLeast() already + // returned non-null indicating such a hole exists. + + uint result; + + if (!isUsed) { + // The location is totally unused, so just allocate from the beginning. + KJ_DASSERT(lgSize <= location.lgSize, "Did smallestHoleAtLeast() really find a hole?"); + result = 0; + isUsed = true; + lgSizeUsed = lgSize; + } else if (lgSize >= lgSizeUsed) { + // Requested size is at least our current usage, so clearly won't fit in any holes. + // We must expand to double the requested size, and return the second half. + KJ_DASSERT(lgSize < location.lgSize, "Did smallestHoleAtLeast() really find a hole?"); + holes.addHolesAtEnd(lgSizeUsed, 1, lgSize); + lgSizeUsed = lgSize + 1; + result = 1; + } else KJ_IF_MAYBE(hole, holes.tryAllocate(lgSize)) { + // Found a hole. + result = *hole; + } else { + // The requested size is smaller than what we're using so far, but didn't fit in a + // hole. We should double our "used" size, then allocate from the new space. + KJ_DASSERT(lgSizeUsed < location.lgSize, + "Did smallestHoleAtLeast() really find a hole?"); + result = 1 << (lgSizeUsed - lgSize); + holes.addHolesAtEnd(lgSize, result + 1, lgSizeUsed); + lgSizeUsed += 1; + } + + // Adjust the offset according to the location's offset before returning. + uint locationOffset = location.offset << (location.lgSize - lgSize); + return locationOffset + result; + } + + kj::Maybe tryAllocateByExpanding( + Group& group, Union::DataLocation& location, uint lgSize) { + // Attempt to allocate the given size by requesting that the parent union expand this + // location to fit. This is used if smallestHoleAtLeast() already determined that there + // are no holes that would fit, so we don't bother checking that. + + if (!isUsed) { + if (location.tryExpandTo(group.parent, lgSize)) { + isUsed = true; + lgSizeUsed = lgSize; + return location.offset << (location.lgSize - lgSize); + } else { + return nullptr; + } + } else { + uint newSize = kj::max(lgSizeUsed, lgSize) + 1; + if (tryExpandUsage(group, location, newSize, true)) { + uint result = KJ_ASSERT_NONNULL(holes.tryAllocate(lgSize)); + uint locationOffset = location.offset << (location.lgSize - lgSize); + return locationOffset + result; + } else { + return nullptr; + } + } + } + + bool tryExpand(Group& group, Union::DataLocation& location, + uint oldLgSize, uint oldOffset, uint expansionFactor) { + if (oldOffset == 0 && lgSizeUsed == oldLgSize) { + // This location contains exactly the requested data, so just expand the whole thing. + return tryExpandUsage(group, location, oldLgSize + expansionFactor, false); + } else { + // This location contains the requested data plus other stuff. Therefore the data cannot + // possibly expand past the end of the space we've already marked used without either + // overlapping with something else or breaking alignment rules. We only have to combine + // it with holes. + return holes.tryExpand(oldLgSize, oldOffset, expansionFactor); + } + } + + private: + bool isUsed; + // Whether or not this location has been used at all by the group. + + uint8_t lgSizeUsed; + // Amount of space from the location which is "used". This is the minimum size needed to + // cover all allocated space. Only meaningful if `isUsed` is true. + + HoleSet holes; + // Indicates holes present in the space designated by `lgSizeUsed`. The offsets in this + // HoleSet are relative to the beginning of this particular data location, not the beginning + // of the struct. + + bool tryExpandUsage(Group& group, Union::DataLocation& location, uint desiredUsage, + bool newHoles) { + if (desiredUsage > location.lgSize) { + // Need to expand the underlying slot. + if (!location.tryExpandTo(group.parent, desiredUsage)) { + return false; + } + } + + // Underlying slot is big enough, so expand our size and update holes. + if (newHoles) { + holes.addHolesAtEnd(lgSizeUsed, 1, desiredUsage); + } else if (shouldDetectIssue344()) { + // Unfortunately, Cap'n Proto 0.5.x and below would always call addHolesAtEnd(), which + // was the wrong thing to do when called from tryExpand(), which itself is only called + // in cases involving unions nested in other unions. The bug could lead to multiple + // fields in a group incorrectly being assigned overlapping offsets. Although the bug + // is now fixed by adding the `newHoles` parameter, this silently breaks + // backwards-compatibilty with affected schemas. Therefore, for now, we throw an + // exception to alert developers of the problem. + // + // TODO(cleanup): Once sufficient time has elapsed, remove this assert. + KJ_FAIL_ASSERT("Bad news: Cap'n Proto 0.5.x and previous contained a bug which would cause this schema to be compiled incorrectly. Please see: https://github.com/sandstorm-io/capnproto/issues/344"); + } + lgSizeUsed = desiredUsage; + return true; + } + }; + + Union& parent; + + kj::Vector parentDataLocationUsage; + // Vector corresponding to the parent union's `dataLocations`, indicating how much of each + // location has already been allocated. + + uint parentPointerLocationUsage = 0; + // Number of parent's pointer locations that have been used by this group. + + bool hasMembers = false; + + inline Group(Union& parent): parent(parent) {} + KJ_DISALLOW_COPY(Group); + + void addMember() { + if (!hasMembers) { + hasMembers = true; + parent.newGroupAddingFirstMember(); + } + } + + void addVoid() override { + addMember(); + + // Make sure that if this is a member of a union which is in turn a member of another union, + // that we let the outer union know that a field is being added, even though it is a + // zero-size field. This is important because the union needs to allocate its discriminant + // just before its second member is added. + parent.parent.addVoid(); + } + + uint addData(uint lgSize) override { + addMember(); + + uint bestSize = kj::maxValue; + kj::Maybe bestLocation = nullptr; + + for (uint i = 0; i < parent.dataLocations.size(); i++) { + // If we haven't seen this DataLocation yet, add a corresponding DataLocationUsage. + if (parentDataLocationUsage.size() == i) { + parentDataLocationUsage.add(); + } + + auto& usage = parentDataLocationUsage[i]; + KJ_IF_MAYBE(hole, usage.smallestHoleAtLeast(parent.dataLocations[i], lgSize)) { + if (*hole < bestSize) { + bestSize = *hole; + bestLocation = i; + } + } + } + + KJ_IF_MAYBE(best, bestLocation) { + return parentDataLocationUsage[*best].allocateFromHole( + *this, parent.dataLocations[*best], lgSize); + } + + // There are no holes at all in the union big enough to fit this field. Go back through all + // of the locations and attempt to expand them to fit. + for (uint i = 0; i < parent.dataLocations.size(); i++) { + KJ_IF_MAYBE(result, parentDataLocationUsage[i].tryAllocateByExpanding( + *this, parent.dataLocations[i], lgSize)) { + return *result; + } + } + + // Couldn't find any space in the existing locations, so add a new one. + uint result = parent.addNewDataLocation(lgSize); + parentDataLocationUsage.add(lgSize); + return result; + } + + uint addPointer() override { + addMember(); + + if (parentPointerLocationUsage < parent.pointerLocations.size()) { + return parent.pointerLocations[parentPointerLocationUsage++]; + } else { + parentPointerLocationUsage++; + return parent.addNewPointerLocation(); + } + } + + bool tryExpandData(uint oldLgSize, uint oldOffset, uint expansionFactor) override { + bool mustFail = false; + if (oldLgSize + expansionFactor > 6 || + (oldOffset & ((1 << expansionFactor) - 1)) != 0) { + // Expansion is not possible because the new size is too large or the offset is not + // properly-aligned. + + // Unfortunately, Cap'n Proto 0.5.x and prior forgot to "return false" here, instead + // continuing to execute the rest of the method. In most cases, the method failed later + // on, causing no harm. But, in cases where the method later succeeded, it probably + // led to bogus layouts. We cannot simply add the return statement now as this would + // silently break backwards-compatibility with affected schemas. Instead, we detect the + // problem and throw an exception. + // + // TODO(cleanup): Once sufficient time has elapsed, switch to "return false;" here. + if (shouldDetectIssue344()) { + mustFail = true; + } else { + return false; + } + } + + for (uint i = 0; i < parentDataLocationUsage.size(); i++) { + auto& location = parent.dataLocations[i]; + if (location.lgSize >= oldLgSize && + oldOffset >> (location.lgSize - oldLgSize) == location.offset) { + // The location we're trying to expand is a subset of this data location. + auto& usage = parentDataLocationUsage[i]; + + // Adjust the offset to be only within this location. + uint localOldOffset = oldOffset - (location.offset << (location.lgSize - oldLgSize)); + + // Try to expand. + bool result = usage.tryExpand( + *this, location, oldLgSize, localOldOffset, expansionFactor); + if (mustFail && result) { + KJ_FAIL_ASSERT("Bad news: Cap'n Proto 0.5.x and previous contained a bug which would cause this schema to be compiled incorrectly. Please see: https://github.com/sandstorm-io/capnproto/issues/344"); + } + return result; + } + } + + KJ_FAIL_ASSERT("Tried to expand field that was never allocated."); + return false; + } + }; + + Top& getTop() { return top; } + +private: + Top top; +}; + +// ======================================================================================= + +class NodeTranslator::BrandedDecl { + // Represents a declaration possibly with generic parameter bindings. + // + // TODO(cleaup): This is too complicated to live here. We should refactor this class and + // BrandScope out into their own file, independent of NodeTranslator. + +public: + inline BrandedDecl(Resolver::ResolvedDecl decl, + kj::Own&& brand, + Expression::Reader source) + : brand(kj::mv(brand)), source(source) { + body.init(kj::mv(decl)); + } + inline BrandedDecl(Resolver::ResolvedParameter variable, Expression::Reader source) + : source(source) { + body.init(kj::mv(variable)); + } + inline BrandedDecl(decltype(nullptr)) {} + + static BrandedDecl implicitMethodParam(uint index) { + // Get a BrandedDecl referring to an implicit method parameter. + // (As a hack, we internally represent this as a ResolvedParameter. Sorry.) + return BrandedDecl(Resolver::ResolvedParameter { 0, index }, Expression::Reader()); + } + + BrandedDecl(BrandedDecl& other); + BrandedDecl(BrandedDecl&& other) = default; + + BrandedDecl& operator=(BrandedDecl& other); + BrandedDecl& operator=(BrandedDecl&& other) = default; + + // TODO(cleanup): A lot of the methods below are actually only called within compileAsType(), + // which was originally a method on NodeTranslator, but now is a method here and thus doesn't + // need these to be public. We should privatize most of these. + + kj::Maybe applyParams(kj::Array params, Expression::Reader subSource); + // Treat the declaration as a generic and apply it to the given parameter list. + + kj::Maybe getMember(kj::StringPtr memberName, Expression::Reader subSource); + // Get a member of this declaration. + + kj::Maybe getKind(); + // Returns the kind of declaration, or null if this is an unbound generic variable. + + template + uint64_t getIdAndFillBrand(InitBrandFunc&& initBrand); + // Returns the type ID of this node. `initBrand` is a zero-arg functor which returns + // schema::Brand::Builder; this will be called if this decl has brand bindings, and + // the returned builder filled in to reflect those bindings. + // + // It is an error to call this when `getKind()` returns null. + + kj::Maybe getListParam(); + // Only if the kind is BUILTIN_LIST: Get the list's type parameter. + + Resolver::ResolvedParameter asVariable(); + // If this is an unbound generic variable (i.e. `getKind()` returns null), return information + // about the variable. + // + // It is an error to call this when `getKind()` does not return null. + + bool compileAsType(ErrorReporter& errorReporter, schema::Type::Builder target); + // Compile this decl to a schema::Type. + + inline void addError(ErrorReporter& errorReporter, kj::StringPtr message) { + errorReporter.addErrorOn(source, message); + } + + Resolver::ResolveResult asResolveResult(uint64_t scopeId, schema::Brand::Builder brandBuilder); + // Reverse this into a ResolveResult. If necessary, use `brandBuilder` to fill in + // ResolvedDecl.brand. + + kj::String toString(); + kj::String toDebugString(); + +private: + Resolver::ResolveResult body; + kj::Own brand; // null if parameter + Expression::Reader source; +}; + +class NodeTranslator::BrandScope: public kj::Refcounted { + // Tracks the brand parameter bindings affecting the current scope. For example, if we are + // interpreting the type expression "Foo(Text).Bar", we would start with the current scopes + // BrandScope, create a new child BrandScope representing "Foo", add the "(Text)" parameter + // bindings to it, then create a further child scope for "Bar". Thus the BrandScope for Bar + // knows that Foo's parameter list has been bound to "(Text)". + // + // TODO(cleanup): This is too complicated to live here. We should refactor this class and + // BrandedDecl out into their own file, independent of NodeTranslator. + +public: + BrandScope(ErrorReporter& errorReporter, uint64_t startingScopeId, + uint startingScopeParamCount, Resolver& startingScope) + : errorReporter(errorReporter), parent(nullptr), leafId(startingScopeId), + leafParamCount(startingScopeParamCount), inherited(true) { + // Create all lexical parent scopes, all with no brand bindings. + KJ_IF_MAYBE(p, startingScope.getParent()) { + parent = kj::refcounted( + errorReporter, p->id, p->genericParamCount, *p->resolver); + } + } + + bool isGeneric() { + if (leafParamCount > 0) return true; + + KJ_IF_MAYBE(p, parent) { + return p->get()->isGeneric(); + } else { + return false; + } + } + + kj::Own push(uint64_t typeId, uint paramCount) { + return kj::refcounted(kj::addRef(*this), typeId, paramCount); + } + + kj::Maybe> setParams( + kj::Array params, Declaration::Which genericType, Expression::Reader source) { + if (this->params.size() != 0) { + errorReporter.addErrorOn(source, "Double-application of generic parameters."); + return nullptr; + } else if (params.size() > leafParamCount) { + if (leafParamCount == 0) { + errorReporter.addErrorOn(source, "Declaration does not accept generic parameters."); + } else { + errorReporter.addErrorOn(source, "Too many generic parameters."); + } + return nullptr; + } else if (params.size() < leafParamCount) { + errorReporter.addErrorOn(source, "Not enough generic parameters."); + return nullptr; + } else { + if (genericType != Declaration::BUILTIN_LIST) { + for (auto& param: params) { + KJ_IF_MAYBE(kind, param.getKind()) { + switch (*kind) { + case Declaration::BUILTIN_LIST: + case Declaration::BUILTIN_TEXT: + case Declaration::BUILTIN_DATA: + case Declaration::BUILTIN_ANY_POINTER: + case Declaration::STRUCT: + case Declaration::INTERFACE: + break; + + default: + param.addError(errorReporter, + "Sorry, only pointer types can be used as generic parameters."); + break; + } + } + } + } + + return kj::refcounted(*this, kj::mv(params)); + } + } + + kj::Own pop(uint64_t newLeafId) { + if (leafId == newLeafId) { + return kj::addRef(*this); + } + KJ_IF_MAYBE(p, parent) { + return (*p)->pop(newLeafId); + } else { + // Looks like we're moving into a whole top-level scope. + return kj::refcounted(errorReporter, newLeafId); + } + } + + kj::Maybe lookupParameter(Resolver& resolver, uint64_t scopeId, uint index) { + // Returns null if the param should be inherited from the client scope. + + if (scopeId == leafId) { + if (index < params.size()) { + return params[index]; + } else if (inherited) { + return nullptr; + } else { + // Unbound and not inherited, so return AnyPointer. + auto decl = resolver.resolveBuiltin(Declaration::BUILTIN_ANY_POINTER); + return BrandedDecl(decl, + evaluateBrand(resolver, decl, List::Reader()), + Expression::Reader()); + } + } else KJ_IF_MAYBE(p, parent) { + return p->get()->lookupParameter(resolver, scopeId, index); + } else { + KJ_FAIL_REQUIRE("scope is not a parent"); + } + } + + kj::Maybe> getParams(uint64_t scopeId) { + // Returns null if params at the requested scope should be inherited from the client scope. + + if (scopeId == leafId) { + if (inherited) { + return nullptr; + } else { + return params.asPtr(); + } + } else KJ_IF_MAYBE(p, parent) { + return p->get()->getParams(scopeId); + } else { + KJ_FAIL_REQUIRE("scope is not a parent"); + } + } + + template + void compile(InitBrandFunc&& initBrand) { + kj::Vector levels; + BrandScope* ptr = this; + for (;;) { + if (ptr->params.size() > 0 || (ptr->inherited && ptr->leafParamCount > 0)) { + levels.add(ptr); + } + KJ_IF_MAYBE(p, ptr->parent) { + ptr = *p; + } else { + break; + } + } + + if (levels.size() > 0) { + auto scopes = initBrand().initScopes(levels.size()); + for (uint i: kj::indices(levels)) { + auto scope = scopes[i]; + scope.setScopeId(levels[i]->leafId); + + if (levels[i]->inherited) { + scope.setInherit(); + } else { + auto bindings = scope.initBind(levels[i]->params.size()); + for (uint j: kj::indices(bindings)) { + levels[i]->params[j].compileAsType(errorReporter, bindings[j].initType()); + } + } + } + } + } + + kj::Maybe compileDeclExpression( + Expression::Reader source, Resolver& resolver, + ImplicitParams implicitMethodParams); + + NodeTranslator::BrandedDecl interpretResolve( + Resolver& resolver, Resolver::ResolveResult& result, Expression::Reader source); + + kj::Own evaluateBrand( + Resolver& resolver, Resolver::ResolvedDecl decl, + List::Reader brand, uint index = 0); + + BrandedDecl decompileType(Resolver& resolver, schema::Type::Reader type); + + inline uint64_t getScopeId() { return leafId; } + +private: + ErrorReporter& errorReporter; + kj::Maybe> parent; + uint64_t leafId; // zero = this is the root + uint leafParamCount; // number of generic parameters on this leaf + bool inherited; + kj::Array params; + + BrandScope(kj::Own parent, uint64_t leafId, uint leafParamCount) + : errorReporter(parent->errorReporter), + parent(kj::mv(parent)), leafId(leafId), leafParamCount(leafParamCount), + inherited(false) {} + BrandScope(BrandScope& base, kj::Array params) + : errorReporter(base.errorReporter), + leafId(base.leafId), leafParamCount(base.leafParamCount), + inherited(false), params(kj::mv(params)) { + KJ_IF_MAYBE(p, base.parent) { + parent = kj::addRef(**p); + } + } + BrandScope(ErrorReporter& errorReporter, uint64_t scopeId) + : errorReporter(errorReporter), leafId(scopeId), leafParamCount(0), inherited(false) {} + + template + friend kj::Own kj::refcounted(Params&&... params); +}; + +NodeTranslator::BrandedDecl::BrandedDecl(BrandedDecl& other) + : body(other.body), + source(other.source) { + if (body.is()) { + brand = kj::addRef(*other.brand); + } +} + +NodeTranslator::BrandedDecl& NodeTranslator::BrandedDecl::operator=(BrandedDecl& other) { + body = other.body; + source = other.source; + if (body.is()) { + brand = kj::addRef(*other.brand); + } + return *this; +} + +kj::Maybe NodeTranslator::BrandedDecl::applyParams( + kj::Array params, Expression::Reader subSource) { + if (body.is()) { + return nullptr; + } else { + return brand->setParams(kj::mv(params), body.get().kind, subSource) + .map([&](kj::Own&& scope) { + BrandedDecl result = *this; + result.brand = kj::mv(scope); + result.source = subSource; + return result; + }); + } +} + +kj::Maybe NodeTranslator::BrandedDecl::getMember( + kj::StringPtr memberName, Expression::Reader subSource) { + if (body.is()) { + return nullptr; + } else KJ_IF_MAYBE(r, body.get().resolver->resolveMember(memberName)) { + return brand->interpretResolve(*body.get().resolver, *r, subSource); + } else { + return nullptr; + } +} + +kj::Maybe NodeTranslator::BrandedDecl::getKind() { + if (body.is()) { + return nullptr; + } else { + return body.get().kind; + } +} + +template +uint64_t NodeTranslator::BrandedDecl::getIdAndFillBrand(InitBrandFunc&& initBrand) { + KJ_REQUIRE(body.is()); + + brand->compile(kj::fwd(initBrand)); + return body.get().id; +} + +kj::Maybe NodeTranslator::BrandedDecl::getListParam() { + KJ_REQUIRE(body.is()); + + auto& decl = body.get(); + KJ_REQUIRE(decl.kind == Declaration::BUILTIN_LIST); + + auto params = KJ_ASSERT_NONNULL(brand->getParams(decl.id)); + if (params.size() != 1) { + return nullptr; + } else { + return params[0]; + } +} + +NodeTranslator::Resolver::ResolvedParameter NodeTranslator::BrandedDecl::asVariable() { + KJ_REQUIRE(body.is()); + + return body.get(); +} + +bool NodeTranslator::BrandedDecl::compileAsType( + ErrorReporter& errorReporter, schema::Type::Builder target) { + KJ_IF_MAYBE(kind, getKind()) { + switch (*kind) { + case Declaration::ENUM: { + auto enum_ = target.initEnum(); + enum_.setTypeId(getIdAndFillBrand([&]() { return enum_.initBrand(); })); + return true; + } + + case Declaration::STRUCT: { + auto struct_ = target.initStruct(); + struct_.setTypeId(getIdAndFillBrand([&]() { return struct_.initBrand(); })); + return true; + } + + case Declaration::INTERFACE: { + auto interface = target.initInterface(); + interface.setTypeId(getIdAndFillBrand([&]() { return interface.initBrand(); })); + return true; + } + + case Declaration::BUILTIN_LIST: { + auto elementType = target.initList().initElementType(); + + KJ_IF_MAYBE(param, getListParam()) { + if (!param->compileAsType(errorReporter, elementType)) { + return false; + } + } else { + addError(errorReporter, "'List' requires exactly one parameter."); + return false; + } + + if (elementType.isAnyPointer()) { + addError(errorReporter, "'List(AnyPointer)' is not supported."); + // Seeing List(AnyPointer) later can mess things up, so change the type to Void. + elementType.setVoid(); + return false; + } + + return true; + } + + case Declaration::BUILTIN_VOID: target.setVoid(); return true; + case Declaration::BUILTIN_BOOL: target.setBool(); return true; + case Declaration::BUILTIN_INT8: target.setInt8(); return true; + case Declaration::BUILTIN_INT16: target.setInt16(); return true; + case Declaration::BUILTIN_INT32: target.setInt32(); return true; + case Declaration::BUILTIN_INT64: target.setInt64(); return true; + case Declaration::BUILTIN_U_INT8: target.setUint8(); return true; + case Declaration::BUILTIN_U_INT16: target.setUint16(); return true; + case Declaration::BUILTIN_U_INT32: target.setUint32(); return true; + case Declaration::BUILTIN_U_INT64: target.setUint64(); return true; + case Declaration::BUILTIN_FLOAT32: target.setFloat32(); return true; + case Declaration::BUILTIN_FLOAT64: target.setFloat64(); return true; + case Declaration::BUILTIN_TEXT: target.setText(); return true; + case Declaration::BUILTIN_DATA: target.setData(); return true; + + case Declaration::BUILTIN_OBJECT: + addError(errorReporter, + "As of Cap'n Proto 0.4, 'Object' has been renamed to 'AnyPointer'. Sorry for the " + "inconvenience, and thanks for being an early adopter. :)"); + // no break + case Declaration::BUILTIN_ANY_POINTER: + target.initAnyPointer().initUnconstrained().setAnyKind(); + return true; + case Declaration::BUILTIN_ANY_STRUCT: + target.initAnyPointer().initUnconstrained().setStruct(); + return true; + case Declaration::BUILTIN_ANY_LIST: + target.initAnyPointer().initUnconstrained().setList(); + return true; + case Declaration::BUILTIN_CAPABILITY: + target.initAnyPointer().initUnconstrained().setCapability(); + return true; + + case Declaration::FILE: + case Declaration::USING: + case Declaration::CONST: + case Declaration::ENUMERANT: + case Declaration::FIELD: + case Declaration::UNION: + case Declaration::GROUP: + case Declaration::METHOD: + case Declaration::ANNOTATION: + case Declaration::NAKED_ID: + case Declaration::NAKED_ANNOTATION: + addError(errorReporter, kj::str("'", toString(), "' is not a type.")); + return false; + } + + KJ_UNREACHABLE; + } else { + // Oh, this is a type variable. + auto var = asVariable(); + if (var.id == 0) { + // This is actually a method implicit parameter. + auto builder = target.initAnyPointer().initImplicitMethodParameter(); + builder.setParameterIndex(var.index); + return true; + } else { + auto builder = target.initAnyPointer().initParameter(); + builder.setScopeId(var.id); + builder.setParameterIndex(var.index); + return true; + } + } +} + +NodeTranslator::Resolver::ResolveResult NodeTranslator::BrandedDecl::asResolveResult( + uint64_t scopeId, schema::Brand::Builder brandBuilder) { + auto result = body; + if (result.is()) { + // May need to compile our context as the "brand". + + result.get().scopeId = scopeId; + + getIdAndFillBrand([&]() { + result.get().brand = brandBuilder.asReader(); + return brandBuilder; + }); + } + return result; +} + +static kj::String expressionString(Expression::Reader name); // defined later + +kj::String NodeTranslator::BrandedDecl::toString() { + return expressionString(source); +} + +kj::String NodeTranslator::BrandedDecl::toDebugString() { + if (body.is()) { + auto variable = body.get(); + return kj::str("varibale(", variable.id, ", ", variable.index, ")"); + } else { + auto decl = body.get(); + return kj::str("decl(", decl.id, ", ", (uint)decl.kind, "')"); + } +} + +NodeTranslator::BrandedDecl NodeTranslator::BrandScope::interpretResolve( + Resolver& resolver, Resolver::ResolveResult& result, Expression::Reader source) { + if (result.is()) { + auto& decl = result.get(); + + auto scope = pop(decl.scopeId); + KJ_IF_MAYBE(brand, decl.brand) { + scope = scope->evaluateBrand(resolver, decl, brand->getScopes()); + } else { + scope = scope->push(decl.id, decl.genericParamCount); + } + + return BrandedDecl(decl, kj::mv(scope), source); + } else { + auto& param = result.get(); + KJ_IF_MAYBE(p, lookupParameter(resolver, param.id, param.index)) { + return *p; + } else { + return BrandedDecl(param, source); + } + } +} + +kj::Own NodeTranslator::BrandScope::evaluateBrand( + Resolver& resolver, Resolver::ResolvedDecl decl, + List::Reader brand, uint index) { + auto result = kj::refcounted(errorReporter, decl.id); + result->leafParamCount = decl.genericParamCount; + + // Fill in `params`. + if (index < brand.size()) { + auto nextScope = brand[index]; + if (decl.id == nextScope.getScopeId()) { + // Initialize our parameters. + + switch (nextScope.which()) { + case schema::Brand::Scope::BIND: { + auto bindings = nextScope.getBind(); + auto params = kj::heapArrayBuilder(bindings.size()); + for (auto binding: bindings) { + switch (binding.which()) { + case schema::Brand::Binding::UNBOUND: { + // Build an AnyPointer-equivalent. + auto anyPointerDecl = resolver.resolveBuiltin(Declaration::BUILTIN_ANY_POINTER); + params.add(BrandedDecl(anyPointerDecl, + kj::refcounted(errorReporter, anyPointerDecl.scopeId), + Expression::Reader())); + break; + } + + case schema::Brand::Binding::TYPE: + // Reverse this schema::Type back into a BrandedDecl. + params.add(decompileType(resolver, binding.getType())); + break; + } + } + result->params = params.finish(); + break; + } + + case schema::Brand::Scope::INHERIT: + KJ_IF_MAYBE(p, getParams(decl.id)) { + result->params = kj::heapArray(*p); + } else { + result->inherited = true; + } + break; + } + + // Parent should start one level deeper in the list. + ++index; + } + } + + // Fill in `parent`. + KJ_IF_MAYBE(parent, decl.resolver->getParent()) { + result->parent = evaluateBrand(resolver, *parent, brand, index); + } + + return result; +} + +NodeTranslator::BrandedDecl NodeTranslator::BrandScope::decompileType( + Resolver& resolver, schema::Type::Reader type) { + auto builtin = [&](Declaration::Which which) -> BrandedDecl { + auto decl = resolver.resolveBuiltin(which); + return BrandedDecl(decl, + evaluateBrand(resolver, decl, List::Reader()), + Expression::Reader()); + }; + + switch (type.which()) { + case schema::Type::VOID: return builtin(Declaration::BUILTIN_VOID); + case schema::Type::BOOL: return builtin(Declaration::BUILTIN_BOOL); + case schema::Type::INT8: return builtin(Declaration::BUILTIN_INT8); + case schema::Type::INT16: return builtin(Declaration::BUILTIN_INT16); + case schema::Type::INT32: return builtin(Declaration::BUILTIN_INT32); + case schema::Type::INT64: return builtin(Declaration::BUILTIN_INT64); + case schema::Type::UINT8: return builtin(Declaration::BUILTIN_U_INT8); + case schema::Type::UINT16: return builtin(Declaration::BUILTIN_U_INT16); + case schema::Type::UINT32: return builtin(Declaration::BUILTIN_U_INT32); + case schema::Type::UINT64: return builtin(Declaration::BUILTIN_U_INT64); + case schema::Type::FLOAT32: return builtin(Declaration::BUILTIN_FLOAT32); + case schema::Type::FLOAT64: return builtin(Declaration::BUILTIN_FLOAT64); + case schema::Type::TEXT: return builtin(Declaration::BUILTIN_TEXT); + case schema::Type::DATA: return builtin(Declaration::BUILTIN_DATA); + + case schema::Type::ENUM: { + auto enumType = type.getEnum(); + Resolver::ResolvedDecl decl = resolver.resolveId(enumType.getTypeId()); + return BrandedDecl(decl, + evaluateBrand(resolver, decl, enumType.getBrand().getScopes()), + Expression::Reader()); + } + + case schema::Type::INTERFACE: { + auto interfaceType = type.getInterface(); + Resolver::ResolvedDecl decl = resolver.resolveId(interfaceType.getTypeId()); + return BrandedDecl(decl, + evaluateBrand(resolver, decl, interfaceType.getBrand().getScopes()), + Expression::Reader()); + } + + case schema::Type::STRUCT: { + auto structType = type.getStruct(); + Resolver::ResolvedDecl decl = resolver.resolveId(structType.getTypeId()); + return BrandedDecl(decl, + evaluateBrand(resolver, decl, structType.getBrand().getScopes()), + Expression::Reader()); + } + + case schema::Type::LIST: { + auto elementType = decompileType(resolver, type.getList().getElementType()); + return KJ_ASSERT_NONNULL(builtin(Declaration::BUILTIN_LIST) + .applyParams(kj::heapArray(&elementType, 1), Expression::Reader())); + } + + case schema::Type::ANY_POINTER: { + auto anyPointer = type.getAnyPointer(); + switch (anyPointer.which()) { + case schema::Type::AnyPointer::UNCONSTRAINED: + return builtin(Declaration::BUILTIN_ANY_POINTER); + + case schema::Type::AnyPointer::PARAMETER: { + auto param = anyPointer.getParameter(); + auto id = param.getScopeId(); + uint index = param.getParameterIndex(); + KJ_IF_MAYBE(binding, lookupParameter(resolver, id, index)) { + return *binding; + } else { + return BrandedDecl(Resolver::ResolvedParameter {id, index}, Expression::Reader()); + } + } + + case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: + KJ_FAIL_ASSERT("Alias pointed to implicit method type parameter?"); + } + + KJ_UNREACHABLE; + } + } + + KJ_UNREACHABLE; +} + +kj::Maybe NodeTranslator::BrandScope::compileDeclExpression( + Expression::Reader source, Resolver& resolver, + ImplicitParams implicitMethodParams) { + switch (source.which()) { + case Expression::UNKNOWN: + // Error reported earlier. + return nullptr; + + case Expression::POSITIVE_INT: + case Expression::NEGATIVE_INT: + case Expression::FLOAT: + case Expression::STRING: + case Expression::BINARY: + case Expression::LIST: + case Expression::TUPLE: + case Expression::EMBED: + errorReporter.addErrorOn(source, "Expected name."); + return nullptr; + + case Expression::RELATIVE_NAME: { + auto name = source.getRelativeName(); + auto nameValue = name.getValue(); + + // Check implicit method params first. + for (auto i: kj::indices(implicitMethodParams.params)) { + if (implicitMethodParams.params[i].getName() == nameValue) { + if (implicitMethodParams.scopeId == 0) { + return BrandedDecl::implicitMethodParam(i); + } else { + return BrandedDecl(Resolver::ResolvedParameter { + implicitMethodParams.scopeId, static_cast(i) }, + Expression::Reader()); + } + } + } + + KJ_IF_MAYBE(r, resolver.resolve(nameValue)) { + return interpretResolve(resolver, *r, source); + } else { + errorReporter.addErrorOn(name, kj::str("Not defined: ", nameValue)); + return nullptr; + } + } + + case Expression::ABSOLUTE_NAME: { + auto name = source.getAbsoluteName(); + KJ_IF_MAYBE(r, resolver.getTopScope().resolver->resolveMember(name.getValue())) { + return interpretResolve(resolver, *r, source); + } else { + errorReporter.addErrorOn(name, kj::str("Not defined: ", name.getValue())); + return nullptr; + } + } + + case Expression::IMPORT: { + auto filename = source.getImport(); + KJ_IF_MAYBE(decl, resolver.resolveImport(filename.getValue())) { + // Import is always a root scope, so create a fresh BrandScope. + return BrandedDecl(*decl, kj::refcounted( + errorReporter, decl->id, decl->genericParamCount, *decl->resolver), source); + } else { + errorReporter.addErrorOn(filename, kj::str("Import failed: ", filename.getValue())); + return nullptr; + } + } + + case Expression::APPLICATION: { + auto app = source.getApplication(); + KJ_IF_MAYBE(decl, compileDeclExpression(app.getFunction(), resolver, implicitMethodParams)) { + // Compile all params. + auto params = app.getParams(); + auto compiledParams = kj::heapArrayBuilder(params.size()); + bool paramFailed = false; + for (auto param: params) { + if (param.isNamed()) { + errorReporter.addErrorOn(param.getNamed(), "Named parameter not allowed here."); + } + + KJ_IF_MAYBE(d, compileDeclExpression(param.getValue(), resolver, implicitMethodParams)) { + compiledParams.add(kj::mv(*d)); + } else { + // Param failed to compile. Error was already reported. + paramFailed = true; + } + }; + + if (paramFailed) { + return kj::mv(*decl); + } + + // Add the parameters to the brand. + KJ_IF_MAYBE(applied, decl->applyParams(compiledParams.finish(), source)) { + return kj::mv(*applied); + } else { + // Error already reported. Ignore parameters. + return kj::mv(*decl); + } + } else { + // error already reported + return nullptr; + } + } + + case Expression::MEMBER: { + auto member = source.getMember(); + KJ_IF_MAYBE(decl, compileDeclExpression(member.getParent(), resolver, implicitMethodParams)) { + auto name = member.getName(); + KJ_IF_MAYBE(memberDecl, decl->getMember(name.getValue(), source)) { + return kj::mv(*memberDecl); + } else { + errorReporter.addErrorOn(name, kj::str( + "'", expressionString(member.getParent()), + "' has no member named '", name.getValue(), "'")); + return nullptr; + } + } else { + // error already reported + return nullptr; + } + } + } + + KJ_UNREACHABLE; +} + +// ======================================================================================= + +NodeTranslator::NodeTranslator( + Resolver& resolver, ErrorReporter& errorReporter, + const Declaration::Reader& decl, Orphan wipNodeParam, + bool compileAnnotations) + : resolver(resolver), errorReporter(errorReporter), + orphanage(Orphanage::getForMessageContaining(wipNodeParam.get())), + compileAnnotations(compileAnnotations), + localBrand(kj::refcounted( + errorReporter, wipNodeParam.getReader().getId(), + decl.getParameters().size(), resolver)), + wipNode(kj::mv(wipNodeParam)) { + compileNode(decl, wipNode.get()); +} + +NodeTranslator::~NodeTranslator() noexcept(false) {} + +NodeTranslator::NodeSet NodeTranslator::getBootstrapNode() { + auto nodeReader = wipNode.getReader(); + if (nodeReader.isInterface()) { + return NodeSet { + nodeReader, + KJ_MAP(g, paramStructs) { return g.getReader(); } + }; + } else { + return NodeSet { + nodeReader, + KJ_MAP(g, groups) { return g.getReader(); } + }; + } +} + +NodeTranslator::NodeSet NodeTranslator::finish() { + // Careful about iteration here: compileFinalValue() may actually add more elements to + // `unfinishedValues`, invalidating iterators in the process. + for (size_t i = 0; i < unfinishedValues.size(); i++) { + auto& value = unfinishedValues[i]; + compileValue(value.source, value.type, value.typeScope, value.target, false); + } + + return getBootstrapNode(); +} + +class NodeTranslator::DuplicateNameDetector { +public: + inline explicit DuplicateNameDetector(ErrorReporter& errorReporter) + : errorReporter(errorReporter) {} + void check(List::Reader nestedDecls, Declaration::Which parentKind); + +private: + ErrorReporter& errorReporter; + std::map names; +}; + +void NodeTranslator::compileNode(Declaration::Reader decl, schema::Node::Builder builder) { + DuplicateNameDetector(errorReporter) + .check(decl.getNestedDecls(), decl.which()); + + auto genericParams = decl.getParameters(); + if (genericParams.size() > 0) { + auto paramsBuilder = builder.initParameters(genericParams.size()); + for (auto i: kj::indices(genericParams)) { + paramsBuilder[i].setName(genericParams[i].getName()); + } + } + + builder.setIsGeneric(localBrand->isGeneric()); + + kj::StringPtr targetsFlagName; + + switch (decl.which()) { + case Declaration::FILE: + targetsFlagName = "targetsFile"; + break; + case Declaration::CONST: + compileConst(decl.getConst(), builder.initConst()); + targetsFlagName = "targetsConst"; + break; + case Declaration::ANNOTATION: + compileAnnotation(decl.getAnnotation(), builder.initAnnotation()); + targetsFlagName = "targetsAnnotation"; + break; + case Declaration::ENUM: + compileEnum(decl.getEnum(), decl.getNestedDecls(), builder); + targetsFlagName = "targetsEnum"; + break; + case Declaration::STRUCT: + compileStruct(decl.getStruct(), decl.getNestedDecls(), builder); + targetsFlagName = "targetsStruct"; + break; + case Declaration::INTERFACE: + compileInterface(decl.getInterface(), decl.getNestedDecls(), builder); + targetsFlagName = "targetsInterface"; + break; + + default: + KJ_FAIL_REQUIRE("This Declaration is not a node."); + break; + } + + builder.adoptAnnotations(compileAnnotationApplications(decl.getAnnotations(), targetsFlagName)); +} + +static kj::StringPtr getExpressionTargetName(Expression::Reader exp) { + kj::StringPtr targetName; + switch (exp.which()) { + case Expression::ABSOLUTE_NAME: + return exp.getAbsoluteName().getValue(); + case Expression::RELATIVE_NAME: + return exp.getRelativeName().getValue(); + case Expression::APPLICATION: + return getExpressionTargetName(exp.getApplication().getFunction()); + case Expression::MEMBER: + return exp.getMember().getName().getValue(); + default: + return nullptr; + } +} + +void NodeTranslator::DuplicateNameDetector::check( + List::Reader nestedDecls, Declaration::Which parentKind) { + for (auto decl: nestedDecls) { + { + auto name = decl.getName(); + auto nameText = name.getValue(); + auto insertResult = names.insert(std::make_pair(nameText, name)); + if (!insertResult.second) { + if (nameText.size() == 0 && decl.isUnion()) { + errorReporter.addErrorOn( + name, kj::str("An unnamed union is already defined in this scope.")); + errorReporter.addErrorOn( + insertResult.first->second, kj::str("Previously defined here.")); + } else { + errorReporter.addErrorOn( + name, kj::str("'", nameText, "' is already defined in this scope.")); + errorReporter.addErrorOn( + insertResult.first->second, kj::str("'", nameText, "' previously defined here.")); + } + } + + switch (decl.which()) { + case Declaration::USING: { + kj::StringPtr targetName = getExpressionTargetName(decl.getUsing().getTarget()); + if (targetName.size() > 0 && targetName[0] >= 'a' && targetName[0] <= 'z') { + // Target starts with lower-case letter, so alias should too. + if (nameText.size() > 0 && (nameText[0] < 'a' || nameText[0] > 'z')) { + errorReporter.addErrorOn(name, + "Non-type names must begin with a lower-case letter."); + } + } else { + // Target starts with capital or is not named (probably, an import). Require + // capitalization. + if (nameText.size() > 0 && (nameText[0] < 'A' || nameText[0] > 'Z')) { + errorReporter.addErrorOn(name, + "Type names must begin with a capital letter."); + } + } + break; + } + + case Declaration::ENUM: + case Declaration::STRUCT: + case Declaration::INTERFACE: + if (nameText.size() > 0 && (nameText[0] < 'A' || nameText[0] > 'Z')) { + errorReporter.addErrorOn(name, + "Type names must begin with a capital letter."); + } + break; + + case Declaration::CONST: + case Declaration::ANNOTATION: + case Declaration::ENUMERANT: + case Declaration::METHOD: + case Declaration::FIELD: + case Declaration::UNION: + case Declaration::GROUP: + if (nameText.size() > 0 && (nameText[0] < 'a' || nameText[0] > 'z')) { + errorReporter.addErrorOn(name, + "Non-type names must begin with a lower-case letter."); + } + break; + + default: + KJ_ASSERT(nameText.size() == 0, "Don't know what naming rules to enforce for node type.", + (uint)decl.which()); + break; + } + + if (nameText.findFirst('_') != nullptr) { + errorReporter.addErrorOn(name, + "Cap'n Proto declaration names should use camelCase and must not contain " + "underscores. (Code generators may convert names to the appropriate style for the " + "target language.)"); + } + } + + switch (decl.which()) { + case Declaration::USING: + case Declaration::CONST: + case Declaration::ENUM: + case Declaration::STRUCT: + case Declaration::INTERFACE: + case Declaration::ANNOTATION: + switch (parentKind) { + case Declaration::FILE: + case Declaration::STRUCT: + case Declaration::INTERFACE: + // OK. + break; + default: + errorReporter.addErrorOn(decl, "This kind of declaration doesn't belong here."); + break; + } + break; + + case Declaration::ENUMERANT: + if (parentKind != Declaration::ENUM) { + errorReporter.addErrorOn(decl, "Enumerants can only appear in enums."); + } + break; + case Declaration::METHOD: + if (parentKind != Declaration::INTERFACE) { + errorReporter.addErrorOn(decl, "Methods can only appear in interfaces."); + } + break; + case Declaration::FIELD: + case Declaration::UNION: + case Declaration::GROUP: + switch (parentKind) { + case Declaration::STRUCT: + case Declaration::UNION: + case Declaration::GROUP: + // OK. + break; + default: + errorReporter.addErrorOn(decl, "This declaration can only appear in structs."); + break; + } + + // Struct members may have nested decls. We need to check those here, because no one else + // is going to do it. + if (decl.getName().getValue().size() == 0) { + // Unnamed union. Check members as if they are in the same scope. + check(decl.getNestedDecls(), decl.which()); + } else { + // Children are in their own scope. + DuplicateNameDetector(errorReporter) + .check(decl.getNestedDecls(), decl.which()); + } + + break; + + default: + errorReporter.addErrorOn(decl, "This kind of declaration doesn't belong here."); + break; + } + } +} + +void NodeTranslator::compileConst(Declaration::Const::Reader decl, + schema::Node::Const::Builder builder) { + auto typeBuilder = builder.initType(); + if (compileType(decl.getType(), typeBuilder, noImplicitParams())) { + compileBootstrapValue(decl.getValue(), typeBuilder.asReader(), builder.initValue()); + } +} + +void NodeTranslator::compileAnnotation(Declaration::Annotation::Reader decl, + schema::Node::Annotation::Builder builder) { + compileType(decl.getType(), builder.initType(), noImplicitParams()); + + // Dynamically copy over the values of all of the "targets" members. + DynamicStruct::Reader src = decl; + DynamicStruct::Builder dst = builder; + for (auto srcField: src.getSchema().getFields()) { + kj::StringPtr fieldName = srcField.getProto().getName(); + if (fieldName.startsWith("targets")) { + auto dstField = dst.getSchema().getFieldByName(fieldName); + dst.set(dstField, src.get(srcField)); + } + } +} + +class NodeTranslator::DuplicateOrdinalDetector { +public: + DuplicateOrdinalDetector(ErrorReporter& errorReporter): errorReporter(errorReporter) {} + + void check(LocatedInteger::Reader ordinal) { + if (ordinal.getValue() < expectedOrdinal) { + errorReporter.addErrorOn(ordinal, "Duplicate ordinal number."); + KJ_IF_MAYBE(last, lastOrdinalLocation) { + errorReporter.addErrorOn( + *last, kj::str("Ordinal @", last->getValue(), " originally used here.")); + // Don't report original again. + lastOrdinalLocation = nullptr; + } + } else if (ordinal.getValue() > expectedOrdinal) { + errorReporter.addErrorOn(ordinal, + kj::str("Skipped ordinal @", expectedOrdinal, ". Ordinals must be sequential with no " + "holes.")); + expectedOrdinal = ordinal.getValue() + 1; + } else { + ++expectedOrdinal; + lastOrdinalLocation = ordinal; + } + } + +private: + ErrorReporter& errorReporter; + uint expectedOrdinal = 0; + kj::Maybe lastOrdinalLocation; +}; + +void NodeTranslator::compileEnum(Void decl, + List::Reader members, + schema::Node::Builder builder) { + // maps ordinal -> (code order, declaration) + std::multimap> enumerants; + + uint codeOrder = 0; + for (auto member: members) { + if (member.isEnumerant()) { + enumerants.insert( + std::make_pair(member.getId().getOrdinal().getValue(), + std::make_pair(codeOrder++, member))); + } + } + + auto list = builder.initEnum().initEnumerants(enumerants.size()); + uint i = 0; + DuplicateOrdinalDetector dupDetector(errorReporter); + + for (auto& entry: enumerants) { + uint codeOrder = entry.second.first; + Declaration::Reader enumerantDecl = entry.second.second; + + dupDetector.check(enumerantDecl.getId().getOrdinal()); + + auto enumerantBuilder = list[i++]; + enumerantBuilder.setName(enumerantDecl.getName().getValue()); + enumerantBuilder.setCodeOrder(codeOrder); + enumerantBuilder.adoptAnnotations(compileAnnotationApplications( + enumerantDecl.getAnnotations(), "targetsEnumerant")); + } +} + +// ------------------------------------------------------------------- + +class NodeTranslator::StructTranslator { +public: + explicit StructTranslator(NodeTranslator& translator, ImplicitParams implicitMethodParams) + : translator(translator), errorReporter(translator.errorReporter), + implicitMethodParams(implicitMethodParams) {} + KJ_DISALLOW_COPY(StructTranslator); + + void translate(Void decl, List::Reader members, schema::Node::Builder builder) { + // Build the member-info-by-ordinal map. + MemberInfo root(builder); + traverseTopOrGroup(members, root, layout.getTop()); + translateInternal(root, builder); + } + + void translate(List::Reader params, schema::Node::Builder builder) { + // Build a struct from a method param / result list. + MemberInfo root(builder); + traverseParams(params, root, layout.getTop()); + translateInternal(root, builder); + } + +private: + NodeTranslator& translator; + ErrorReporter& errorReporter; + ImplicitParams implicitMethodParams; + StructLayout layout; + kj::Arena arena; + + struct MemberInfo { + MemberInfo* parent; + // The MemberInfo for the parent scope. + + uint codeOrder; + // Code order within the parent. + + uint index = 0; + // Index within the parent. + + uint childCount = 0; + // Number of children this member has. + + uint childInitializedCount = 0; + // Number of children whose `schema` member has been initialized. This initialization happens + // while walking the fields in ordinal order. + + uint unionDiscriminantCount = 0; + // Number of children who are members of the scope's union and have had their discriminant + // value decided. + + bool isInUnion; + // Whether or not this field is in the parent's union. + + kj::StringPtr name; + Declaration::Id::Reader declId; + Declaration::Which declKind; + bool isParam = false; + bool hasDefaultValue = false; // if declKind == FIELD + Expression::Reader fieldType; // if declKind == FIELD + Expression::Reader fieldDefaultValue; // if declKind == FIELD && hasDefaultValue + List::Reader declAnnotations; + uint startByte = 0; + uint endByte = 0; + // Information about the field declaration. We don't use Declaration::Reader because it might + // have come from a Declaration::Param instead. + + kj::Maybe schema; + // Schema for the field. Initialized when getSchema() is first called. + + schema::Node::Builder node; + // If it's a group, or the top-level struct. + + union { + StructLayout::StructOrGroup* fieldScope; + // If this member is a field, the scope of that field. This will be used to assign an + // offset for the field when going through in ordinal order. + + StructLayout::Union* unionScope; + // If this member is a union, or it is a group or top-level struct containing an unnamed + // union, this is the union. This will be used to assign a discriminant offset when the + // union's ordinal comes up (if the union has an explicit ordinal), as well as to finally + // copy over the discriminant offset to the schema. + }; + + inline explicit MemberInfo(schema::Node::Builder node) + : parent(nullptr), codeOrder(0), isInUnion(false), node(node), unionScope(nullptr) {} + inline MemberInfo(MemberInfo& parent, uint codeOrder, + const Declaration::Reader& decl, + StructLayout::StructOrGroup& fieldScope, + bool isInUnion) + : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion), + name(decl.getName().getValue()), declId(decl.getId()), declKind(Declaration::FIELD), + declAnnotations(decl.getAnnotations()), + startByte(decl.getStartByte()), endByte(decl.getEndByte()), + node(nullptr), fieldScope(&fieldScope) { + KJ_REQUIRE(decl.which() == Declaration::FIELD); + auto fieldDecl = decl.getField(); + fieldType = fieldDecl.getType(); + if (fieldDecl.getDefaultValue().isValue()) { + hasDefaultValue = true; + fieldDefaultValue = fieldDecl.getDefaultValue().getValue(); + } + } + inline MemberInfo(MemberInfo& parent, uint codeOrder, + const Declaration::Param::Reader& decl, + StructLayout::StructOrGroup& fieldScope, + bool isInUnion) + : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion), + name(decl.getName().getValue()), declKind(Declaration::FIELD), isParam(true), + declAnnotations(decl.getAnnotations()), + startByte(decl.getStartByte()), endByte(decl.getEndByte()), + node(nullptr), fieldScope(&fieldScope) { + fieldType = decl.getType(); + if (decl.getDefaultValue().isValue()) { + hasDefaultValue = true; + fieldDefaultValue = decl.getDefaultValue().getValue(); + } + } + inline MemberInfo(MemberInfo& parent, uint codeOrder, + const Declaration::Reader& decl, + schema::Node::Builder node, + bool isInUnion) + : parent(&parent), codeOrder(codeOrder), isInUnion(isInUnion), + name(decl.getName().getValue()), declId(decl.getId()), declKind(decl.which()), + declAnnotations(decl.getAnnotations()), + startByte(decl.getStartByte()), endByte(decl.getEndByte()), + node(node), unionScope(nullptr) { + KJ_REQUIRE(decl.which() != Declaration::FIELD); + } + + schema::Field::Builder getSchema() { + KJ_IF_MAYBE(result, schema) { + return *result; + } else { + index = parent->childInitializedCount; + auto builder = parent->addMemberSchema(); + if (isInUnion) { + builder.setDiscriminantValue(parent->unionDiscriminantCount++); + } + builder.setName(name); + builder.setCodeOrder(codeOrder); + schema = builder; + return builder; + } + } + + schema::Field::Builder addMemberSchema() { + // Get the schema builder for the child member at the given index. This lazily/dynamically + // builds the builder tree. + + KJ_REQUIRE(childInitializedCount < childCount); + + auto structNode = node.getStruct(); + if (!structNode.hasFields()) { + if (parent != nullptr) { + getSchema(); // Make sure field exists in parent once the first child is added. + } + return structNode.initFields(childCount)[childInitializedCount++]; + } else { + return structNode.getFields()[childInitializedCount++]; + } + } + + void finishGroup() { + if (unionScope != nullptr) { + unionScope->addDiscriminant(); // if it hasn't happened already + auto structNode = node.getStruct(); + structNode.setDiscriminantCount(unionDiscriminantCount); + structNode.setDiscriminantOffset(KJ_ASSERT_NONNULL(unionScope->discriminantOffset)); + } + + if (parent != nullptr) { + uint64_t groupId = generateGroupId(parent->node.getId(), index); + node.setId(groupId); + node.setScopeId(parent->node.getId()); + getSchema().initGroup().setTypeId(groupId); + } + } + }; + + std::multimap membersByOrdinal; + // Every member that has an explicit ordinal goes into this map. We then iterate over the map + // to assign field offsets (or discriminant offsets for unions). + + kj::Vector allMembers; + // All members, including ones that don't have ordinals. + + void traverseUnion(const Declaration::Reader& decl, + List::Reader members, MemberInfo& parent, + StructLayout::Union& layout, uint& codeOrder) { + if (members.size() < 2) { + errorReporter.addErrorOn(decl, "Union must have at least two members."); + } + + for (auto member: members) { + kj::Maybe ordinal; + MemberInfo* memberInfo = nullptr; + + switch (member.which()) { + case Declaration::FIELD: { + parent.childCount++; + // For layout purposes, pretend this field is enclosed in a one-member group. + StructLayout::Group& singletonGroup = + arena.allocate(layout); + memberInfo = &arena.allocate(parent, codeOrder++, member, singletonGroup, + true); + allMembers.add(memberInfo); + ordinal = member.getId().getOrdinal().getValue(); + break; + } + + case Declaration::UNION: + if (member.getName().getValue() == "") { + errorReporter.addErrorOn(member, "Unions cannot contain unnamed unions."); + } else { + parent.childCount++; + + // For layout purposes, pretend this union is enclosed in a one-member group. + StructLayout::Group& singletonGroup = + arena.allocate(layout); + StructLayout::Union& unionLayout = arena.allocate(singletonGroup); + + memberInfo = &arena.allocate( + parent, codeOrder++, member, + newGroupNode(parent.node, member.getName().getValue()), + true); + allMembers.add(memberInfo); + memberInfo->unionScope = &unionLayout; + uint subCodeOrder = 0; + traverseUnion(member, member.getNestedDecls(), *memberInfo, unionLayout, subCodeOrder); + if (member.getId().isOrdinal()) { + ordinal = member.getId().getOrdinal().getValue(); + } + } + break; + + case Declaration::GROUP: { + parent.childCount++; + StructLayout::Group& group = arena.allocate(layout); + memberInfo = &arena.allocate( + parent, codeOrder++, member, + newGroupNode(parent.node, member.getName().getValue()), + true); + allMembers.add(memberInfo); + traverseGroup(member.getNestedDecls(), *memberInfo, group); + break; + } + + default: + // Ignore others. + break; + } + + KJ_IF_MAYBE(o, ordinal) { + membersByOrdinal.insert(std::make_pair(*o, memberInfo)); + } + } + } + + void traverseGroup(List::Reader members, MemberInfo& parent, + StructLayout::StructOrGroup& layout) { + if (members.size() < 1) { + errorReporter.addError(parent.startByte, parent.endByte, + "Group must have at least one member."); + } + + traverseTopOrGroup(members, parent, layout); + } + + void traverseTopOrGroup(List::Reader members, MemberInfo& parent, + StructLayout::StructOrGroup& layout) { + uint codeOrder = 0; + + for (auto member: members) { + kj::Maybe ordinal; + MemberInfo* memberInfo = nullptr; + + switch (member.which()) { + case Declaration::FIELD: { + parent.childCount++; + memberInfo = &arena.allocate( + parent, codeOrder++, member, layout, false); + allMembers.add(memberInfo); + ordinal = member.getId().getOrdinal().getValue(); + break; + } + + case Declaration::UNION: { + StructLayout::Union& unionLayout = arena.allocate(layout); + + uint independentSubCodeOrder = 0; + uint* subCodeOrder = &independentSubCodeOrder; + if (member.getName().getValue() == "") { + memberInfo = &parent; + subCodeOrder = &codeOrder; + } else { + parent.childCount++; + memberInfo = &arena.allocate( + parent, codeOrder++, member, + newGroupNode(parent.node, member.getName().getValue()), + false); + allMembers.add(memberInfo); + } + memberInfo->unionScope = &unionLayout; + traverseUnion(member, member.getNestedDecls(), *memberInfo, unionLayout, *subCodeOrder); + if (member.getId().isOrdinal()) { + ordinal = member.getId().getOrdinal().getValue(); + } + break; + } + + case Declaration::GROUP: + parent.childCount++; + memberInfo = &arena.allocate( + parent, codeOrder++, member, + newGroupNode(parent.node, member.getName().getValue()), + false); + allMembers.add(memberInfo); + + // Members of the group are laid out just like they were members of the parent, so we + // just pass along the parent layout. + traverseGroup(member.getNestedDecls(), *memberInfo, layout); + + // No ordinal for groups. + break; + + default: + // Ignore others. + break; + } + + KJ_IF_MAYBE(o, ordinal) { + membersByOrdinal.insert(std::make_pair(*o, memberInfo)); + } + } + } + + void traverseParams(List::Reader params, MemberInfo& parent, + StructLayout::StructOrGroup& layout) { + for (uint i: kj::indices(params)) { + auto param = params[i]; + parent.childCount++; + MemberInfo* memberInfo = &arena.allocate(parent, i, param, layout, false); + allMembers.add(memberInfo); + membersByOrdinal.insert(std::make_pair(i, memberInfo)); + } + } + + schema::Node::Builder newGroupNode(schema::Node::Reader parent, kj::StringPtr name) { + auto orphan = translator.orphanage.newOrphan(); + auto node = orphan.get(); + + // We'll set the ID and scope ID later. + node.setDisplayName(kj::str(parent.getDisplayName(), '.', name)); + node.setDisplayNamePrefixLength(node.getDisplayName().size() - name.size()); + node.setIsGeneric(parent.getIsGeneric()); + node.initStruct().setIsGroup(true); + + // The remaining contents of node.struct will be filled in later. + + translator.groups.add(kj::mv(orphan)); + return node; + } + + void translateInternal(MemberInfo& root, schema::Node::Builder builder) { + auto structBuilder = builder.initStruct(); + + // Go through each member in ordinal order, building each member schema. + DuplicateOrdinalDetector dupDetector(errorReporter); + for (auto& entry: membersByOrdinal) { + MemberInfo& member = *entry.second; + + // Make sure the exceptions added relating to + // https://github.com/sandstorm-io/capnproto/issues/344 identify the affected field. + KJ_CONTEXT(member.name); + + if (member.declId.isOrdinal()) { + dupDetector.check(member.declId.getOrdinal()); + } + + schema::Field::Builder fieldBuilder = member.getSchema(); + fieldBuilder.getOrdinal().setExplicit(entry.first); + + switch (member.declKind) { + case Declaration::FIELD: { + auto slot = fieldBuilder.initSlot(); + auto typeBuilder = slot.initType(); + if (translator.compileType(member.fieldType, typeBuilder, implicitMethodParams)) { + if (member.hasDefaultValue) { + if (member.isParam && + member.fieldDefaultValue.isRelativeName() && + member.fieldDefaultValue.getRelativeName().getValue() == "null") { + // special case: parameter set null + switch (typeBuilder.which()) { + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + break; + default: + errorReporter.addErrorOn(member.fieldDefaultValue.getRelativeName(), + "Only pointer parameters can declare their default as 'null'."); + break; + } + translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue()); + } else { + translator.compileBootstrapValue(member.fieldDefaultValue, + typeBuilder, slot.initDefaultValue()); + } + slot.setHadExplicitDefault(true); + } else { + translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue()); + } + } else { + translator.compileDefaultDefaultValue(typeBuilder, slot.initDefaultValue()); + } + + int lgSize = -1; + switch (typeBuilder.which()) { + case schema::Type::VOID: lgSize = -1; break; + case schema::Type::BOOL: lgSize = 0; break; + case schema::Type::INT8: lgSize = 3; break; + case schema::Type::INT16: lgSize = 4; break; + case schema::Type::INT32: lgSize = 5; break; + case schema::Type::INT64: lgSize = 6; break; + case schema::Type::UINT8: lgSize = 3; break; + case schema::Type::UINT16: lgSize = 4; break; + case schema::Type::UINT32: lgSize = 5; break; + case schema::Type::UINT64: lgSize = 6; break; + case schema::Type::FLOAT32: lgSize = 5; break; + case schema::Type::FLOAT64: lgSize = 6; break; + + case schema::Type::TEXT: lgSize = -2; break; + case schema::Type::DATA: lgSize = -2; break; + case schema::Type::LIST: lgSize = -2; break; + case schema::Type::ENUM: lgSize = 4; break; + case schema::Type::STRUCT: lgSize = -2; break; + case schema::Type::INTERFACE: lgSize = -2; break; + case schema::Type::ANY_POINTER: lgSize = -2; break; + } + + if (lgSize == -2) { + // pointer + slot.setOffset(member.fieldScope->addPointer()); + } else if (lgSize == -1) { + // void + member.fieldScope->addVoid(); + slot.setOffset(0); + } else { + slot.setOffset(member.fieldScope->addData(lgSize)); + } + break; + } + + case Declaration::UNION: + if (!member.unionScope->addDiscriminant()) { + errorReporter.addErrorOn(member.declId.getOrdinal(), + "Union ordinal, if specified, must be greater than no more than one of its " + "member ordinals (i.e. there can only be one field retroactively unionized)."); + } + break; + + case Declaration::GROUP: + KJ_FAIL_ASSERT("Groups don't have ordinals."); + break; + + default: + KJ_FAIL_ASSERT("Unexpected member type."); + break; + } + } + + // OK, we should have built all the members. Now go through and make sure the discriminant + // offsets have been copied over to the schemas and annotations have been applied. + root.finishGroup(); + for (auto member: allMembers) { + kj::StringPtr targetsFlagName; + if (member->isParam) { + targetsFlagName = "targetsParam"; + } else { + switch (member->declKind) { + case Declaration::FIELD: + targetsFlagName = "targetsField"; + break; + + case Declaration::UNION: + member->finishGroup(); + targetsFlagName = "targetsUnion"; + break; + + case Declaration::GROUP: + member->finishGroup(); + targetsFlagName = "targetsGroup"; + break; + + default: + KJ_FAIL_ASSERT("Unexpected member type."); + break; + } + } + + member->getSchema().adoptAnnotations(translator.compileAnnotationApplications( + member->declAnnotations, targetsFlagName)); + } + + // And fill in the sizes. + structBuilder.setDataWordCount(layout.getTop().dataWordCount); + structBuilder.setPointerCount(layout.getTop().pointerCount); + structBuilder.setPreferredListEncoding(schema::ElementSize::INLINE_COMPOSITE); + + for (auto& group: translator.groups) { + auto groupBuilder = group.get().getStruct(); + groupBuilder.setDataWordCount(structBuilder.getDataWordCount()); + groupBuilder.setPointerCount(structBuilder.getPointerCount()); + groupBuilder.setPreferredListEncoding(structBuilder.getPreferredListEncoding()); + } + } +}; + +void NodeTranslator::compileStruct(Void decl, List::Reader members, + schema::Node::Builder builder) { + StructTranslator(*this, noImplicitParams()).translate(decl, members, builder); +} + +// ------------------------------------------------------------------- + +static kj::String expressionString(Expression::Reader name); + +void NodeTranslator::compileInterface(Declaration::Interface::Reader decl, + List::Reader members, + schema::Node::Builder builder) { + auto interfaceBuilder = builder.initInterface(); + + auto superclassesDecl = decl.getSuperclasses(); + auto superclassesBuilder = interfaceBuilder.initSuperclasses(superclassesDecl.size()); + for (uint i: kj::indices(superclassesDecl)) { + auto superclass = superclassesDecl[i]; + + KJ_IF_MAYBE(decl, compileDeclExpression(superclass, noImplicitParams())) { + KJ_IF_MAYBE(kind, decl->getKind()) { + if (*kind == Declaration::INTERFACE) { + auto s = superclassesBuilder[i]; + s.setId(decl->getIdAndFillBrand([&]() { return s.initBrand(); })); + } else { + decl->addError(errorReporter, kj::str( + "'", decl->toString(), "' is not an interface.")); + } + } else { + // A variable? + decl->addError(errorReporter, kj::str( + "'", decl->toString(), "' is an unbound generic parameter. Currently we don't support " + "extending these.")); + } + } + } + + // maps ordinal -> (code order, declaration) + std::multimap> methods; + + uint codeOrder = 0; + for (auto member: members) { + if (member.isMethod()) { + methods.insert( + std::make_pair(member.getId().getOrdinal().getValue(), + std::make_pair(codeOrder++, member))); + } + } + + auto list = interfaceBuilder.initMethods(methods.size()); + uint i = 0; + DuplicateOrdinalDetector dupDetector(errorReporter); + + for (auto& entry: methods) { + uint codeOrder = entry.second.first; + Declaration::Reader methodDecl = entry.second.second; + auto methodReader = methodDecl.getMethod(); + + auto ordinalDecl = methodDecl.getId().getOrdinal(); + dupDetector.check(ordinalDecl); + uint16_t ordinal = ordinalDecl.getValue(); + + auto methodBuilder = list[i++]; + methodBuilder.setName(methodDecl.getName().getValue()); + methodBuilder.setCodeOrder(codeOrder); + + auto implicits = methodDecl.getParameters(); + auto implicitsBuilder = methodBuilder.initImplicitParameters(implicits.size()); + for (auto i: kj::indices(implicits)) { + implicitsBuilder[i].setName(implicits[i].getName()); + } + + methodBuilder.setParamStructType(compileParamList( + methodDecl.getName().getValue(), ordinal, false, + methodReader.getParams(), implicits, + [&]() { return methodBuilder.initParamBrand(); })); + + auto results = methodReader.getResults(); + Declaration::ParamList::Reader resultList; + if (results.isExplicit()) { + resultList = results.getExplicit(); + } else { + // We just stick with `resultList` uninitialized, which is equivalent to the default + // instance. This works because `namedList` is the default kind of ParamList, and it will + // default to an empty list. + } + methodBuilder.setResultStructType(compileParamList( + methodDecl.getName().getValue(), ordinal, true, + resultList, implicits, + [&]() { return methodBuilder.initResultBrand(); })); + + methodBuilder.adoptAnnotations(compileAnnotationApplications( + methodDecl.getAnnotations(), "targetsMethod")); + } +} + +template +uint64_t NodeTranslator::compileParamList( + kj::StringPtr methodName, uint16_t ordinal, bool isResults, + Declaration::ParamList::Reader paramList, + typename List::Reader implicitParams, + InitBrandFunc&& initBrand) { + switch (paramList.which()) { + case Declaration::ParamList::NAMED_LIST: { + auto newStruct = orphanage.newOrphan(); + auto builder = newStruct.get(); + auto parent = wipNode.getReader(); + + kj::String typeName = kj::str(methodName, isResults ? "$Results" : "$Params"); + + builder.setId(generateMethodParamsId(parent.getId(), ordinal, isResults)); + builder.setDisplayName(kj::str(parent.getDisplayName(), '.', typeName)); + builder.setDisplayNamePrefixLength(builder.getDisplayName().size() - typeName.size()); + builder.setIsGeneric(parent.getIsGeneric() || implicitParams.size() > 0); + builder.setScopeId(0); // detached struct type + + builder.initStruct(); + + // Note that the struct we create here has a brand parameter list mirrioring the method's + // implicit parameter list. Of course, fields inside the struct using the method's implicit + // params as types actually need to refer to them as regular params, so we create an + // ImplicitParams with a scopeId here. + StructTranslator(*this, ImplicitParams { builder.getId(), implicitParams }) + .translate(paramList.getNamedList(), builder); + uint64_t id = builder.getId(); + paramStructs.add(kj::mv(newStruct)); + + auto brand = localBrand->push(builder.getId(), implicitParams.size()); + + if (implicitParams.size() > 0) { + auto implicitDecls = kj::heapArrayBuilder(implicitParams.size()); + auto implicitBuilder = builder.initParameters(implicitParams.size()); + + for (auto i: kj::indices(implicitParams)) { + auto param = implicitParams[i]; + implicitDecls.add(BrandedDecl::implicitMethodParam(i)); + implicitBuilder[i].setName(param.getName()); + } + + brand->setParams(implicitDecls.finish(), Declaration::STRUCT, Expression::Reader()); + } + + brand->compile(initBrand); + return id; + } + case Declaration::ParamList::TYPE: + KJ_IF_MAYBE(target, compileDeclExpression( + paramList.getType(), ImplicitParams { 0, implicitParams })) { + KJ_IF_MAYBE(kind, target->getKind()) { + if (*kind == Declaration::STRUCT) { + return target->getIdAndFillBrand(kj::fwd(initBrand)); + } else { + errorReporter.addErrorOn( + paramList.getType(), + kj::str("'", expressionString(paramList.getType()), "' is not a struct type.")); + } + } else { + // A variable? + target->addError(errorReporter, + "Cannot use generic parameter as whole input or output of a method. Instead, " + "use a parameter/result list containing a field with this type."); + return 0; + } + } + return 0; + } + KJ_UNREACHABLE; +} + +// ------------------------------------------------------------------- + +static const char HEXDIGITS[] = "0123456789abcdef"; + +static kj::StringTree stringLiteral(kj::StringPtr chars) { + // TODO(cleanup): This code keeps coming up. Put somewhere common? + + kj::Vector escaped(chars.size()); + + for (char c: chars) { + switch (c) { + case '\a': escaped.addAll(kj::StringPtr("\\a")); break; + case '\b': escaped.addAll(kj::StringPtr("\\b")); break; + case '\f': escaped.addAll(kj::StringPtr("\\f")); break; + case '\n': escaped.addAll(kj::StringPtr("\\n")); break; + case '\r': escaped.addAll(kj::StringPtr("\\r")); break; + case '\t': escaped.addAll(kj::StringPtr("\\t")); break; + case '\v': escaped.addAll(kj::StringPtr("\\v")); break; + case '\'': escaped.addAll(kj::StringPtr("\\\'")); break; + case '\"': escaped.addAll(kj::StringPtr("\\\"")); break; + case '\\': escaped.addAll(kj::StringPtr("\\\\")); break; + default: + if (c < 0x20) { + escaped.add('\\'); + escaped.add('x'); + uint8_t c2 = c; + escaped.add(HEXDIGITS[c2 / 16]); + escaped.add(HEXDIGITS[c2 % 16]); + } else { + escaped.add(c); + } + break; + } + } + return kj::strTree('"', escaped, '"'); +} + +static kj::StringTree binaryLiteral(Data::Reader data) { + kj::Vector escaped(data.size() * 3); + + for (byte b: data) { + escaped.add(HEXDIGITS[b % 16]); + escaped.add(HEXDIGITS[b / 16]); + escaped.add(' '); + } + + escaped.removeLast(); + return kj::strTree("0x\"", escaped, '"'); +} + +static kj::StringTree expressionStringTree(Expression::Reader exp); + +static kj::StringTree tupleLiteral(List::Reader params) { + auto parts = kj::heapArrayBuilder(params.size()); + for (auto param: params) { + auto part = expressionStringTree(param.getValue()); + if (param.isNamed()) { + part = kj::strTree(param.getNamed().getValue(), " = ", kj::mv(part)); + } + parts.add(kj::mv(part)); + } + return kj::strTree("( ", kj::StringTree(parts.finish(), ", "), " )"); +} + +static kj::StringTree expressionStringTree(Expression::Reader exp) { + switch (exp.which()) { + case Expression::UNKNOWN: + return kj::strTree(""); + case Expression::POSITIVE_INT: + return kj::strTree(exp.getPositiveInt()); + case Expression::NEGATIVE_INT: + return kj::strTree('-', exp.getNegativeInt()); + case Expression::FLOAT: + return kj::strTree(exp.getFloat()); + case Expression::STRING: + return stringLiteral(exp.getString()); + case Expression::BINARY: + return binaryLiteral(exp.getBinary()); + case Expression::RELATIVE_NAME: + return kj::strTree(exp.getRelativeName().getValue()); + case Expression::ABSOLUTE_NAME: + return kj::strTree('.', exp.getAbsoluteName().getValue()); + case Expression::IMPORT: + return kj::strTree("import ", stringLiteral(exp.getImport().getValue())); + case Expression::EMBED: + return kj::strTree("embed ", stringLiteral(exp.getEmbed().getValue())); + + case Expression::LIST: { + auto list = exp.getList(); + auto parts = kj::heapArrayBuilder(list.size()); + for (auto element: list) { + parts.add(expressionStringTree(element)); + } + return kj::strTree("[ ", kj::StringTree(parts.finish(), ", "), " ]"); + } + + case Expression::TUPLE: + return tupleLiteral(exp.getTuple()); + + case Expression::APPLICATION: { + auto app = exp.getApplication(); + return kj::strTree(expressionStringTree(app.getFunction()), + '(', tupleLiteral(app.getParams()), ')'); + } + + case Expression::MEMBER: { + auto member = exp.getMember(); + return kj::strTree(expressionStringTree(member.getParent()), '.', + member.getName().getValue()); + } + } + + KJ_UNREACHABLE; +} + +static kj::String expressionString(Expression::Reader name) { + return expressionStringTree(name).flatten(); +} + +// ------------------------------------------------------------------- + +kj::Maybe +NodeTranslator::compileDeclExpression( + Expression::Reader source, ImplicitParams implicitMethodParams) { + return localBrand->compileDeclExpression(source, resolver, implicitMethodParams); +} + +/* static */ kj::Maybe NodeTranslator::compileDecl( + uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter, + Expression::Reader expression, schema::Brand::Builder brandBuilder) { + auto scope = kj::refcounted(errorReporter, scopeId, scopeParameterCount, resolver); + KJ_IF_MAYBE(decl, scope->compileDeclExpression(expression, resolver, noImplicitParams())) { + return decl->asResolveResult(scope->getScopeId(), brandBuilder); + } else { + return nullptr; + } +} + +bool NodeTranslator::compileType(Expression::Reader source, schema::Type::Builder target, + ImplicitParams implicitMethodParams) { + KJ_IF_MAYBE(decl, compileDeclExpression(source, implicitMethodParams)) { + return decl->compileAsType(errorReporter, target); + } else { + return false; + } +} + +// ------------------------------------------------------------------- + +void NodeTranslator::compileDefaultDefaultValue( + schema::Type::Reader type, schema::Value::Builder target) { + switch (type.which()) { + case schema::Type::VOID: target.setVoid(); break; + case schema::Type::BOOL: target.setBool(false); break; + case schema::Type::INT8: target.setInt8(0); break; + case schema::Type::INT16: target.setInt16(0); break; + case schema::Type::INT32: target.setInt32(0); break; + case schema::Type::INT64: target.setInt64(0); break; + case schema::Type::UINT8: target.setUint8(0); break; + case schema::Type::UINT16: target.setUint16(0); break; + case schema::Type::UINT32: target.setUint32(0); break; + case schema::Type::UINT64: target.setUint64(0); break; + case schema::Type::FLOAT32: target.setFloat32(0); break; + case schema::Type::FLOAT64: target.setFloat64(0); break; + case schema::Type::ENUM: target.setEnum(0); break; + case schema::Type::INTERFACE: target.setInterface(); break; + + // Bit of a hack: For Text/Data, we adopt a null orphan, which sets the field to null. + // TODO(cleanup): Create a cleaner way to do this. + case schema::Type::TEXT: target.adoptText(Orphan()); break; + case schema::Type::DATA: target.adoptData(Orphan()); break; + case schema::Type::STRUCT: target.initStruct(); break; + case schema::Type::LIST: target.initList(); break; + case schema::Type::ANY_POINTER: target.initAnyPointer(); break; + } +} + +void NodeTranslator::compileBootstrapValue( + Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target, + Schema typeScope) { + // Start by filling in a default default value so that if for whatever reason we don't end up + // initializing the value, this won't cause schema validation to fail. + compileDefaultDefaultValue(type, target); + + switch (type.which()) { + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + unfinishedValues.add(UnfinishedValue { source, type, typeScope, target }); + break; + + default: + // Primitive value. + compileValue(source, type, typeScope, target, true); + break; + } +} + +void NodeTranslator::compileValue(Expression::Reader source, schema::Type::Reader type, + Schema typeScope, schema::Value::Builder target, + bool isBootstrap) { + class ResolverGlue: public ValueTranslator::Resolver { + public: + inline ResolverGlue(NodeTranslator& translator, bool isBootstrap) + : translator(translator), isBootstrap(isBootstrap) {} + + kj::Maybe resolveConstant(Expression::Reader name) override { + return translator.readConstant(name, isBootstrap); + } + + kj::Maybe> readEmbed(LocatedText::Reader filename) override { + return translator.readEmbed(filename); + } + + private: + NodeTranslator& translator; + bool isBootstrap; + }; + + ResolverGlue glue(*this, isBootstrap); + ValueTranslator valueTranslator(glue, errorReporter, orphanage); + + KJ_IF_MAYBE(typeSchema, resolver.resolveBootstrapType(type, typeScope)) { + kj::StringPtr fieldName = Schema::from() + .getUnionFields()[static_cast(typeSchema->which())].getProto().getName(); + + KJ_IF_MAYBE(value, valueTranslator.compileValue(source, *typeSchema)) { + if (typeSchema->isEnum()) { + target.setEnum(value->getReader().as().getRaw()); + } else { + toDynamic(target).adopt(fieldName, kj::mv(*value)); + } + } + } +} + +kj::Maybe> ValueTranslator::compileValue(Expression::Reader src, Type type) { + Orphan result = compileValueInner(src, type); + + switch (result.getType()) { + case DynamicValue::UNKNOWN: + // Error already reported. + return nullptr; + + case DynamicValue::VOID: + if (type.isVoid()) { + return kj::mv(result); + } + break; + + case DynamicValue::BOOL: + if (type.isBool()) { + return kj::mv(result); + } + break; + + case DynamicValue::INT: { + int64_t value = result.getReader().as(); + if (value < 0) { + int64_t minValue = 1; + switch (type.which()) { + case schema::Type::INT8: minValue = (int8_t)kj::minValue; break; + case schema::Type::INT16: minValue = (int16_t)kj::minValue; break; + case schema::Type::INT32: minValue = (int32_t)kj::minValue; break; + case schema::Type::INT64: minValue = (int64_t)kj::minValue; break; + case schema::Type::UINT8: minValue = (uint8_t)kj::minValue; break; + case schema::Type::UINT16: minValue = (uint16_t)kj::minValue; break; + case schema::Type::UINT32: minValue = (uint32_t)kj::minValue; break; + case schema::Type::UINT64: minValue = (uint64_t)kj::minValue; break; + + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + // Any integer is acceptable. + minValue = (int64_t)kj::minValue; + break; + + default: break; + } + if (minValue == 1) break; + + if (value < minValue) { + errorReporter.addErrorOn(src, "Integer value out of range."); + result = minValue; + } + return kj::mv(result); + } + + // No break -- value is positive, so we can just go on to the uint case below. + } + + case DynamicValue::UINT: { + uint64_t maxValue = 0; + switch (type.which()) { + case schema::Type::INT8: maxValue = (int8_t)kj::maxValue; break; + case schema::Type::INT16: maxValue = (int16_t)kj::maxValue; break; + case schema::Type::INT32: maxValue = (int32_t)kj::maxValue; break; + case schema::Type::INT64: maxValue = (int64_t)kj::maxValue; break; + case schema::Type::UINT8: maxValue = (uint8_t)kj::maxValue; break; + case schema::Type::UINT16: maxValue = (uint16_t)kj::maxValue; break; + case schema::Type::UINT32: maxValue = (uint32_t)kj::maxValue; break; + case schema::Type::UINT64: maxValue = (uint64_t)kj::maxValue; break; + + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + // Any integer is acceptable. + maxValue = (uint64_t)kj::maxValue; + break; + + default: break; + } + if (maxValue == 0) break; + + if (result.getReader().as() > maxValue) { + errorReporter.addErrorOn(src, "Integer value out of range."); + result = maxValue; + } + return kj::mv(result); + } + + case DynamicValue::FLOAT: + if (type.isFloat32() || type.isFloat64()) { + return kj::mv(result); + } + break; + + case DynamicValue::TEXT: + if (type.isText()) { + return kj::mv(result); + } + break; + + case DynamicValue::DATA: + if (type.isData()) { + return kj::mv(result); + } + break; + + case DynamicValue::LIST: + if (type.isList()) { + if (result.getReader().as().getSchema() == type.asList()) { + return kj::mv(result); + } + } else if (type.isAnyPointer()) { + switch (type.whichAnyPointerKind()) { + case schema::Type::AnyPointer::Unconstrained::ANY_KIND: + case schema::Type::AnyPointer::Unconstrained::LIST: + return kj::mv(result); + case schema::Type::AnyPointer::Unconstrained::STRUCT: + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + break; + } + } + break; + + case DynamicValue::ENUM: + if (type.isEnum()) { + if (result.getReader().as().getSchema() == type.asEnum()) { + return kj::mv(result); + } + } + break; + + case DynamicValue::STRUCT: + if (type.isStruct()) { + if (result.getReader().as().getSchema() == type.asStruct()) { + return kj::mv(result); + } + } else if (type.isAnyPointer()) { + switch (type.whichAnyPointerKind()) { + case schema::Type::AnyPointer::Unconstrained::ANY_KIND: + case schema::Type::AnyPointer::Unconstrained::STRUCT: + return kj::mv(result); + case schema::Type::AnyPointer::Unconstrained::LIST: + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + break; + } + } + break; + + case DynamicValue::CAPABILITY: + KJ_FAIL_ASSERT("Interfaces can't have literal values."); + + case DynamicValue::ANY_POINTER: + KJ_FAIL_ASSERT("AnyPointers can't have literal values."); + } + + errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), ".")); + return nullptr; +} + +Orphan ValueTranslator::compileValueInner(Expression::Reader src, Type type) { + switch (src.which()) { + case Expression::RELATIVE_NAME: { + auto name = src.getRelativeName(); + + // The name is just a bare identifier. It may be a literal value or an enumerant. + kj::StringPtr id = name.getValue(); + + if (type.isEnum()) { + KJ_IF_MAYBE(enumerant, type.asEnum().findEnumerantByName(id)) { + return DynamicEnum(*enumerant); + } + } else { + // Interpret known constant values. + if (id == "void") { + return VOID; + } else if (id == "true") { + return true; + } else if (id == "false") { + return false; + } else if (id == "nan") { + return kj::nan(); + } else if (id == "inf") { + return kj::inf(); + } + } + + // Apparently not a literal. Try resolving it. + KJ_IF_MAYBE(constValue, resolver.resolveConstant(src)) { + return orphanage.newOrphanCopy(*constValue); + } else { + return nullptr; + } + } + + case Expression::ABSOLUTE_NAME: + case Expression::IMPORT: + case Expression::APPLICATION: + case Expression::MEMBER: + KJ_IF_MAYBE(constValue, resolver.resolveConstant(src)) { + return orphanage.newOrphanCopy(*constValue); + } else { + return nullptr; + } + + case Expression::EMBED: + KJ_IF_MAYBE(data, resolver.readEmbed(src.getEmbed())) { + switch (type.which()) { + case schema::Type::TEXT: { + // Sadly, we need to make a copy to add the NUL terminator. + auto text = orphanage.newOrphan(data->size()); + memcpy(text.get().begin(), data->begin(), data->size()); + return kj::mv(text); + } + case schema::Type::DATA: + // TODO(perf): It would arguably be neat to use orphanage.referenceExternalData(), + // since typically the data is mmap()ed and this would avoid forcing a large file + // to become memory-resident. However, we'd have to figure out who should own the + // Array. Also, we'd have to deal with the possibility of misaligned data -- + // though arguably in that case we know it's not mmap()ed so whatever. One more + // thing: it would be neat to be able to reference text blobs this way too, if only + // we could rely on the assumption that as long as the data doesn't end on a page + // boundary, it will be zero-padded, thus giving us our NUL terminator (4095/4096 of + // the time), but this seems to require documenting constraints on the underlying + // file-reading interfaces. Hm. + return orphanage.newOrphanCopy(Data::Reader(*data)); + case schema::Type::STRUCT: { + // We will almost certainly + if (data->size() % sizeof(word) != 0) { + errorReporter.addErrorOn(src, + "Embedded file is not a valid Cap'n Proto message."); + return nullptr; + } + kj::Array copy; + kj::ArrayPtr words; + if (reinterpret_cast(data->begin()) % sizeof(void*) == 0) { + // Hooray, data is aligned. + words = kj::ArrayPtr( + reinterpret_cast(data->begin()), + data->size() / sizeof(word)); + } else { + // Ugh, data not aligned. Make a copy. + copy = kj::heapArray(data->size() / sizeof(word)); + memcpy(copy.begin(), data->begin(), data->size()); + words = copy; + } + ReaderOptions options; + options.traversalLimitInWords = kj::maxValue; + options.nestingLimit = kj::maxValue; + FlatArrayMessageReader reader(words, options); + return orphanage.newOrphanCopy(reader.getRoot(type.asStruct())); + } + default: + errorReporter.addErrorOn(src, + "Embeds can only be used when Text, Data, or a struct is expected."); + return nullptr; + } + } else { + return nullptr; + } + + case Expression::POSITIVE_INT: + return src.getPositiveInt(); + + case Expression::NEGATIVE_INT: { + uint64_t nValue = src.getNegativeInt(); + if (nValue > ((uint64_t)kj::maxValue >> 1) + 1) { + errorReporter.addErrorOn(src, "Integer is too big to be negative."); + return nullptr; + } else { + return kj::implicitCast(-nValue); + } + } + + case Expression::FLOAT: + return src.getFloat(); + break; + + case Expression::STRING: + if (type.isData()) { + Text::Reader text = src.getString(); + return orphanage.newOrphanCopy(Data::Reader(text.asBytes())); + } else { + return orphanage.newOrphanCopy(src.getString()); + } + break; + + case Expression::BINARY: + if (!type.isData()) { + errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), ".")); + return nullptr; + } + return orphanage.newOrphanCopy(src.getBinary()); + + case Expression::LIST: { + if (!type.isList()) { + errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), ".")); + return nullptr; + } + auto listSchema = type.asList(); + Type elementType = listSchema.getElementType(); + auto srcList = src.getList(); + Orphan result = orphanage.newOrphan(listSchema, srcList.size()); + auto dstList = result.get(); + for (uint i = 0; i < srcList.size(); i++) { + KJ_IF_MAYBE(value, compileValue(srcList[i], elementType)) { + dstList.adopt(i, kj::mv(*value)); + } + } + return kj::mv(result); + } + + case Expression::TUPLE: { + if (!type.isStruct()) { + errorReporter.addErrorOn(src, kj::str("Type mismatch; expected ", makeTypeName(type), ".")); + return nullptr; + } + auto structSchema = type.asStruct(); + Orphan result = orphanage.newOrphan(structSchema); + fillStructValue(result.get(), src.getTuple()); + return kj::mv(result); + } + + case Expression::UNKNOWN: + // Ignore earlier error. + return nullptr; + } + + KJ_UNREACHABLE; +} + +void ValueTranslator::fillStructValue(DynamicStruct::Builder builder, + List::Reader assignments) { + for (auto assignment: assignments) { + if (assignment.isNamed()) { + auto fieldName = assignment.getNamed(); + KJ_IF_MAYBE(field, builder.getSchema().findFieldByName(fieldName.getValue())) { + auto fieldProto = field->getProto(); + auto value = assignment.getValue(); + + switch (fieldProto.which()) { + case schema::Field::SLOT: + KJ_IF_MAYBE(compiledValue, compileValue(value, field->getType())) { + builder.adopt(*field, kj::mv(*compiledValue)); + } + break; + + case schema::Field::GROUP: + if (value.isTuple()) { + fillStructValue(builder.init(*field).as(), value.getTuple()); + } else { + errorReporter.addErrorOn(value, "Type mismatch; expected group."); + } + break; + } + } else { + errorReporter.addErrorOn(fieldName, kj::str( + "Struct has no field named '", fieldName.getValue(), "'.")); + } + } else { + errorReporter.addErrorOn(assignment.getValue(), kj::str("Missing field name.")); + } + } +} + +kj::String ValueTranslator::makeNodeName(Schema schema) { + schema::Node::Reader proto = schema.getProto(); + return kj::str(proto.getDisplayName().slice(proto.getDisplayNamePrefixLength())); +} + +kj::String ValueTranslator::makeTypeName(Type type) { + switch (type.which()) { + case schema::Type::VOID: return kj::str("Void"); + case schema::Type::BOOL: return kj::str("Bool"); + case schema::Type::INT8: return kj::str("Int8"); + case schema::Type::INT16: return kj::str("Int16"); + case schema::Type::INT32: return kj::str("Int32"); + case schema::Type::INT64: return kj::str("Int64"); + case schema::Type::UINT8: return kj::str("UInt8"); + case schema::Type::UINT16: return kj::str("UInt16"); + case schema::Type::UINT32: return kj::str("UInt32"); + case schema::Type::UINT64: return kj::str("UInt64"); + case schema::Type::FLOAT32: return kj::str("Float32"); + case schema::Type::FLOAT64: return kj::str("Float64"); + case schema::Type::TEXT: return kj::str("Text"); + case schema::Type::DATA: return kj::str("Data"); + case schema::Type::LIST: + return kj::str("List(", makeTypeName(type.asList().getElementType()), ")"); + case schema::Type::ENUM: return makeNodeName(type.asEnum()); + case schema::Type::STRUCT: return makeNodeName(type.asStruct()); + case schema::Type::INTERFACE: return makeNodeName(type.asInterface()); + case schema::Type::ANY_POINTER: return kj::str("AnyPointer"); + } + KJ_UNREACHABLE; +} + +kj::Maybe NodeTranslator::readConstant( + Expression::Reader source, bool isBootstrap) { + // Look up the constant decl. + NodeTranslator::BrandedDecl constDecl = nullptr; + KJ_IF_MAYBE(decl, compileDeclExpression(source, noImplicitParams())) { + constDecl = *decl; + } else { + // Lookup will have reported an error. + return nullptr; + } + + // Is it a constant? + if(constDecl.getKind().orDefault(Declaration::FILE) != Declaration::CONST) { + errorReporter.addErrorOn(source, + kj::str("'", expressionString(source), "' does not refer to a constant.")); + return nullptr; + } + + // Extract the ID and brand. + MallocMessageBuilder builder(256); + auto constBrand = builder.getRoot(); + uint64_t id = constDecl.getIdAndFillBrand([&]() { return constBrand; }); + + // Look up the schema -- we'll need this to compile the constant's type. + Schema constSchema; + KJ_IF_MAYBE(s, resolver.resolveBootstrapSchema(id, constBrand)) { + constSchema = *s; + } else { + // The constant's schema is broken for reasons already reported. + return nullptr; + } + + // If we're bootstrapping, then we know we're expecting a primitive value, so if the + // constant turns out to be non-primitive, we'll error out anyway. If we're not + // bootstrapping, we may be compiling a non-primitive value and so we need the final + // version of the constant to make sure its value is filled in. + schema::Node::Reader proto = constSchema.getProto(); + if (!isBootstrap) { + KJ_IF_MAYBE(finalProto, resolver.resolveFinalSchema(id)) { + proto = *finalProto; + } else { + // The constant's final schema is broken for reasons already reported. + return nullptr; + } + } + + auto constReader = proto.getConst(); + auto dynamicConst = toDynamic(constReader.getValue()); + auto constValue = dynamicConst.get(KJ_ASSERT_NONNULL(dynamicConst.which())); + + if (constValue.getType() == DynamicValue::ANY_POINTER) { + // We need to assign an appropriate schema to this pointer. + AnyPointer::Reader objValue = constValue.as(); + + auto constType = constSchema.asConst().getType(); + switch (constType.which()) { + case schema::Type::STRUCT: + constValue = objValue.getAs(constType.asStruct()); + break; + case schema::Type::LIST: + constValue = objValue.getAs(constType.asList()); + break; + case schema::Type::ANY_POINTER: + // Fine as-is. + break; + default: + KJ_FAIL_ASSERT("Unrecognized AnyPointer-typed member of schema::Value."); + break; + } + } + + if (source.isRelativeName()) { + // A fully unqualified identifier looks like it might refer to a constant visible in the + // current scope, but if that's really what the user wanted, we want them to use a + // qualified name to make it more obvious. Report an error. + KJ_IF_MAYBE(scope, resolver.resolveBootstrapSchema(proto.getScopeId(), + schema::Brand::Reader())) { + auto scopeReader = scope->getProto(); + kj::StringPtr parent; + if (scopeReader.isFile()) { + parent = ""; + } else { + parent = scopeReader.getDisplayName().slice(scopeReader.getDisplayNamePrefixLength()); + } + kj::StringPtr id = source.getRelativeName().getValue(); + + errorReporter.addErrorOn(source, kj::str( + "Constant names must be qualified to avoid confusion. Please replace '", + expressionString(source), "' with '", parent, ".", id, + "', if that's what you intended.")); + } + } + + return constValue; +} + +kj::Maybe> NodeTranslator::readEmbed(LocatedText::Reader filename) { + KJ_IF_MAYBE(data, resolver.readEmbed(filename.getValue())) { + return kj::mv(*data); + } else { + errorReporter.addErrorOn(filename, + kj::str("Couldn't read file for embed: ", filename.getValue())); + return nullptr; + } +} + +Orphan> NodeTranslator::compileAnnotationApplications( + List::Reader annotations, + kj::StringPtr targetsFlagName) { + if (annotations.size() == 0 || !compileAnnotations) { + // Return null. + return Orphan>(); + } + + auto result = orphanage.newOrphan>(annotations.size()); + auto builder = result.get(); + + for (uint i = 0; i < annotations.size(); i++) { + Declaration::AnnotationApplication::Reader annotation = annotations[i]; + schema::Annotation::Builder annotationBuilder = builder[i]; + + // Set the annotation's value to void in case we fail to produce something better below. + annotationBuilder.initValue().setVoid(); + + auto name = annotation.getName(); + KJ_IF_MAYBE(decl, compileDeclExpression(name, noImplicitParams())) { + KJ_IF_MAYBE(kind, decl->getKind()) { + if (*kind != Declaration::ANNOTATION) { + errorReporter.addErrorOn(name, kj::str( + "'", expressionString(name), "' is not an annotation.")); + } else { + annotationBuilder.setId(decl->getIdAndFillBrand( + [&]() { return annotationBuilder.initBrand(); })); + KJ_IF_MAYBE(annotationSchema, + resolver.resolveBootstrapSchema(annotationBuilder.getId(), + annotationBuilder.getBrand())) { + auto node = annotationSchema->getProto().getAnnotation(); + if (!toDynamic(node).get(targetsFlagName).as()) { + errorReporter.addErrorOn(name, kj::str( + "'", expressionString(name), "' cannot be applied to this kind of declaration.")); + } + + // Interpret the value. + auto value = annotation.getValue(); + switch (value.which()) { + case Declaration::AnnotationApplication::Value::NONE: + // No value, i.e. void. + if (node.getType().isVoid()) { + annotationBuilder.getValue().setVoid(); + } else { + errorReporter.addErrorOn(name, kj::str( + "'", expressionString(name), "' requires a value.")); + compileDefaultDefaultValue(node.getType(), annotationBuilder.getValue()); + } + break; + + case Declaration::AnnotationApplication::Value::EXPRESSION: + compileBootstrapValue(value.getExpression(), node.getType(), + annotationBuilder.getValue(), + *annotationSchema); + break; + } + } + } + } else if (*kind != Declaration::ANNOTATION) { + errorReporter.addErrorOn(name, kj::str( + "'", expressionString(name), "' is not an annotation.")); + } + } + } + + return result; +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/node-translator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/node-translator.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,311 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPILER_NODE_TRANSLATOR_H_ +#define CAPNP_COMPILER_NODE_TRANSLATOR_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include +#include +#include +#include +#include "error-reporter.h" + +namespace capnp { +namespace compiler { + +class NodeTranslator { + // Translates one node in the schema from AST form to final schema form. A "node" is anything + // that has a unique ID, such as structs, enums, constants, and annotations, but not fields, + // unions, enumerants, or methods (the latter set have 16-bit ordinals but not 64-bit global IDs). + +public: + class Resolver { + // Callback class used to find other nodes relative to this one. + // + // TODO(cleanup): This has evolved into being a full interface for traversing the node tree. + // Maybe we should rename it as such, and move it out of NodeTranslator. See also + // TODO(cleanup) on NodeTranslator::BrandedDecl. + + public: + struct ResolvedDecl { + uint64_t id; + uint genericParamCount; + uint64_t scopeId; + Declaration::Which kind; + Resolver* resolver; + + kj::Maybe brand; + // If present, then it is necessary to replace the brand scope with the given brand before + // using the target type. This happens when the decl resolved to an alias; all other fields + // of `ResolvedDecl` refer to the target of the alias, except for `scopeId` which is the + // scope that contained the alias. + }; + + struct ResolvedParameter { + uint64_t id; // ID of the node declaring the parameter. + uint index; // Index of the parameter. + }; + + typedef kj::OneOf ResolveResult; + + virtual kj::Maybe resolve(kj::StringPtr name) = 0; + // Look up the given name, relative to this node, and return basic information about the + // target. + + virtual kj::Maybe resolveMember(kj::StringPtr name) = 0; + // Look up a member of this node. + + virtual ResolvedDecl resolveBuiltin(Declaration::Which which) = 0; + virtual ResolvedDecl resolveId(uint64_t id) = 0; + + virtual kj::Maybe getParent() = 0; + // Returns the parent of this scope, or null if this is the top scope. + + virtual ResolvedDecl getTopScope() = 0; + // Get the top-level scope containing this node. + + virtual kj::Maybe resolveBootstrapSchema(uint64_t id, schema::Brand::Reader brand) = 0; + // Get the schema for the given ID. If a schema is returned, it must be safe to traverse its + // dependencies via the Schema API. A schema that is only at the bootstrap stage is + // acceptable. + // + // Throws an exception if the id is not one that was found by calling resolve() or by + // traversing other schemas. Returns null if the ID is recognized, but the corresponding + // schema node failed to be built for reasons that were already reported. + + virtual kj::Maybe resolveFinalSchema(uint64_t id) = 0; + // Get the final schema for the given ID. A bootstrap schema is not acceptable. A raw + // node reader is returned rather than a Schema object because using a Schema object built + // by the final schema loader could trigger lazy initialization of dependencies which could + // lead to a cycle and deadlock. + // + // Throws an exception if the id is not one that was found by calling resolve() or by + // traversing other schemas. Returns null if the ID is recognized, but the corresponding + // schema node failed to be built for reasons that were already reported. + + virtual kj::Maybe resolveImport(kj::StringPtr name) = 0; + // Get the ID of an imported file given the import path. + + virtual kj::Maybe> readEmbed(kj::StringPtr name) = 0; + // Read and return the contents of a file for an `embed` expression. + + virtual kj::Maybe resolveBootstrapType(schema::Type::Reader type, Schema scope) = 0; + // Compile a schema::Type into a Type whose dependencies may safely be traversed via the schema + // API. These dependencies may have only bootstrap schemas. Returns null if the type could not + // be constructed due to already-reported errors. + }; + + NodeTranslator(Resolver& resolver, ErrorReporter& errorReporter, + const Declaration::Reader& decl, Orphan wipNode, + bool compileAnnotations); + // Construct a NodeTranslator to translate the given declaration. The wipNode starts out with + // `displayName`, `id`, `scopeId`, and `nestedNodes` already initialized. The `NodeTranslator` + // fills in the rest. + + ~NodeTranslator() noexcept(false); + + struct NodeSet { + schema::Node::Reader node; + // The main node. + + kj::Array auxNodes; + // Auxiliary nodes that were produced when translating this node and should be loaded along + // with it. In particular, structs that contain groups (or named unions) spawn extra nodes + // representing those, and interfaces spawn struct nodes representing method params/results. + }; + + NodeSet getBootstrapNode(); + // Get an incomplete version of the node in which pointer-typed value expressions have not yet + // been translated. Instead, for all `schema.Value` objects representing pointer-type values, + // the value is set to an appropriate "empty" value. This version of the schema can be used to + // bootstrap the dynamic API which can then in turn be used to encode the missing complex values. + // + // If the final node has already been built, this will actually return the final node (in fact, + // it's the same node object). + + NodeSet finish(); + // Finish translating the node (including filling in all the pieces that are missing from the + // bootstrap node) and return it. + + static kj::Maybe compileDecl( + uint64_t scopeId, uint scopeParameterCount, Resolver& resolver, ErrorReporter& errorReporter, + Expression::Reader expression, schema::Brand::Builder brandBuilder); + // Compile a one-off declaration expression without building a NodeTranslator. Used for + // evaluating aliases. + // + // `brandBuilder` may be used to construct a message which will fill in ResolvedDecl::brand in + // the result. + +private: + class DuplicateNameDetector; + class DuplicateOrdinalDetector; + class StructLayout; + class StructTranslator; + class BrandedDecl; + class BrandScope; + + Resolver& resolver; + ErrorReporter& errorReporter; + Orphanage orphanage; + bool compileAnnotations; + kj::Own localBrand; + + Orphan wipNode; + // The work-in-progress schema node. + + kj::Vector> groups; + // If this is a struct node and it contains groups, these are the nodes for those groups, which + // must be loaded together with the top-level node. + + kj::Vector> paramStructs; + // If this is an interface, these are the auto-generated structs representing params and results. + + struct UnfinishedValue { + Expression::Reader source; + schema::Type::Reader type; + Schema typeScope; + schema::Value::Builder target; + }; + kj::Vector unfinishedValues; + // List of values in `wipNode` which have not yet been interpreted, because they are structs + // or lists and as such interpreting them require using the types' schemas (to take advantage + // of the dynamic API). Once bootstrap schemas have been built, they can be used to interpret + // these values. + + void compileNode(Declaration::Reader decl, schema::Node::Builder builder); + + void compileConst(Declaration::Const::Reader decl, schema::Node::Const::Builder builder); + void compileAnnotation(Declaration::Annotation::Reader decl, + schema::Node::Annotation::Builder builder); + + void compileEnum(Void decl, List::Reader members, + schema::Node::Builder builder); + void compileStruct(Void decl, List::Reader members, + schema::Node::Builder builder); + void compileInterface(Declaration::Interface::Reader decl, + List::Reader members, + schema::Node::Builder builder); + // The `members` arrays contain only members with ordinal numbers, in code order. Other members + // are handled elsewhere. + + struct ImplicitParams { + // Represents a set of implicit parameters visible in the current context. + + uint64_t scopeId; + // If zero, then any reference to an implciit param in this context should be compiled to a + // `implicitMethodParam` AnyPointer. If non-zero, it should be complied to a `parameter` + // AnyPointer. + + List::Reader params; + }; + + static inline ImplicitParams noImplicitParams() { + return { 0, List::Reader() }; + } + + template + uint64_t compileParamList(kj::StringPtr methodName, uint16_t ordinal, bool isResults, + Declaration::ParamList::Reader paramList, + typename List::Reader implicitParams, + InitBrandFunc&& initBrand); + // Compile a param (or result) list and return the type ID of the struct type. + + kj::Maybe compileDeclExpression( + Expression::Reader source, ImplicitParams implicitMethodParams); + // Compile an expression which is expected to resolve to a declaration or type expression. + + bool compileType(Expression::Reader source, schema::Type::Builder target, + ImplicitParams implicitMethodParams); + // Returns false if there was a problem, in which case value expressions of this type should + // not be parsed. + + void compileDefaultDefaultValue(schema::Type::Reader type, schema::Value::Builder target); + // Initializes `target` to contain the "default default" value for `type`. + + void compileBootstrapValue( + Expression::Reader source, schema::Type::Reader type, schema::Value::Builder target, + Schema typeScope = Schema()); + // Calls compileValue() if this value should be interpreted at bootstrap time. Otheriwse, + // adds the value to `unfinishedValues` for later evaluation. + // + // If `type` comes from some other node, `typeScope` is the schema for that node. This is only + // really needed for looking up generic parameter bindings, therefore if the type comes from + // the node being built, an empty "Schema" (the default) works here because the node being built + // is of course being built for all possible bindings and thus none of its generic parameters are + // bound. + + void compileValue(Expression::Reader source, schema::Type::Reader type, + Schema typeScope, schema::Value::Builder target, bool isBootstrap); + // Interprets the value expression and initializes `target` with the result. + + kj::Maybe readConstant(Expression::Reader name, bool isBootstrap); + // Get the value of the given constant. May return null if some error occurs, which will already + // have been reported. + + kj::Maybe> readEmbed(LocatedText::Reader filename); + // Read a raw file for embedding. + + Orphan> compileAnnotationApplications( + List::Reader annotations, + kj::StringPtr targetsFlagName); +}; + +class ValueTranslator { +public: + class Resolver { + public: + virtual kj::Maybe resolveConstant(Expression::Reader name) = 0; + virtual kj::Maybe> readEmbed(LocatedText::Reader filename) = 0; + }; + + ValueTranslator(Resolver& resolver, ErrorReporter& errorReporter, Orphanage orphanage) + : resolver(resolver), errorReporter(errorReporter), orphanage(orphanage) {} + + kj::Maybe> compileValue(Expression::Reader src, Type type); + + void fillStructValue(DynamicStruct::Builder builder, + List::Reader assignments); + // Interprets the given assignments and uses them to fill in the given struct builder. + +private: + Resolver& resolver; + ErrorReporter& errorReporter; + Orphanage orphanage; + + Orphan compileValueInner(Expression::Reader src, Type type); + // Helper for compileValue(). + + kj::String makeNodeName(Schema node); + kj::String makeTypeName(Type type); + + kj::Maybe makeListSchemaOf(schema::Type::Reader elementType); +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_NODE_TRANSLATOR_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/parser.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/parser.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1134 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "parser.h" +#include "md5.h" +#include +#include +#if !_MSC_VER +#include +#endif +#include +#include +#include + +#if _WIN32 +#include +#undef VOID +#endif + +namespace capnp { +namespace compiler { + +uint64_t generateRandomId() { + uint64_t result; + +#if _WIN32 + HCRYPTPROV handle; + KJ_ASSERT(CryptAcquireContextW(&handle, nullptr, nullptr, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)); + KJ_DEFER(KJ_ASSERT(CryptReleaseContext(handle, 0)) {break;}); + + KJ_ASSERT(CryptGenRandom(handle, sizeof(result), reinterpret_cast(&result))); + +#else + int fd; + KJ_SYSCALL(fd = open("/dev/urandom", O_RDONLY)); + + ssize_t n; + KJ_SYSCALL(n = read(fd, &result, sizeof(result)), "/dev/urandom"); + KJ_ASSERT(n == sizeof(result), "Incomplete read from /dev/urandom.", n); +#endif + + return result | (1ull << 63); +} + +uint64_t generateChildId(uint64_t parentId, kj::StringPtr childName) { + // Compute ID by MD5 hashing the concatenation of the parent ID and the declaration name, and + // then taking the first 8 bytes. + + kj::byte parentIdBytes[sizeof(uint64_t)]; + for (uint i = 0; i < sizeof(uint64_t); i++) { + parentIdBytes[i] = (parentId >> (i * 8)) & 0xff; + } + + Md5 md5; + md5.update(kj::arrayPtr(parentIdBytes, kj::size(parentIdBytes))); + md5.update(childName); + + kj::ArrayPtr resultBytes = md5.finish(); + + uint64_t result = 0; + for (uint i = 0; i < sizeof(uint64_t); i++) { + result = (result << 8) | resultBytes[i]; + } + + return result | (1ull << 63); +} + +uint64_t generateGroupId(uint64_t parentId, uint16_t groupIndex) { + // Compute ID by MD5 hashing the concatenation of the parent ID and the group index, and + // then taking the first 8 bytes. + + kj::byte bytes[sizeof(uint64_t) + sizeof(uint16_t)]; + for (uint i = 0; i < sizeof(uint64_t); i++) { + bytes[i] = (parentId >> (i * 8)) & 0xff; + } + for (uint i = 0; i < sizeof(uint16_t); i++) { + bytes[sizeof(uint64_t) + i] = (groupIndex >> (i * 8)) & 0xff; + } + + Md5 md5; + md5.update(bytes); + + kj::ArrayPtr resultBytes = md5.finish(); + + uint64_t result = 0; + for (uint i = 0; i < sizeof(uint64_t); i++) { + result = (result << 8) | resultBytes[i]; + } + + return result | (1ull << 63); +} + +uint64_t generateMethodParamsId(uint64_t parentId, uint16_t methodOrdinal, bool isResults) { + // Compute ID by MD5 hashing the concatenation of the parent ID, the method ordinal, and a + // boolean indicating whether this is the params or the results, and then taking the first 8 + // bytes. + + kj::byte bytes[sizeof(uint64_t) + sizeof(uint16_t) + 1]; + for (uint i = 0; i < sizeof(uint64_t); i++) { + bytes[i] = (parentId >> (i * 8)) & 0xff; + } + for (uint i = 0; i < sizeof(uint16_t); i++) { + bytes[sizeof(uint64_t) + i] = (methodOrdinal >> (i * 8)) & 0xff; + } + bytes[sizeof(bytes) - 1] = isResults; + + Md5 md5; + md5.update(bytes); + + kj::ArrayPtr resultBytes = md5.finish(); + + uint64_t result = 0; + for (uint i = 0; i < sizeof(uint64_t); i++) { + result = (result << 8) | resultBytes[i]; + } + + return result | (1ull << 63); +} + +void parseFile(List::Reader statements, ParsedFile::Builder result, + ErrorReporter& errorReporter) { + CapnpParser parser(Orphanage::getForMessageContaining(result), errorReporter); + + kj::Vector> decls(statements.size()); + kj::Vector> annotations; + + auto fileDecl = result.getRoot(); + fileDecl.setFile(VOID); + + for (auto statement: statements) { + KJ_IF_MAYBE(decl, parser.parseStatement(statement, parser.getParsers().fileLevelDecl)) { + Declaration::Builder builder = decl->get(); + switch (builder.which()) { + case Declaration::NAKED_ID: + if (fileDecl.getId().isUid()) { + errorReporter.addError(builder.getStartByte(), builder.getEndByte(), + "File can only have one ID."); + } else { + fileDecl.getId().adoptUid(builder.disownNakedId()); + if (builder.hasDocComment()) { + fileDecl.adoptDocComment(builder.disownDocComment()); + } + } + break; + case Declaration::NAKED_ANNOTATION: + annotations.add(builder.disownNakedAnnotation()); + break; + default: + decls.add(kj::mv(*decl)); + break; + } + } + } + + if (fileDecl.getId().which() != Declaration::Id::UID) { + // We didn't see an ID. Generate one randomly for now. + uint64_t id = generateRandomId(); + fileDecl.getId().initUid().setValue(id); + + // Don't report missing ID if there was a parse error, because quite often the parse error + // prevents us from parsing the ID even though it is actually there. + if (!errorReporter.hadErrors()) { + errorReporter.addError(0, 0, + kj::str("File does not declare an ID. I've generated one for you. Add this line to " + "your file: @0x", kj::hex(id), ";")); + } + } + + auto declsBuilder = fileDecl.initNestedDecls(decls.size()); + for (size_t i = 0; i < decls.size(); i++) { + declsBuilder.adoptWithCaveats(i, kj::mv(decls[i])); + } + + auto annotationsBuilder = fileDecl.initAnnotations(annotations.size()); + for (size_t i = 0; i < annotations.size(); i++) { + annotationsBuilder.adoptWithCaveats(i, kj::mv(annotations[i])); + } +} + +namespace p = kj::parse; + +namespace { + +// ======================================================================================= + +template +struct Located { + T value; + uint32_t startByte; + uint32_t endByte; + + template + void copyLocationTo(Builder builder) { + builder.setStartByte(startByte); + builder.setEndByte(endByte); + } + template + void copyTo(Builder builder) { + builder.setValue(value); + copyLocationTo(builder); + } + template + Orphan asProto(Orphanage orphanage) { + auto result = orphanage.newOrphan(); + copyTo(result.get()); + return result; + } + template + Located> rewrap(Other&& other) { + return Located(kj::fwd(other), startByte, endByte); + } + + Located(const T& value, uint32_t startByte, uint32_t endByte) + : value(value), startByte(startByte), endByte(endByte) {} + Located(T&& value, uint32_t startByte, uint32_t endByte) + : value(kj::mv(value)), startByte(startByte), endByte(endByte) {} +}; + +// ======================================================================================= + +template +struct MatchTokenType { + kj::Maybe> operator()(Token::Reader token) const { + if (token.which() == type) { + return Located((token.*get)(), token.getStartByte(), token.getEndByte()); + } else { + return nullptr; + } + } +}; + +#define TOKEN_TYPE_PARSER(type, discrim, getter) \ + p::transformOrReject(p::any, \ + MatchTokenType()) + +constexpr auto identifier = TOKEN_TYPE_PARSER(Text::Reader, IDENTIFIER, getIdentifier); +constexpr auto stringLiteral = TOKEN_TYPE_PARSER(Text::Reader, STRING_LITERAL, getStringLiteral); +constexpr auto binaryLiteral = TOKEN_TYPE_PARSER(Data::Reader, BINARY_LITERAL, getBinaryLiteral); +constexpr auto integerLiteral = TOKEN_TYPE_PARSER(uint64_t, INTEGER_LITERAL, getIntegerLiteral); +constexpr auto floatLiteral = TOKEN_TYPE_PARSER(double, FLOAT_LITERAL, getFloatLiteral); +constexpr auto operatorToken = TOKEN_TYPE_PARSER(Text::Reader, OPERATOR, getOperator); +constexpr auto rawParenthesizedList = + TOKEN_TYPE_PARSER(List>::Reader, PARENTHESIZED_LIST, getParenthesizedList); +constexpr auto rawBracketedList = + TOKEN_TYPE_PARSER(List>::Reader, BRACKETED_LIST, getBracketedList); + +// ======================================================================================= + +class ExactString { +public: + constexpr ExactString(const char* expected): expected(expected) {} + + kj::Maybe> operator()(Located&& text) const { + if (text.value == expected) { + return kj::Tuple<>(); + } else { + return nullptr; + } + } + +private: + const char* expected; +}; + +constexpr auto keyword(const char* expected) + -> decltype(p::transformOrReject(identifier, ExactString(expected))) { + return p::transformOrReject(identifier, ExactString(expected)); +} + +constexpr auto op(const char* expected) + -> decltype(p::transformOrReject(operatorToken, ExactString(expected))) { + return p::transformOrReject(operatorToken, ExactString(expected)); +} + +// ======================================================================================= + +template +class ParseListItems { + // Transformer that parses all items in the input token sequence list using the given parser. + +public: + constexpr ParseListItems(ItemParser&& itemParser, ErrorReporter& errorReporter) + : itemParser(p::sequence(kj::fwd(itemParser), p::endOfInput)), + errorReporter(errorReporter) {} + + Located>>> operator()( + Located>::Reader>&& items) const { + auto result = kj::heapArray>>( + items.value.size()); + for (uint i = 0; i < items.value.size(); i++) { + auto item = items.value[i]; + CapnpParser::ParserInput input(item.begin(), item.end()); + result[i] = itemParser(input); + if (result[i] == nullptr) { + // Parsing failed. Report an error. + auto best = input.getBest(); + if (best < item.end()) { + // Report error from the point where parsing failed to the end of the item. + errorReporter.addError( + best->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error."); + } else if (item.size() > 0) { + // The item is non-empty and the parser consumed all of it before failing. Report an + // error for the whole thing. + errorReporter.addError( + item.begin()->getStartByte(), (item.end() - 1)->getEndByte(), "Parse error."); + } else { + // The item has no content. + // TODO(cleanup): We don't actually know the item's location, so we can only report + // an error across the whole list. Fix this. + errorReporter.addError(items.startByte, items.endByte, "Parse error: Empty list item."); + } + } + } + return Located>>>( + kj::mv(result), items.startByte, items.endByte); + } + +private: + decltype(p::sequence(kj::instance(), p::endOfInput)) itemParser; + ErrorReporter& errorReporter; +}; + +template +constexpr auto parenthesizedList(ItemParser&& itemParser, ErrorReporter& errorReporter) -> decltype( + transform(rawParenthesizedList, ParseListItems( + kj::fwd(itemParser), errorReporter))) { + return transform(rawParenthesizedList, ParseListItems( + kj::fwd(itemParser), errorReporter)); +} + +template +constexpr auto bracketedList(ItemParser&& itemParser, ErrorReporter& errorReporter) -> decltype( + transform(rawBracketedList, ParseListItems( + kj::fwd(itemParser), errorReporter))) { + return transform(rawBracketedList, ParseListItems( + kj::fwd(itemParser), errorReporter)); +} + +// ======================================================================================= + +template +Orphan> arrayToList(Orphanage& orphanage, kj::Array>&& elements) { + auto result = orphanage.newOrphan>(elements.size()); + auto builder = result.get(); + for (size_t i = 0; i < elements.size(); i++) { + builder.adoptWithCaveats(i, kj::mv(elements[i])); + } + return kj::mv(result); +} + +static void initGenericParams(Declaration::Builder builder, + kj::Maybe>>>>&& genericParameters) { + KJ_IF_MAYBE(p, genericParameters) { + auto params = builder.initParameters(p->value.size()); + for (uint i: kj::indices(p->value)) { + KJ_IF_MAYBE(name, p->value[i]) { + auto param = params[i]; + param.setName(name->value); + name->copyLocationTo(param); + } + } + } +} + +static Declaration::Builder initDecl( + Declaration::Builder builder, Located&& name, + kj::Maybe>&& id, + kj::Maybe>>>>&& genericParameters, + kj::Array>&& annotations) { + name.copyTo(builder.initName()); + KJ_IF_MAYBE(i, id) { + builder.getId().adoptUid(kj::mv(*i)); + } + + initGenericParams(builder, kj::mv(genericParameters)); + + auto list = builder.initAnnotations(annotations.size()); + for (uint i = 0; i < annotations.size(); i++) { + list.adoptWithCaveats(i, kj::mv(annotations[i])); + } + return builder; +} + +static Declaration::Builder initMemberDecl( + Declaration::Builder builder, Located&& name, + Orphan&& ordinal, + kj::Array>&& annotations) { + name.copyTo(builder.initName()); + builder.getId().adoptOrdinal(kj::mv(ordinal)); + auto list = builder.initAnnotations(annotations.size()); + for (uint i = 0; i < annotations.size(); i++) { + list.adoptWithCaveats(i, kj::mv(annotations[i])); + } + return builder; +} + +template +void initLocation(kj::parse::Span::Reader::Iterator> location, + BuilderType builder) { + if (location.begin() < location.end()) { + builder.setStartByte(location.begin()->getStartByte()); + builder.setEndByte((location.end() - 1)->getEndByte()); + } +} + +} // namespace + +// ======================================================================================= + +CapnpParser::CapnpParser(Orphanage orphanageParam, ErrorReporter& errorReporterParam) + : orphanage(orphanageParam), errorReporter(errorReporterParam) { + auto& tupleElement = arena.copy(p::transform( + p::sequence(p::optional(p::sequence(identifier, op("="))), parsers.expression), + [this](kj::Maybe>&& fieldName, Orphan&& fieldValue) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + KJ_IF_MAYBE(fn, fieldName) { + fn->copyTo(builder.initNamed()); + } else { + builder.setUnnamed(); + } + builder.adoptValue(kj::mv(fieldValue)); + return kj::mv(result); + })); + + auto& tuple = arena.copy>>>>( + arena.copy(p::transform( + parenthesizedList(tupleElement, errorReporter), + [this](Located>>>&& elements) + -> Located>> { + auto result = orphanage.newOrphan>(elements.value.size()); + auto builder = result.get(); + for (uint i: kj::indices(elements.value)) { + KJ_IF_MAYBE(e, elements.value[i]) { + builder.adoptWithCaveats(i, kj::mv(*e)); + } else { + builder[i].initValue().setUnknown(); + } + } + return elements.rewrap(kj::mv(result)); + }))); + + parsers.expression = arena.copy(p::transform( + p::sequence( + // Base expression. + p::oneOf( + p::transform(integerLiteral, + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setPositiveInt(value.value); + value.copyLocationTo(builder); + return result; + }), + p::transform(p::sequence(op("-"), integerLiteral), + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setNegativeInt(value.value); + value.copyLocationTo(builder); + return result; + }), + p::transform(floatLiteral, + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setFloat(value.value); + value.copyLocationTo(builder); + return result; + }), + p::transform(p::sequence(op("-"), floatLiteral), + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setFloat(-value.value); + value.copyLocationTo(builder); + return result; + }), + p::transformWithLocation(p::sequence(op("-"), keyword("inf")), + [this](kj::parse::Span::Reader::Iterator> location) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setFloat(-kj::inf()); + initLocation(location, builder); + return result; + }), + p::transform(stringLiteral, + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setString(value.value); + value.copyLocationTo(builder); + return result; + }), + p::transform(binaryLiteral, + [this](Located&& value) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.setBinary(value.value); + value.copyLocationTo(builder); + return result; + }), + p::transform(bracketedList(parsers.expression, errorReporter), + [this](Located>>>&& value) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + auto listBuilder = builder.initList(value.value.size()); + for (uint i = 0; i < value.value.size(); i++) { + KJ_IF_MAYBE(element, value.value[i]) { + listBuilder.adoptWithCaveats(i, kj::mv(*element)); + } + } + value.copyLocationTo(builder); + return result; + }), + p::transform(tuple, + [this](Located>>&& value) + -> Orphan { + auto elements = value.value.get(); + + if (elements.size() == 1 && elements[0].isUnnamed()) { + // Single-value tuple is just a value. + return elements[0].disownValue(); + } else { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + builder.adoptTuple(kj::mv(value.value)); + value.copyLocationTo(builder); + return result; + } + }), + p::transformWithLocation(p::sequence(keyword("import"), stringLiteral), + [this](kj::parse::Span::Reader::Iterator> location, + Located&& filename) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + initLocation(location, builder); + filename.copyTo(builder.initImport()); + return result; + }), + p::transformWithLocation(p::sequence(keyword("embed"), stringLiteral), + [this](kj::parse::Span::Reader::Iterator> location, + Located&& filename) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + initLocation(location, builder); + filename.copyTo(builder.initEmbed()); + return result; + }), + p::transformWithLocation(p::sequence(op("."), identifier), + [this](kj::parse::Span::Reader::Iterator> location, + Located&& name) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + initLocation(location, builder); + name.copyTo(builder.initAbsoluteName()); + return result; + }), + p::transform(identifier, + [this](Located&& name) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + name.copyTo(builder.initRelativeName()); + name.copyLocationTo(builder); + return result; + })), + // Suffixes, e.g. ".member" or "(param1, param2)". + p::many(p::oneOf( + p::transformWithLocation(p::sequence(op("."), identifier), + [this](kj::parse::Span::Reader::Iterator> location, + Located&& name) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + initLocation(location, builder); + name.copyTo(builder.initMember().initName()); + return result; + }), + p::transform(tuple, + [this](Located>>&& params) -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + params.copyLocationTo(builder); + builder.initApplication().adoptParams(kj::mv(params.value)); + return result; + })))), + [](Orphan&& base, kj::Array>&& suffixes) + -> Orphan { + // Apply all the suffixes to the base expression. + uint startByte = base.getReader().getStartByte(); + for (auto& suffix: suffixes) { + auto builder = suffix.get(); + if (builder.isApplication()) { + builder.getApplication().adoptFunction(kj::mv(base)); + } else if (builder.isMember()) { + builder.getMember().adoptParent(kj::mv(base)); + } else { + KJ_FAIL_ASSERT("Unknown suffix?", (uint)builder.which()); + } + builder.setStartByte(startByte); + base = kj::mv(suffix); + } + return kj::mv(base); + })); + + parsers.annotation = arena.copy(p::transform( + p::sequence(op("$"), parsers.expression), + [this](Orphan&& expression) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + + auto exp = expression.get(); + if (exp.isApplication()) { + // Oops, this annotation specifies the value, but we parsed it as an application on + // the preceding expression. Pull it back apart. + auto app = exp.getApplication(); + builder.adoptName(app.disownFunction()); + auto params = app.getParams(); + if (params.size() == 1 && params[0].isUnnamed()) { + // Params has a single unnamed element, so reduce it to a simple value rather than + // a tuple. + builder.getValue().adoptExpression(params[0].disownValue()); + } else { + // Params is not a single unnamed element, so it's a tuple. + builder.getValue().initExpression().adoptTuple(app.disownParams()); + } + } else { + // The annotation has no value. + builder.adoptName(kj::mv(expression)); + builder.getValue().setNone(); + } + + return result; + })); + + parsers.uid = arena.copy(p::transform( + p::sequence(op("@"), integerLiteral), + [this](Located&& value) { + if (value.value < (1ull << 63)) { + errorReporter.addError(value.startByte, value.endByte, + "Invalid ID. Please generate a new one with 'capnpc -i'."); + } + return value.asProto(orphanage); + })); + + parsers.ordinal = arena.copy(p::transform( + p::sequence(op("@"), integerLiteral), + [this](Located&& value) { + if (value.value >= 65536) { + errorReporter.addError(value.startByte, value.endByte, + "Ordinals cannot be greater than 65535."); + } + return value.asProto(orphanage); + })); + + // ----------------------------------------------------------------- + + parsers.usingDecl = arena.copy(p::transform( + p::sequence(keyword("using"), p::optional(p::sequence(identifier, op("="))), + parsers.expression), + [this](kj::Maybe>&& name, Orphan&& target) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = decl.get(); + KJ_IF_MAYBE(n, name) { + n->copyTo(builder.initName()); + } else { + auto targetReader = target.getReader(); + if (targetReader.isMember()) { + builder.setName(targetReader.getMember().getName()); + } else { + errorReporter.addErrorOn(targetReader, + "'using' declaration without '=' must specify a named declaration from a " + "different scope."); + } + } + // no id, no annotations for using decl + builder.initUsing().adoptTarget(kj::mv(target)); + return DeclParserResult(kj::mv(decl)); + })); + + parsers.constDecl = arena.copy(p::transform( + p::sequence(keyword("const"), identifier, p::optional(parsers.uid), + op(":"), parsers.expression, + op("="), parsers.expression, + p::many(parsers.annotation)), + [this](Located&& name, kj::Maybe>&& id, + Orphan&& type, Orphan&& value, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = + initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr, + kj::mv(annotations)).initConst(); + builder.adoptType(kj::mv(type)); + builder.adoptValue(kj::mv(value)); + return DeclParserResult(kj::mv(decl)); + })); + + parsers.enumDecl = arena.copy(p::transform( + p::sequence(keyword("enum"), identifier, p::optional(parsers.uid), + p::many(parsers.annotation)), + [this](Located&& name, kj::Maybe>&& id, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr, kj::mv(annotations)).setEnum(); + return DeclParserResult(kj::mv(decl), parsers.enumLevelDecl); + })); + + parsers.enumerantDecl = arena.copy(p::transform( + p::sequence(identifier, parsers.ordinal, p::many(parsers.annotation)), + [this](Located&& name, Orphan&& ordinal, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + initMemberDecl(decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations)) + .setEnumerant(); + return DeclParserResult(kj::mv(decl)); + })); + + parsers.structDecl = arena.copy(p::transform( + p::sequence(keyword("struct"), identifier, p::optional(parsers.uid), + p::optional(parenthesizedList(identifier, errorReporter)), + p::many(parsers.annotation)), + [this](Located&& name, kj::Maybe>&& id, + kj::Maybe>>>>&& genericParameters, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + initDecl(decl.get(), kj::mv(name), kj::mv(id), kj::mv(genericParameters), + kj::mv(annotations)).setStruct(); + return DeclParserResult(kj::mv(decl), parsers.structLevelDecl); + })); + + parsers.fieldDecl = arena.copy(p::transform( + p::sequence(identifier, parsers.ordinal, op(":"), parsers.expression, + p::optional(p::sequence(op("="), parsers.expression)), + p::many(parsers.annotation)), + [this](Located&& name, Orphan&& ordinal, + Orphan&& type, kj::Maybe>&& defaultValue, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = + initMemberDecl(decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations)) + .initField(); + builder.adoptType(kj::mv(type)); + KJ_IF_MAYBE(val, defaultValue) { + builder.getDefaultValue().adoptValue(kj::mv(*val)); + } else { + builder.getDefaultValue().setNone(); + } + return DeclParserResult(kj::mv(decl)); + })); + + // Parse an ordinal followed by an optional colon, or no ordinal but require a colon. + auto& ordinalOrColon = arena.copy(p::oneOf( + p::transform(p::sequence(parsers.ordinal, p::optional(op("!")), p::optional(op(":"))), + [](Orphan&& ordinal, + kj::Maybe> exclamation, + kj::Maybe> colon) + -> kj::Tuple>, bool, bool> { + return kj::tuple(kj::mv(ordinal), exclamation == nullptr, colon == nullptr); + }), + p::transform(op(":"), + []() -> kj::Tuple>, bool, bool> { + return kj::tuple(nullptr, false, false); + }))); + + parsers.unionDecl = arena.copy(p::transform( + // The first branch of this oneOf() matches named unions. The second branch matches unnamed + // unions and generates dummy values for the parse results. + p::oneOf( + p::sequence( + identifier, ordinalOrColon, + keyword("union"), p::many(parsers.annotation)), + p::transformWithLocation(p::sequence(keyword("union"), p::endOfInput), + [](kj::parse::Span::Reader::Iterator> location) { + return kj::tuple( + Located("", location.begin()->getStartByte(), + location.begin()->getEndByte()), + kj::Maybe>(nullptr), + false, false, + kj::Array>(nullptr)); + })), + [this](Located&& name, + kj::Maybe>&& ordinal, + bool missingExclamation, bool missingColon, + kj::Array>&& annotations) + -> DeclParserResult { + if (missingExclamation) { + errorReporter.addErrorOn(KJ_ASSERT_NONNULL(ordinal).getReader(), + "As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to " + "unions. However, removing the number will break binary compatibility. " + "If this is an old protocol and you need to retain compatibility, please " + "add an exclamation point after the number to indicate that it is really " + "needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility " + "doesn't matter, just remove the @n entirely. Sorry for the inconvenience, " + "and thanks for being an early adopter! :)"); + } + if (missingColon) { + errorReporter.addErrorOn(KJ_ASSERT_NONNULL(ordinal).getReader(), + "As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon " + "for named unions, e.g. `foo :union {`."); + } + + auto decl = orphanage.newOrphan(); + auto builder = decl.get(); + name.copyTo(builder.initName()); + KJ_IF_MAYBE(ord, ordinal) { + builder.getId().adoptOrdinal(kj::mv(*ord)); + } else { + builder.getId().setUnspecified(); + } + auto list = builder.initAnnotations(annotations.size()); + for (uint i = 0; i < annotations.size(); i++) { + list.adoptWithCaveats(i, kj::mv(annotations[i])); + } + builder.setUnion(); + return DeclParserResult(kj::mv(decl), parsers.structLevelDecl); + })); + + parsers.groupDecl = arena.copy(p::transform( + p::sequence(identifier, op(":"), keyword("group"), p::many(parsers.annotation)), + [this](Located&& name, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = decl.get(); + name.copyTo(builder.getName()); + builder.getId().setUnspecified(); + auto list = builder.initAnnotations(annotations.size()); + for (uint i = 0; i < annotations.size(); i++) { + list.adoptWithCaveats(i, kj::mv(annotations[i])); + } + builder.setGroup(); + return DeclParserResult(kj::mv(decl), parsers.structLevelDecl); + })); + + parsers.interfaceDecl = arena.copy(p::transform( + p::sequence(keyword("interface"), identifier, p::optional(parsers.uid), + p::optional(parenthesizedList(identifier, errorReporter)), + p::optional(p::sequence( + keyword("extends"), parenthesizedList(parsers.expression, errorReporter))), + p::many(parsers.annotation)), + [this](Located&& name, kj::Maybe>&& id, + kj::Maybe>>>>&& genericParameters, + kj::Maybe>>>>&& superclasses, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = initDecl( + decl.get(), kj::mv(name), kj::mv(id), kj::mv(genericParameters), + kj::mv(annotations)).initInterface(); + KJ_IF_MAYBE(s, superclasses) { + auto superclassesBuilder = builder.initSuperclasses(s->value.size()); + for (uint i: kj::indices(s->value)) { + KJ_IF_MAYBE(superclass, s->value[i]) { + superclassesBuilder.adoptWithCaveats(i, kj::mv(*superclass)); + } + } + } + return DeclParserResult(kj::mv(decl), parsers.interfaceLevelDecl); + })); + + parsers.param = arena.copy(p::transformWithLocation( + p::sequence(identifier, op(":"), parsers.expression, + p::optional(p::sequence(op("="), parsers.expression)), + p::many(parsers.annotation)), + [this](kj::parse::Span::Reader::Iterator> location, + Located&& name, Orphan&& type, + kj::Maybe>&& defaultValue, + kj::Array>&& annotations) + -> Orphan { + auto result = orphanage.newOrphan(); + auto builder = result.get(); + + initLocation(location, builder); + + name.copyTo(builder.initName()); + builder.adoptType(kj::mv(type)); + builder.adoptAnnotations(arrayToList(orphanage, kj::mv(annotations))); + KJ_IF_MAYBE(val, defaultValue) { + builder.getDefaultValue().adoptValue(kj::mv(*val)); + } else { + builder.getDefaultValue().setNone(); + } + + return kj::mv(result); + })); + + auto& paramList = arena.copy(p::oneOf( + p::transform(parenthesizedList(parsers.param, errorReporter), + [this](Located>>>&& params) + -> Orphan { + auto decl = orphanage.newOrphan(); + auto builder = decl.get(); + params.copyLocationTo(builder); + auto listBuilder = builder.initNamedList(params.value.size()); + for (uint i: kj::indices(params.value)) { + KJ_IF_MAYBE(param, params.value[i]) { + listBuilder.adoptWithCaveats(i, kj::mv(*param)); + } + } + return decl; + }), + p::transform(parsers.expression, + [this](Orphan&& name) -> Orphan { + auto decl = orphanage.newOrphan(); + auto builder = decl.get(); + auto nameReader = name.getReader(); + builder.setStartByte(nameReader.getStartByte()); + builder.setEndByte(nameReader.getEndByte()); + builder.adoptType(kj::mv(name)); + return decl; + }))); + + parsers.methodDecl = arena.copy(p::transform( + p::sequence(identifier, parsers.ordinal, + p::optional(bracketedList(identifier, errorReporter)), + paramList, + p::optional(p::sequence(op("->"), paramList)), + p::many(parsers.annotation)), + [this](Located&& name, Orphan&& ordinal, + kj::Maybe>>>>&& genericParams, + Orphan&& params, + kj::Maybe>&& results, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto nodeBuilder = initMemberDecl( + decl.get(), kj::mv(name), kj::mv(ordinal), kj::mv(annotations)); + + initGenericParams(nodeBuilder, kj::mv(genericParams)); + + auto builder = nodeBuilder.initMethod(); + + builder.adoptParams(kj::mv(params)); + + KJ_IF_MAYBE(r, results) { + builder.getResults().adoptExplicit(kj::mv(*r)); + } else { + builder.getResults().setNone(); + } + + return DeclParserResult(kj::mv(decl)); + })); + + auto& annotationTarget = arena.copy(p::oneOf( + identifier, + p::transformWithLocation(op("*"), + [](kj::parse::Span::Reader::Iterator> location) { + // Hacky... + return Located("*", + location.begin()->getStartByte(), + location.begin()->getEndByte()); + }))); + + parsers.annotationDecl = arena.copy(p::transform( + p::sequence(keyword("annotation"), identifier, p::optional(parsers.uid), + parenthesizedList(annotationTarget, errorReporter), + op(":"), parsers.expression, + p::many(parsers.annotation)), + [this](Located&& name, kj::Maybe>&& id, + Located>>>&& targets, + Orphan&& type, + kj::Array>&& annotations) + -> DeclParserResult { + auto decl = orphanage.newOrphan(); + auto builder = + initDecl(decl.get(), kj::mv(name), kj::mv(id), nullptr, + kj::mv(annotations)).initAnnotation(); + builder.adoptType(kj::mv(type)); + DynamicStruct::Builder dynamicBuilder = builder; + for (auto& maybeTarget: targets.value) { + KJ_IF_MAYBE(target, maybeTarget) { + if (target->value == "*") { + // Set all. + if (targets.value.size() > 1) { + errorReporter.addError(target->startByte, target->endByte, + "Wildcard should not be specified together with other targets."); + } + + for (auto field: dynamicBuilder.getSchema().getFields()) { + if (field.getProto().getName().startsWith("targets")) { + dynamicBuilder.set(field, true); + } + } + } else { + if (target->value.size() == 0 || target->value.size() >= 32 || + target->value[0] < 'a' || target->value[0] > 'z') { + errorReporter.addError(target->startByte, target->endByte, + "Not a valid annotation target."); + } else { + char buffer[64]; + strcpy(buffer, "targets"); + strcat(buffer, target->value.cStr()); + buffer[strlen("targets")] += 'A' - 'a'; + KJ_IF_MAYBE(field, dynamicBuilder.getSchema().findFieldByName(buffer)) { + if (dynamicBuilder.get(*field).as()) { + errorReporter.addError(target->startByte, target->endByte, + "Duplicate target specification."); + } + dynamicBuilder.set(*field, true); + } else { + errorReporter.addError(target->startByte, target->endByte, + "Not a valid annotation target."); + } + } + } + } + } + return DeclParserResult(kj::mv(decl)); + })); + + // ----------------------------------------------------------------- + + auto& nakedId = arena.copy(p::transform(parsers.uid, + [this](Orphan&& value) -> DeclParserResult { + auto decl = orphanage.newOrphan(); + decl.get().adoptNakedId(kj::mv(value)); + return DeclParserResult(kj::mv(decl)); + })); + + auto& nakedAnnotation = arena.copy(p::transform(parsers.annotation, + [this](Orphan&& value) -> DeclParserResult { + auto decl = orphanage.newOrphan(); + decl.get().adoptNakedAnnotation(kj::mv(value)); + return DeclParserResult(kj::mv(decl)); + })); + + // ----------------------------------------------------------------- + + parsers.genericDecl = arena.copy(p::oneOf( + parsers.usingDecl, parsers.constDecl, parsers.annotationDecl, + parsers.enumDecl, parsers.structDecl, parsers.interfaceDecl)); + parsers.fileLevelDecl = arena.copy(p::oneOf( + parsers.genericDecl, nakedId, nakedAnnotation)); + parsers.enumLevelDecl = arena.copy(p::oneOf(parsers.enumerantDecl)); + parsers.structLevelDecl = arena.copy(p::oneOf( + parsers.unionDecl, parsers.fieldDecl, parsers.groupDecl, parsers.genericDecl)); + parsers.interfaceLevelDecl = arena.copy(p::oneOf( + parsers.methodDecl, parsers.genericDecl)); +} + +CapnpParser::~CapnpParser() noexcept(false) {} + +kj::Maybe> CapnpParser::parseStatement( + Statement::Reader statement, const DeclParser& parser) { + auto fullParser = p::sequence(parser, p::endOfInput); + + auto tokens = statement.getTokens(); + ParserInput parserInput(tokens.begin(), tokens.end()); + + KJ_IF_MAYBE(output, fullParser(parserInput)) { + auto builder = output->decl.get(); + + if (statement.hasDocComment()) { + builder.setDocComment(statement.getDocComment()); + } + + builder.setStartByte(statement.getStartByte()); + builder.setEndByte(statement.getEndByte()); + + switch (statement.which()) { + case Statement::LINE: + if (output->memberParser != nullptr) { + errorReporter.addError(statement.getStartByte(), statement.getEndByte(), + "This statement should end with a block, not a semicolon."); + } + break; + + case Statement::BLOCK: + KJ_IF_MAYBE(memberParser, output->memberParser) { + auto memberStatements = statement.getBlock(); + kj::Vector> members(memberStatements.size()); + for (auto memberStatement: memberStatements) { + KJ_IF_MAYBE(member, parseStatement(memberStatement, *memberParser)) { + members.add(kj::mv(*member)); + } + } + builder.adoptNestedDecls(arrayToList(orphanage, members.releaseAsArray())); + } else { + errorReporter.addError(statement.getStartByte(), statement.getEndByte(), + "This statement should end with a semicolon, not a block."); + } + break; + } + + return kj::mv(output->decl); + + } else { + // Parse error. Figure out where to report it. + auto best = parserInput.getBest(); + uint32_t bestByte; + + if (best != tokens.end()) { + bestByte = best->getStartByte(); + } else if (tokens.end() != tokens.begin()) { + bestByte = (tokens.end() - 1)->getEndByte(); + } else { + bestByte = statement.getStartByte(); + } + + errorReporter.addError(bestByte, bestByte, "Parse error."); + return nullptr; + } +} + +} // namespace compiler +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/compiler/parser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/compiler/parser.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,151 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_COMPILER_PARSER_H_ +#define CAPNP_COMPILER_PARSER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include +#include +#include "error-reporter.h" + +namespace capnp { +namespace compiler { + +void parseFile(List::Reader statements, ParsedFile::Builder result, + ErrorReporter& errorReporter); +// Parse a list of statements to build a ParsedFile. +// +// If any errors are reported, then the output is not usable. However, it may be passed on through +// later stages of compilation in order to detect additional errors. + +uint64_t generateRandomId(); +// Generate a new random unique ID. This lives here mostly for lack of a better location. + +uint64_t generateChildId(uint64_t parentId, kj::StringPtr childName); +// Generate the ID for a child node given its parent ID and name. + +uint64_t generateGroupId(uint64_t parentId, uint16_t groupIndex); +// Generate the ID for a group within a struct. + +uint64_t generateMethodParamsId(uint64_t parentId, uint16_t methodOrdinal, bool isResults); +// Generate the ID for a struct representing method params / results. +// +// TODO(cleanup): Move generate*Id() somewhere more sensible. + +class CapnpParser { + // Advanced parser interface. This interface exposes the inner parsers so that you can embed + // them into your own parsers. + +public: + CapnpParser(Orphanage orphanage, ErrorReporter& errorReporter); + // `orphanage` is used to allocate Cap'n Proto message objects in the result. `inputStart` is + // a pointer to the beginning of the input, used to compute byte offsets. + + ~CapnpParser() noexcept(false); + + KJ_DISALLOW_COPY(CapnpParser); + + using ParserInput = kj::parse::IteratorInput::Reader::Iterator>; + struct DeclParserResult; + template + using Parser = kj::parse::ParserRef; + using DeclParser = Parser; + + kj::Maybe> parseStatement( + Statement::Reader statement, const DeclParser& parser); + // Parse a statement using the given parser. In addition to parsing the token sequence itself, + // this takes care of parsing the block (if any) and copying over the doc comment (if any). + + struct DeclParserResult { + // DeclParser parses a sequence of tokens representing just the "line" part of the statement -- + // i.e. everything up to the semicolon or opening curly brace. + // + // Use `parseStatement()` to avoid having to deal with this struct. + + Orphan decl; + // The decl parsed so far. The decl's `docComment` and `nestedDecls` are both empty at this + // point. + + kj::Maybe memberParser; + // If null, the statement should not have a block. If non-null, the statement should have a + // block containing statements parseable by this parser. + + DeclParserResult(Orphan&& decl, const DeclParser& memberParser) + : decl(kj::mv(decl)), memberParser(memberParser) {} + explicit DeclParserResult(Orphan&& decl) + : decl(kj::mv(decl)), memberParser(nullptr) {} + }; + + struct Parsers { + DeclParser genericDecl; + // Parser that matches any declaration type except those that have ordinals (since they are + // context-dependent). + + DeclParser fileLevelDecl; + DeclParser enumLevelDecl; + DeclParser structLevelDecl; + DeclParser interfaceLevelDecl; + // Parsers that match genericDecl *and* the ordinal-based declaration types valid in the given + // contexts. Note that these may match declarations that are not actually allowed in the given + // contexts, as long as the grammar is unambiguous. E.g. nested types are not allowed in + // enums, but they'll be accepted by enumLevelDecl. A later stage of compilation should report + // these as errors. + + Parser> expression; + Parser> annotation; + Parser> uid; + Parser> ordinal; + Parser> param; + + DeclParser usingDecl; + DeclParser constDecl; + DeclParser enumDecl; + DeclParser enumerantDecl; + DeclParser structDecl; + DeclParser fieldDecl; + DeclParser unionDecl; + DeclParser groupDecl; + DeclParser interfaceDecl; + DeclParser methodDecl; + DeclParser paramDecl; + DeclParser annotationDecl; + // Parsers for individual declaration types. + }; + + const Parsers& getParsers() { return parsers; } + +private: + Orphanage orphanage; + ErrorReporter& errorReporter; + kj::Arena arena; + Parsers parsers; +}; + +} // namespace compiler +} // namespace capnp + +#endif // CAPNP_COMPILER_PARSER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/dynamic-capability.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/dynamic-capability.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,93 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains the parts of dynamic.h that live in capnp-rpc.so. + +#include "dynamic.h" +#include + +namespace capnp { + +DynamicCapability::Client DynamicCapability::Client::upcast(InterfaceSchema requestedSchema) { + KJ_REQUIRE(schema.extends(requestedSchema), "Can't upcast to non-superclass.") {} + return DynamicCapability::Client(requestedSchema, hook->addRef()); +} + +Request DynamicCapability::Client::newRequest( + InterfaceSchema::Method method, kj::Maybe sizeHint) { + auto methodInterface = method.getContainingInterface(); + + KJ_REQUIRE(schema.extends(methodInterface), "Interface does not implement this method."); + + auto paramType = method.getParamType(); + auto resultType = method.getResultType(); + + auto typeless = hook->newCall( + methodInterface.getProto().getId(), method.getIndex(), sizeHint); + + return Request( + typeless.getAs(paramType), kj::mv(typeless.hook), resultType); +} + +Request DynamicCapability::Client::newRequest( + kj::StringPtr methodName, kj::Maybe sizeHint) { + return newRequest(schema.getMethodByName(methodName), sizeHint); +} + +kj::Promise DynamicCapability::Server::dispatchCall( + uint64_t interfaceId, uint16_t methodId, + CallContext context) { + KJ_IF_MAYBE(interface, schema.findSuperclass(interfaceId)) { + auto methods = interface->getMethods(); + if (methodId < methods.size()) { + auto method = methods[methodId]; + return call(method, CallContext(*context.hook, + method.getParamType(), method.getResultType())); + } else { + return internalUnimplemented( + interface->getProto().getDisplayName().cStr(), interfaceId, methodId); + } + } else { + return internalUnimplemented(schema.getProto().getDisplayName().cStr(), interfaceId); + } +} + +RemotePromise Request::send() { + auto typelessPromise = hook->send(); + auto resultSchemaCopy = resultSchema; + + // Convert the Promise to return the correct response type. + // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the + // Pipeline part of the RemotePromise. + auto typedPromise = kj::implicitCast>&>(typelessPromise) + .then([=](Response&& response) -> Response { + return Response(response.getAs(resultSchemaCopy), + kj::mv(response.hook)); + }); + + // Wrap the typeless pipeline in a typed wrapper. + DynamicStruct::Pipeline typedPipeline(resultSchema, + kj::mv(kj::implicitCast(typelessPromise))); + + return RemotePromise(kj::mv(typedPromise), kj::mv(typedPipeline)); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/dynamic-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/dynamic-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,487 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "dynamic.h" +#include "message.h" +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +template +void checkList(T reader, std::initializer_list> expected) { + auto list = reader.template as(); + ASSERT_EQ(expected.size(), list.size()); + for (uint i = 0; i < expected.size(); i++) { + EXPECT_EQ(expected.begin()[i], list[i].template as()); + } + + auto typed = reader.template as>(); + ASSERT_EQ(expected.size(), typed.size()); + for (uint i = 0; i < expected.size(); i++) { + EXPECT_EQ(expected.begin()[i], typed[i]); + } +} + +TEST(DynamicApi, Build) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + initDynamicTestMessage(root); + checkTestMessage(root.asReader().as()); + + checkDynamicTestMessage(root.asReader()); + checkDynamicTestMessage(root); +} + +TEST(DynamicApi, Read) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root); + + checkDynamicTestMessage(toDynamic(root.asReader())); + checkDynamicTestMessage(toDynamic(root).asReader()); + checkDynamicTestMessage(toDynamic(root)); +} + +TEST(DynamicApi, Defaults) { + AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(nullRoot.words, 1)}; + SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + auto root = reader.getRoot(Schema::from()); + checkDynamicTestMessage(root); +} + +TEST(DynamicApi, DefaultsBuilder) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + checkTestMessage(root.asReader().as()); + checkDynamicTestMessage(root.asReader()); + + // This will initialize the whole message, replacing null pointers with copies of defaults. + checkDynamicTestMessage(root); + + // Check again now that the message is initialized. + checkTestMessage(root.asReader().as()); + checkDynamicTestMessage(root.asReader()); + checkDynamicTestMessage(root); +} + +TEST(DynamicApi, Zero) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + checkDynamicTestMessageAllZero(root.asReader()); + checkTestMessageAllZero(root.asReader().as()); + checkDynamicTestMessageAllZero(root); + checkTestMessageAllZero(root.asReader().as()); +} + +TEST(DynamicApi, ListListsBuild) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + initDynamicTestLists(root); + checkTestMessage(root.asReader().as()); + + checkDynamicTestLists(root.asReader()); + checkDynamicTestLists(root); +} + +TEST(DynamicApi, ListListsRead) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root); + + checkDynamicTestLists(toDynamic(root.asReader())); + checkDynamicTestLists(toDynamic(root).asReader()); + checkDynamicTestLists(toDynamic(root)); +} + +TEST(DynamicApi, AnyPointers) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + initDynamicTestMessage( + root.getAnyPointerField().initAs(Schema::from())); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); + + checkDynamicTestMessage( + root.asReader().getAnyPointerField().getAs(Schema::from())); + checkDynamicTestMessage( + root.getAnyPointerField().getAs(Schema::from())); + + { + { + auto list = root.getAnyPointerField().initAs(Schema::from>(), 4); + list.set(0, 123); + list.set(1, 456); + list.set(2, 789); + list.set(3, 123456789); + } + + { + auto list = root.asReader().getAnyPointerField().getAs>(); + ASSERT_EQ(4u, list.size()); + EXPECT_EQ(123u, list[0]); + EXPECT_EQ(456u, list[1]); + EXPECT_EQ(789u, list[2]); + EXPECT_EQ(123456789u, list[3]); + } + + checkList(root.asReader().getAnyPointerField().getAs( + Schema::from>()), {123u, 456u, 789u, 123456789u}); + checkList(root.getAnyPointerField().getAs( + Schema::from>()), {123u, 456u, 789u, 123456789u}); + } + + // Setting an AnyPointer to various types should work. + toDynamic(root).set("anyPointerField", capnp::Text::Reader("foo")); + EXPECT_EQ("foo", root.getAnyPointerField().getAs()); + + { + auto orphan = builder.getOrphanage().newOrphan(); + initTestMessage(orphan.get()); + toDynamic(root).set("anyPointerField", orphan.getReader()); + checkTestMessage(root.getAnyPointerField().getAs()); + + toDynamic(root).adopt("anyPointerField", kj::mv(orphan)); + checkTestMessage(root.getAnyPointerField().getAs()); + } + + { + auto lorphan = builder.getOrphanage().newOrphan>(3); + lorphan.get().set(0, 12); + lorphan.get().set(1, 34); + lorphan.get().set(2, 56); + toDynamic(root).set("anyPointerField", lorphan.getReader()); + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(3, l.size()); + EXPECT_EQ(12, l[0]); + EXPECT_EQ(34, l[1]); + EXPECT_EQ(56, l[2]); + } + + // Just compile this one. + toDynamic(root).set("anyPointerField", Capability::Client(nullptr)); + root.getAnyPointerField().getAs(); +} + +TEST(DynamicApi, DynamicAnyPointers) { + MallocMessageBuilder builder; + auto root = builder.getRoot(Schema::from()); + + initDynamicTestMessage( + root.get("anyPointerField").as() + .initAs(Schema::from())); + checkTestMessage( + root.asReader().as().getAnyPointerField().getAs()); + + checkDynamicTestMessage( + root.asReader().get("anyPointerField").as() + .getAs(Schema::from())); + checkDynamicTestMessage( + root.asReader().get("anyPointerField").as() + .getAs(Schema::from())); + checkDynamicTestMessage( + root.get("anyPointerField").as().asReader() + .getAs(Schema::from())); + checkDynamicTestMessage( + root.get("anyPointerField").as() + .getAs(Schema::from())); + + { + { + auto list = root.init("anyPointerField").as() + .initAs(Schema::from>(), 4); + list.set(0, 123); + list.set(1, 456); + list.set(2, 789); + list.set(3, 123456789); + } + + { + auto list = root.asReader().as() + .getAnyPointerField().getAs>(); + ASSERT_EQ(4u, list.size()); + EXPECT_EQ(123u, list[0]); + EXPECT_EQ(456u, list[1]); + EXPECT_EQ(789u, list[2]); + EXPECT_EQ(123456789u, list[3]); + } + + checkList( + root.asReader().get("anyPointerField").as() + .getAs(Schema::from>()), + {123u, 456u, 789u, 123456789u}); + checkList( + root.asReader().get("anyPointerField").as() + .getAs(Schema::from>()), + {123u, 456u, 789u, 123456789u}); + checkList( + root.get("anyPointerField").as().asReader() + .getAs(Schema::from>()), + {123u, 456u, 789u, 123456789u}); + checkList( + root.get("anyPointerField").as() + .getAs(Schema::from>()), + {123u, 456u, 789u, 123456789u}); + } +} + +TEST(DynamicApi, DynamicAnyStructs) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.as().as().setInt8Field(123); + EXPECT_EQ(root.get("int8Field").as(), 123); + EXPECT_EQ(root.asReader().as().as().getInt8Field(), 123); +} + +#define EXPECT_MAYBE_EQ(name, exp, expected, actual) \ + KJ_IF_MAYBE(name, exp) { \ + EXPECT_EQ(expected, actual); \ + } else { \ + KJ_FAIL_EXPECT("Maybe was empty."); \ + } + +TEST(DynamicApi, UnionsRead) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getUnion0().setU0f1s32(1234567); + root.getUnion1().setU1f1sp("foo"); + root.getUnion2().setU2f0s1(true); + root.getUnion3().setU3f0s64(1234567890123456789ll); + + { + auto dynamic = toDynamic(root.asReader()); + { + auto u = dynamic.get("union0").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u0f1s32", w->getProto().getName()); + EXPECT_EQ(1234567, u.get("u0f1s32").as()); + } + { + auto u = dynamic.get("union1").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u1f1sp", w->getProto().getName()); + EXPECT_EQ("foo", u.get("u1f1sp").as()); + } + { + auto u = dynamic.get("union2").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u2f0s1", w->getProto().getName()); + EXPECT_TRUE(u.get("u2f0s1").as()); + } + { + auto u = dynamic.get("union3").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u3f0s64", w->getProto().getName()); + EXPECT_EQ(1234567890123456789ll, u.get("u3f0s64").as()); + } + } + + { + // Again as a builder. + auto dynamic = toDynamic(root); + { + auto u = dynamic.get("union0").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u0f1s32", w->getProto().getName()); + EXPECT_EQ(1234567, u.get("u0f1s32").as()); + } + { + auto u = dynamic.get("union1").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u1f1sp", w->getProto().getName()); + EXPECT_EQ("foo", u.get("u1f1sp").as()); + } + { + auto u = dynamic.get("union2").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u2f0s1", w->getProto().getName()); + EXPECT_TRUE(u.get("u2f0s1").as()); + } + { + auto u = dynamic.get("union3").as(); + EXPECT_MAYBE_EQ(w, u.which(), "u3f0s64", w->getProto().getName()); + EXPECT_EQ(1234567890123456789ll, u.get("u3f0s64").as()); + } + } +} + +TEST(DynamicApi, UnionsWrite) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.get("union0").as().set("u0f1s32", 1234567); + root.get("union1").as().set("u1f1sp", "foo"); + root.get("union2").as().set("u2f0s1", true); + root.get("union3").as().set("u3f0s64", 1234567890123456789ll); + + auto reader = root.asReader().as(); + ASSERT_EQ(TestUnion::Union0::U0F1S32, reader.getUnion0().which()); + EXPECT_EQ(1234567, reader.getUnion0().getU0f1s32()); + + ASSERT_EQ(TestUnion::Union1::U1F1SP, reader.getUnion1().which()); + EXPECT_EQ("foo", reader.getUnion1().getU1f1sp()); + + ASSERT_EQ(TestUnion::Union2::U2F0S1, reader.getUnion2().which()); + EXPECT_TRUE(reader.getUnion2().getU2f0s1()); + + ASSERT_EQ(TestUnion::Union3::U3F0S64, reader.getUnion3().which()); + EXPECT_EQ(1234567890123456789ll, reader.getUnion3().getU3f0s64()); + + // Can't access union members by name from the root. + EXPECT_ANY_THROW(root.get("u0f1s32")); + EXPECT_ANY_THROW(root.set("u0f1s32", 1234567)); +} + +TEST(DynamicApi, UnnamedUnion) { + MallocMessageBuilder builder; + StructSchema schema = Schema::from(); + auto root = builder.initRoot(schema); + + EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); + + root.set("bar", 321); + EXPECT_EQ(schema.getFieldByName("bar"), KJ_ASSERT_NONNULL(root.which())); + EXPECT_EQ(321u, root.get("bar").as()); + EXPECT_EQ(321u, root.asReader().get("bar").as()); + EXPECT_ANY_THROW(root.get("foo")); + EXPECT_ANY_THROW(root.asReader().get("foo")); + + root.set("foo", 123); + EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); + EXPECT_EQ(123u, root.get("foo").as()); + EXPECT_EQ(123u, root.asReader().get("foo").as()); + EXPECT_ANY_THROW(root.get("bar")); + EXPECT_ANY_THROW(root.asReader().get("bar")); + + root.set("bar", 321); + EXPECT_EQ(schema.getFieldByName("bar"), KJ_ASSERT_NONNULL(root.which())); + EXPECT_EQ(321u, root.get("bar").as()); + EXPECT_EQ(321u, root.asReader().get("bar").as()); + EXPECT_ANY_THROW(root.get("foo")); + EXPECT_ANY_THROW(root.asReader().get("foo")); + + root.set("foo", 123); + EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); + EXPECT_EQ(123u, root.get("foo").as()); + EXPECT_EQ(123u, root.asReader().get("foo").as()); + EXPECT_ANY_THROW(root.get("bar")); + EXPECT_ANY_THROW(root.asReader().get("bar")); +} + +TEST(DynamicApi, ConversionFailures) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.set("int8Field", 123); + EXPECT_NONFATAL_FAILURE(root.set("int8Field", 1234)); + + root.set("uInt32Field", 1); + EXPECT_NONFATAL_FAILURE(root.set("uInt32Field", -1)); + + root.set("int16Field", 5); + EXPECT_NONFATAL_FAILURE(root.set("int16Field", 0.5)); + + root.set("boolField", true); + EXPECT_NONFATAL_FAILURE(root.set("boolField", 1)); +} + +TEST(DynamicApi, LateUnion) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.get("theUnion").as().set("qux", "hello"); + EXPECT_EQ("hello", root.as().getTheUnion().getQux()); +} + +TEST(DynamicApi, Has) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + // Primitive fields are always present even if set to default. + EXPECT_TRUE(root.has("int32Field")); + root.set("int32Field", 123); + EXPECT_TRUE(root.has("int32Field")); + root.set("int32Field", -12345678); + EXPECT_TRUE(root.has("int32Field")); + + // Pointers are absent until initialized. + EXPECT_FALSE(root.has("structField")); + root.init("structField"); + EXPECT_TRUE(root.has("structField")); +} + +TEST(DynamicApi, HasWhenEmpty) { + AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(nullRoot.words, 1)}; + SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + auto root = reader.getRoot(Schema::from()); + + EXPECT_TRUE(root.has("voidField")); + EXPECT_TRUE(root.has("int32Field")); + EXPECT_FALSE(root.has("structField")); + EXPECT_FALSE(root.has("int32List")); +} + +TEST(DynamicApi, SetEnumFromNative) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.set("enumField", TestEnum::BAZ); + root.set("enumList", {TestEnum::BAR, TestEnum::FOO}); + EXPECT_EQ(TestEnum::BAZ, root.get("enumField").as()); + checkList(root.get("enumList"), {TestEnum::BAR, TestEnum::FOO}); +} + +TEST(DynamicApi, SetDataFromText) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + root.set("dataField", "foo"); + EXPECT_EQ(data("foo"), root.get("dataField").as()); +} + +TEST(DynamicApi, BuilderAssign) { + MallocMessageBuilder builder; + auto root = builder.initRoot(Schema::from()); + + // Declare upfront, assign later. + // Note that the Python implementation requires defaulted constructors. Do not delete them! + DynamicValue::Builder value; + DynamicStruct::Builder structValue; + DynamicList::Builder listValue; + + value = root.get("structField"); + structValue = value.as(); + structValue.set("int32Field", 123); + + value = root.init("int32List", 1); + listValue = value.as(); + listValue.set(0, 123); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/dynamic.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/dynamic.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,2137 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "dynamic.h" +#include + +namespace capnp { + +namespace { + +bool hasDiscriminantValue(const schema::Field::Reader& reader) { + return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT; +} + +template +KJ_ALWAYS_INLINE(T bitCast(U value)); + +template +inline T bitCast(U value) { + static_assert(sizeof(T) == sizeof(U), "Size must match."); + return value; +} +template <> +inline float bitCast(uint32_t value) KJ_UNUSED; +template <> +inline float bitCast(uint32_t value) { + float result; + memcpy(&result, &value, sizeof(value)); + return result; +} +template <> +inline double bitCast(uint64_t value) KJ_UNUSED; +template <> +inline double bitCast(uint64_t value) { + double result; + memcpy(&result, &value, sizeof(value)); + return result; +} +template <> +inline uint32_t bitCast(float value) { + uint32_t result; + memcpy(&result, &value, sizeof(value)); + return result; +} +template <> +inline uint64_t bitCast(double value) { + uint64_t result; + memcpy(&result, &value, sizeof(value)); + return result; +} + +ElementSize elementSizeFor(schema::Type::Which elementType) { + switch (elementType) { + case schema::Type::VOID: return ElementSize::VOID; + case schema::Type::BOOL: return ElementSize::BIT; + case schema::Type::INT8: return ElementSize::BYTE; + case schema::Type::INT16: return ElementSize::TWO_BYTES; + case schema::Type::INT32: return ElementSize::FOUR_BYTES; + case schema::Type::INT64: return ElementSize::EIGHT_BYTES; + case schema::Type::UINT8: return ElementSize::BYTE; + case schema::Type::UINT16: return ElementSize::TWO_BYTES; + case schema::Type::UINT32: return ElementSize::FOUR_BYTES; + case schema::Type::UINT64: return ElementSize::EIGHT_BYTES; + case schema::Type::FLOAT32: return ElementSize::FOUR_BYTES; + case schema::Type::FLOAT64: return ElementSize::EIGHT_BYTES; + + case schema::Type::TEXT: return ElementSize::POINTER; + case schema::Type::DATA: return ElementSize::POINTER; + case schema::Type::LIST: return ElementSize::POINTER; + case schema::Type::ENUM: return ElementSize::TWO_BYTES; + case schema::Type::STRUCT: return ElementSize::INLINE_COMPOSITE; + case schema::Type::INTERFACE: return ElementSize::POINTER; + case schema::Type::ANY_POINTER: KJ_FAIL_ASSERT("List(AnyPointer) not supported."); break; + } + + // Unknown type. Treat it as zero-size. + return ElementSize::VOID; +} + +inline _::StructSize structSizeFromSchema(StructSchema schema) { + auto node = schema.getProto().getStruct(); + return _::StructSize( + bounded(node.getDataWordCount()) * WORDS, + bounded(node.getPointerCount()) * POINTERS); +} + +} // namespace + +// ======================================================================================= + +kj::Maybe DynamicEnum::getEnumerant() const { + auto enumerants = schema.getEnumerants(); + if (value < enumerants.size()) { + return enumerants[value]; + } else { + return nullptr; + } +} + +uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const { + KJ_REQUIRE(requestedTypeId == schema.getProto().getId(), + "Type mismatch in DynamicEnum.as().") { + // use it anyway + break; + } + return value; +} + +// ======================================================================================= + +bool DynamicStruct::Reader::isSetInUnion(StructSchema::Field field) const { + auto proto = field.getProto(); + if (hasDiscriminantValue(proto)) { + uint16_t discrim = reader.getDataField( + assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset())); + return discrim == proto.getDiscriminantValue(); + } else { + return true; + } +} + +void DynamicStruct::Reader::verifySetInUnion(StructSchema::Field field) const { + KJ_REQUIRE(isSetInUnion(field), + "Tried to get() a union member which is not currently initialized.", + field.getProto().getName(), schema.getProto().getDisplayName()); +} + +bool DynamicStruct::Builder::isSetInUnion(StructSchema::Field field) { + auto proto = field.getProto(); + if (hasDiscriminantValue(proto)) { + uint16_t discrim = builder.getDataField( + assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset())); + return discrim == proto.getDiscriminantValue(); + } else { + return true; + } +} + +void DynamicStruct::Builder::verifySetInUnion(StructSchema::Field field) { + KJ_REQUIRE(isSetInUnion(field), + "Tried to get() a union member which is not currently initialized.", + field.getProto().getName(), schema.getProto().getDisplayName()); +} + +void DynamicStruct::Builder::setInUnion(StructSchema::Field field) { + // If a union member, set the discriminant to match. + auto proto = field.getProto(); + if (hasDiscriminantValue(proto)) { + builder.setDataField( + assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()), + proto.getDiscriminantValue()); + } +} + +DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + verifySetInUnion(field); + + auto type = field.getType(); + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + + // Note that the default value might be "anyPointer" even if the type is some poniter type + // *other than* anyPointer. This happens with generics -- the field is actually a generic + // parameter that has been bound, but the default value was of course compiled without any + // binding available. + auto dval = slot.getDefaultValue(); + + switch (type.which()) { + case schema::Type::VOID: + return reader.getDataField(assumeDataOffset(slot.getOffset())); + +#define HANDLE_TYPE(discrim, titleCase, type) \ + case schema::Type::discrim: \ + return reader.getDataField( \ + assumeDataOffset(slot.getOffset()), \ + bitCast<_::Mask>(dval.get##titleCase())); + + HANDLE_TYPE(BOOL, Bool, bool) + HANDLE_TYPE(INT8, Int8, int8_t) + HANDLE_TYPE(INT16, Int16, int16_t) + HANDLE_TYPE(INT32, Int32, int32_t) + HANDLE_TYPE(INT64, Int64, int64_t) + HANDLE_TYPE(UINT8, Uint8, uint8_t) + HANDLE_TYPE(UINT16, Uint16, uint16_t) + HANDLE_TYPE(UINT32, Uint32, uint32_t) + HANDLE_TYPE(UINT64, Uint64, uint64_t) + HANDLE_TYPE(FLOAT32, Float32, float) + HANDLE_TYPE(FLOAT64, Float64, double) + +#undef HANDLE_TYPE + + case schema::Type::ENUM: { + uint16_t typedDval = dval.getEnum(); + return DynamicEnum(type.asEnum(), + reader.getDataField(assumeDataOffset(slot.getOffset()), typedDval)); + } + + case schema::Type::TEXT: { + Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText(); + return reader.getPointerField(assumePointerOffset(slot.getOffset())) + .getBlob(typedDval.begin(), + assumeMax(typedDval.size()) * BYTES); + } + + case schema::Type::DATA: { + Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData(); + return reader.getPointerField(assumePointerOffset(slot.getOffset())) + .getBlob(typedDval.begin(), + assumeBits(typedDval.size()) * BYTES); + } + + case schema::Type::LIST: { + auto elementType = type.asList().getElementType(); + return DynamicList::Reader(type.asList(), + reader.getPointerField(assumePointerOffset(slot.getOffset())) + .getList(elementSizeFor(elementType.which()), dval.isAnyPointer() ? nullptr : + dval.getList().getAs<_::UncheckedMessage>())); + } + + case schema::Type::STRUCT: + return DynamicStruct::Reader(type.asStruct(), + reader.getPointerField(assumePointerOffset(slot.getOffset())) + .getStruct(dval.isAnyPointer() ? nullptr : + dval.getStruct().getAs<_::UncheckedMessage>())); + + case schema::Type::ANY_POINTER: + return AnyPointer::Reader(reader.getPointerField(assumePointerOffset(slot.getOffset()))); + + case schema::Type::INTERFACE: + return DynamicCapability::Client(type.asInterface(), + reader.getPointerField(assumePointerOffset(slot.getOffset())).getCapability()); + } + + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: + return DynamicStruct::Reader(type.asStruct(), reader); + } + + KJ_UNREACHABLE; +} + +DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + verifySetInUnion(field); + + auto proto = field.getProto(); + auto type = field.getType(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + + // Note that the default value might be "anyPointer" even if the type is some poniter type + // *other than* anyPointer. This happens with generics -- the field is actually a generic + // parameter that has been bound, but the default value was of course compiled without any + // binding available. + auto dval = slot.getDefaultValue(); + + switch (type.which()) { + case schema::Type::VOID: + return builder.getDataField(assumeDataOffset(slot.getOffset())); + +#define HANDLE_TYPE(discrim, titleCase, type) \ + case schema::Type::discrim: \ + return builder.getDataField( \ + assumeDataOffset(slot.getOffset()), \ + bitCast<_::Mask>(dval.get##titleCase())); + + HANDLE_TYPE(BOOL, Bool, bool) + HANDLE_TYPE(INT8, Int8, int8_t) + HANDLE_TYPE(INT16, Int16, int16_t) + HANDLE_TYPE(INT32, Int32, int32_t) + HANDLE_TYPE(INT64, Int64, int64_t) + HANDLE_TYPE(UINT8, Uint8, uint8_t) + HANDLE_TYPE(UINT16, Uint16, uint16_t) + HANDLE_TYPE(UINT32, Uint32, uint32_t) + HANDLE_TYPE(UINT64, Uint64, uint64_t) + HANDLE_TYPE(FLOAT32, Float32, float) + HANDLE_TYPE(FLOAT64, Float64, double) + +#undef HANDLE_TYPE + + case schema::Type::ENUM: { + uint16_t typedDval = dval.getEnum(); + return DynamicEnum(type.asEnum(), + builder.getDataField(assumeDataOffset(slot.getOffset()), typedDval)); + } + + case schema::Type::TEXT: { + Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText(); + return builder.getPointerField(assumePointerOffset(slot.getOffset())) + .getBlob(typedDval.begin(), + assumeMax(typedDval.size()) * BYTES); + } + + case schema::Type::DATA: { + Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData(); + return builder.getPointerField(assumePointerOffset(slot.getOffset())) + .getBlob(typedDval.begin(), + assumeBits(typedDval.size()) * BYTES); + } + + case schema::Type::LIST: { + ListSchema listType = type.asList(); + if (listType.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(listType, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .getStructList(structSizeFromSchema(listType.getStructElementType()), + dval.isAnyPointer() ? nullptr : + dval.getList().getAs<_::UncheckedMessage>())); + } else { + return DynamicList::Builder(listType, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .getList(elementSizeFor(listType.whichElementType()), + dval.isAnyPointer() ? nullptr : + dval.getList().getAs<_::UncheckedMessage>())); + } + } + + case schema::Type::STRUCT: { + auto structSchema = type.asStruct(); + return DynamicStruct::Builder(structSchema, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .getStruct(structSizeFromSchema(structSchema), + dval.isAnyPointer() ? nullptr : + dval.getStruct().getAs<_::UncheckedMessage>())); + } + + case schema::Type::ANY_POINTER: + return AnyPointer::Builder( + builder.getPointerField(assumePointerOffset(slot.getOffset()))); + + case schema::Type::INTERFACE: + return DynamicCapability::Client(type.asInterface(), + builder.getPointerField(assumePointerOffset(slot.getOffset())).getCapability()); + } + + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: + return DynamicStruct::Builder(type.asStruct(), builder); + } + + KJ_UNREACHABLE; +} + +DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + + auto proto = field.getProto(); + KJ_REQUIRE(!hasDiscriminantValue(proto), "Can't pipeline on union members."); + + auto type = field.getType(); + + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + + switch (type.which()) { + case schema::Type::STRUCT: + return DynamicStruct::Pipeline(type.asStruct(), + typeless.getPointerField(slot.getOffset())); + + case schema::Type::INTERFACE: + return DynamicCapability::Client(type.asInterface(), + typeless.getPointerField(slot.getOffset()).asCap()); + + case schema::Type::ANY_POINTER: + switch (type.whichAnyPointerKind()) { + case schema::Type::AnyPointer::Unconstrained::STRUCT: + return DynamicStruct::Pipeline(StructSchema(), + typeless.getPointerField(slot.getOffset())); + case schema::Type::AnyPointer::Unconstrained::CAPABILITY: + return DynamicCapability::Client(Capability::Client( + typeless.getPointerField(slot.getOffset()).asCap())); + default: + KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields."); + } + + default: + KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields."); + } + + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: + return DynamicStruct::Pipeline(type.asStruct(), typeless.noop()); + } + + KJ_UNREACHABLE; +} + +bool DynamicStruct::Reader::has(StructSchema::Field field) const { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + + auto proto = field.getProto(); + if (hasDiscriminantValue(proto)) { + uint16_t discrim = reader.getDataField( + assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset())); + if (discrim != proto.getDiscriminantValue()) { + // Field is not active in the union. + return false; + } + } + + switch (proto.which()) { + case schema::Field::SLOT: + // Continue to below. + break; + + case schema::Field::GROUP: + return true; + } + + auto slot = proto.getSlot(); + auto type = field.getType(); + + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + // Primitive types are always present. + return true; + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::ANY_POINTER: + case schema::Type::INTERFACE: + return !reader.getPointerField(assumePointerOffset(slot.getOffset())).isNull(); + } + + // Unknown type. As far as we know, it isn't set. + return false; +} + +kj::Maybe DynamicStruct::Reader::which() const { + auto structProto = schema.getProto().getStruct(); + if (structProto.getDiscriminantCount() == 0) { + return nullptr; + } + + uint16_t discrim = reader.getDataField( + assumeDataOffset(structProto.getDiscriminantOffset())); + return schema.getFieldByDiscriminant(discrim); +} + +kj::Maybe DynamicStruct::Builder::which() { + auto structProto = schema.getProto().getStruct(); + if (structProto.getDiscriminantCount() == 0) { + return nullptr; + } + + uint16_t discrim = builder.getDataField( + assumeDataOffset(structProto.getDiscriminantOffset())); + return schema.getFieldByDiscriminant(discrim); +} + +void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::Reader& value) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + setInUnion(field); + + auto proto = field.getProto(); + auto type = field.getType(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + auto dval = slot.getDefaultValue(); + + switch (type.which()) { + case schema::Type::VOID: + builder.setDataField(assumeDataOffset(slot.getOffset()), value.as()); + return; + +#define HANDLE_TYPE(discrim, titleCase, type) \ + case schema::Type::discrim: \ + builder.setDataField( \ + assumeDataOffset(slot.getOffset()), value.as(), \ + bitCast<_::Mask >(dval.get##titleCase())); \ + return; + + HANDLE_TYPE(BOOL, Bool, bool) + HANDLE_TYPE(INT8, Int8, int8_t) + HANDLE_TYPE(INT16, Int16, int16_t) + HANDLE_TYPE(INT32, Int32, int32_t) + HANDLE_TYPE(INT64, Int64, int64_t) + HANDLE_TYPE(UINT8, Uint8, uint8_t) + HANDLE_TYPE(UINT16, Uint16, uint16_t) + HANDLE_TYPE(UINT32, Uint32, uint32_t) + HANDLE_TYPE(UINT64, Uint64, uint64_t) + HANDLE_TYPE(FLOAT32, Float32, float) + HANDLE_TYPE(FLOAT64, Float64, double) + +#undef HANDLE_TYPE + + case schema::Type::ENUM: { + uint16_t rawValue; + auto enumSchema = type.asEnum(); + if (value.getType() == DynamicValue::TEXT) { + // Convert from text. + rawValue = enumSchema.getEnumerantByName(value.as()).getOrdinal(); + } else if (value.getType() == DynamicValue::INT || + value.getType() == DynamicValue::UINT) { + rawValue = value.as(); + } else { + DynamicEnum enumValue = value.as(); + KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") { + return; + } + rawValue = enumValue.getRaw(); + } + builder.setDataField(assumeDataOffset(slot.getOffset()), rawValue, + dval.getEnum()); + return; + } + + case schema::Type::TEXT: + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .setBlob(value.as()); + return; + + case schema::Type::DATA: + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .setBlob(value.as()); + return; + + case schema::Type::LIST: { + ListSchema listType = type.asList(); + auto listValue = value.as(); + KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") { + return; + } + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .setList(listValue.reader); + return; + } + + case schema::Type::STRUCT: { + auto structType = type.asStruct(); + auto structValue = value.as(); + KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") { + return; + } + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .setStruct(structValue.reader); + return; + } + + case schema::Type::ANY_POINTER: { + auto target = AnyPointer::Builder( + builder.getPointerField(assumePointerOffset(slot.getOffset()))); + + switch (value.getType()) { + case DynamicValue::Type::TEXT: + target.setAs(value.as()); + return; + case DynamicValue::Type::DATA: + target.setAs(value.as()); + return; + case DynamicValue::Type::LIST: + target.setAs(value.as()); + return; + case DynamicValue::Type::STRUCT: + target.setAs(value.as()); + return; + case DynamicValue::Type::CAPABILITY: + target.setAs(value.as()); + return; + case DynamicValue::Type::ANY_POINTER: + target.set(value.as()); + return; + + case DynamicValue::Type::UNKNOWN: + case DynamicValue::Type::VOID: + case DynamicValue::Type::BOOL: + case DynamicValue::Type::INT: + case DynamicValue::Type::UINT: + case DynamicValue::Type::FLOAT: + case DynamicValue::Type::ENUM: + KJ_FAIL_ASSERT("Value type mismatch; expected AnyPointer"); + } + + KJ_UNREACHABLE; + } + + case schema::Type::INTERFACE: { + auto interfaceType = type.asInterface(); + auto capability = value.as(); + KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") { + return; + } + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .setCapability(kj::mv(capability.hook)); + return; + } + } + + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: { + auto src = value.as(); + auto dst = init(field).as(); + + KJ_IF_MAYBE(unionField, src.which()) { + dst.set(*unionField, src.get(*unionField)); + } + + for (auto field: src.schema.getNonUnionFields()) { + if (src.has(field)) { + dst.set(field, src.get(field)); + } + } + } + } + + KJ_UNREACHABLE; +} + +DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + setInUnion(field); + + auto proto = field.getProto(); + auto type = field.getType(); + + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + switch (type.which()) { + case schema::Type::STRUCT: { + auto subSchema = type.asStruct(); + return DynamicStruct::Builder(subSchema, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .initStruct(structSizeFromSchema(subSchema))); + } + case schema::Type::ANY_POINTER: { + auto pointer = builder.getPointerField(assumePointerOffset(slot.getOffset())); + pointer.clear(); + return AnyPointer::Builder(pointer); + } + default: + KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields."); + } + } + + case schema::Field::GROUP: { + clear(field); + return DynamicStruct::Builder(type.asStruct(), builder); + } + } + + KJ_UNREACHABLE; +} + +DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, uint size) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + setInUnion(field); + + auto proto = field.getProto(); + auto type = field.getType(); + + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + switch (type.which()) { + case schema::Type::LIST: { + auto listType = type.asList(); + if (listType.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(listType, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .initStructList(bounded(size) * ELEMENTS, + structSizeFromSchema(listType.getStructElementType()))); + } else { + return DynamicList::Builder(listType, + builder.getPointerField(assumePointerOffset(slot.getOffset())) + .initList(elementSizeFor(listType.whichElementType()), + bounded(size) * ELEMENTS)); + } + } + case schema::Type::TEXT: + return builder.getPointerField(assumePointerOffset(slot.getOffset())) + .initBlob(bounded(size) * BYTES); + case schema::Type::DATA: + return builder.getPointerField(assumePointerOffset(slot.getOffset())) + .initBlob(bounded(size) * BYTES); + default: + KJ_FAIL_REQUIRE( + "init() with size is only valid for list, text, or data fields.", + (uint)type.which()); + break; + } + } + + case schema::Field::GROUP: + KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields."); + } + + KJ_UNREACHABLE; +} + +void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan&& orphan) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + setInUnion(field); + + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + auto type = field.getType(); + + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + set(field, orphan.getReader()); + return; + + case schema::Type::TEXT: + KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch."); + break; + + case schema::Type::DATA: + KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch."); + break; + + case schema::Type::LIST: { + ListSchema listType = type.asList(); + KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType, + "Value type mismatch.") { + return; + } + break; + } + + case schema::Type::STRUCT: { + auto structType = type.asStruct(); + KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType, + "Value type mismatch.") { + return; + } + break; + } + + case schema::Type::ANY_POINTER: + KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT || + orphan.getType() == DynamicValue::LIST || + orphan.getType() == DynamicValue::TEXT || + orphan.getType() == DynamicValue::DATA || + orphan.getType() == DynamicValue::CAPABILITY || + orphan.getType() == DynamicValue::ANY_POINTER, + "Value type mismatch.") { + return; + } + break; + + case schema::Type::INTERFACE: { + auto interfaceType = type.asInterface(); + KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY && + orphan.interfaceSchema.extends(interfaceType), + "Value type mismatch.") { + return; + } + break; + } + } + + builder.getPointerField(assumePointerOffset(slot.getOffset())).adopt(kj::mv(orphan.builder)); + return; + } + + case schema::Field::GROUP: + // Have to transfer fields. + auto src = orphan.get().as(); + auto dst = init(field).as(); + + KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == dst.getSchema(), + "Value type mismatch."); + + KJ_IF_MAYBE(unionField, src.which()) { + dst.adopt(*unionField, src.disown(*unionField)); + } + + for (auto field: src.schema.getNonUnionFields()) { + if (src.has(field)) { + dst.adopt(field, src.disown(field)); + } + } + + return; + } + + KJ_UNREACHABLE; +} + +Orphan DynamicStruct::Builder::disown(StructSchema::Field field) { + // We end up calling get(field) below, so we don't need to validate `field` here. + + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + + switch (field.getType().which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: { + auto result = Orphan(get(field), _::OrphanBuilder()); + clear(field); + return kj::mv(result); + } + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::ANY_POINTER: + case schema::Type::INTERFACE: { + auto value = get(field); + return Orphan( + value, builder.getPointerField(assumePointerOffset(slot.getOffset())).disown()); + } + } + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: { + // We have to allocate new space for the group, unfortunately. + auto src = get(field).as(); + + Orphan result = + Orphanage::getForMessageContaining(*this).newOrphan(src.getSchema()); + auto dst = result.get(); + + KJ_IF_MAYBE(unionField, src.which()) { + dst.adopt(*unionField, src.disown(*unionField)); + } + + // We need to explicitly reset the union to its default field. + KJ_IF_MAYBE(unionField, src.schema.getFieldByDiscriminant(0)) { + src.clear(*unionField); + } + + for (auto field: src.schema.getNonUnionFields()) { + if (src.has(field)) { + dst.adopt(field, src.disown(field)); + } + } + + return kj::mv(result); + } + } + + KJ_UNREACHABLE; +} + +void DynamicStruct::Builder::clear(StructSchema::Field field) { + KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct."); + setInUnion(field); + + auto proto = field.getProto(); + auto type = field.getType(); + switch (proto.which()) { + case schema::Field::SLOT: { + auto slot = proto.getSlot(); + + switch (type.which()) { + case schema::Type::VOID: + builder.setDataField(assumeDataOffset(slot.getOffset()), VOID); + return; + +#define HANDLE_TYPE(discrim, type) \ + case schema::Type::discrim: \ + builder.setDataField(assumeDataOffset(slot.getOffset()), 0); \ + return; + + HANDLE_TYPE(BOOL, bool) + HANDLE_TYPE(INT8, uint8_t) + HANDLE_TYPE(INT16, uint16_t) + HANDLE_TYPE(INT32, uint32_t) + HANDLE_TYPE(INT64, uint64_t) + HANDLE_TYPE(UINT8, uint8_t) + HANDLE_TYPE(UINT16, uint16_t) + HANDLE_TYPE(UINT32, uint32_t) + HANDLE_TYPE(UINT64, uint64_t) + HANDLE_TYPE(FLOAT32, uint32_t) + HANDLE_TYPE(FLOAT64, uint64_t) + HANDLE_TYPE(ENUM, uint16_t) + +#undef HANDLE_TYPE + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::ANY_POINTER: + case schema::Type::INTERFACE: + builder.getPointerField(assumePointerOffset(slot.getOffset())).clear(); + return; + } + + KJ_UNREACHABLE; + } + + case schema::Field::GROUP: { + DynamicStruct::Builder group(type.asStruct(), builder); + + // We clear the union field with discriminant 0 rather than the one that is set because + // we want the union to end up with its default field active. + KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) { + group.clear(*unionField); + } + + for (auto subField: group.schema.getNonUnionFields()) { + group.clear(subField); + } + return; + } + } + + KJ_UNREACHABLE; +} + +DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const { + return get(schema.getFieldByName(name)); +} +DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) { + return get(schema.getFieldByName(name)); +} +DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) { + return get(schema.getFieldByName(name)); +} +bool DynamicStruct::Reader::has(kj::StringPtr name) const { + return has(schema.getFieldByName(name)); +} +bool DynamicStruct::Builder::has(kj::StringPtr name) { + return has(schema.getFieldByName(name)); +} +void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) { + set(schema.getFieldByName(name), value); +} +void DynamicStruct::Builder::set(kj::StringPtr name, + std::initializer_list value) { + auto list = init(name, value.size()).as(); + uint i = 0; + for (auto element: value) { + list.set(i++, element); + } +} +DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) { + return init(schema.getFieldByName(name)); +} +DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) { + return init(schema.getFieldByName(name), size); +} +void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan&& orphan) { + adopt(schema.getFieldByName(name), kj::mv(orphan)); +} +Orphan DynamicStruct::Builder::disown(kj::StringPtr name) { + return disown(schema.getFieldByName(name)); +} +void DynamicStruct::Builder::clear(kj::StringPtr name) { + clear(schema.getFieldByName(name)); +} + +// ======================================================================================= + +DynamicValue::Reader DynamicList::Reader::operator[](uint index) const { + KJ_REQUIRE(index < size(), "List index out-of-bounds."); + + switch (schema.whichElementType()) { +#define HANDLE_TYPE(name, discrim, typeName) \ + case schema::Type::discrim: \ + return reader.getDataElement(bounded(index) * ELEMENTS); + + HANDLE_TYPE(void, VOID, Void) + HANDLE_TYPE(bool, BOOL, bool) + HANDLE_TYPE(int8, INT8, int8_t) + HANDLE_TYPE(int16, INT16, int16_t) + HANDLE_TYPE(int32, INT32, int32_t) + HANDLE_TYPE(int64, INT64, int64_t) + HANDLE_TYPE(uint8, UINT8, uint8_t) + HANDLE_TYPE(uint16, UINT16, uint16_t) + HANDLE_TYPE(uint32, UINT32, uint32_t) + HANDLE_TYPE(uint64, UINT64, uint64_t) + HANDLE_TYPE(float32, FLOAT32, float) + HANDLE_TYPE(float64, FLOAT64, double) +#undef HANDLE_TYPE + + case schema::Type::TEXT: + return reader.getPointerElement(bounded(index) * ELEMENTS) + .getBlob(nullptr, ZERO * BYTES); + case schema::Type::DATA: + return reader.getPointerElement(bounded(index) * ELEMENTS) + .getBlob(nullptr, ZERO * BYTES); + + case schema::Type::LIST: { + auto elementType = schema.getListElementType(); + return DynamicList::Reader(elementType, + reader.getPointerElement(bounded(index) * ELEMENTS) + .getList(elementSizeFor(elementType.whichElementType()), nullptr)); + } + + case schema::Type::STRUCT: + return DynamicStruct::Reader(schema.getStructElementType(), + reader.getStructElement(bounded(index) * ELEMENTS)); + + case schema::Type::ENUM: + return DynamicEnum(schema.getEnumElementType(), + reader.getDataElement(bounded(index) * ELEMENTS)); + + case schema::Type::ANY_POINTER: + return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS)); + + case schema::Type::INTERFACE: + return DynamicCapability::Client(schema.getInterfaceElementType(), + reader.getPointerElement(bounded(index) * ELEMENTS) + .getCapability()); + } + + return nullptr; +} + +DynamicValue::Builder DynamicList::Builder::operator[](uint index) { + KJ_REQUIRE(index < size(), "List index out-of-bounds."); + + switch (schema.whichElementType()) { +#define HANDLE_TYPE(name, discrim, typeName) \ + case schema::Type::discrim: \ + return builder.getDataElement(bounded(index) * ELEMENTS); + + HANDLE_TYPE(void, VOID, Void) + HANDLE_TYPE(bool, BOOL, bool) + HANDLE_TYPE(int8, INT8, int8_t) + HANDLE_TYPE(int16, INT16, int16_t) + HANDLE_TYPE(int32, INT32, int32_t) + HANDLE_TYPE(int64, INT64, int64_t) + HANDLE_TYPE(uint8, UINT8, uint8_t) + HANDLE_TYPE(uint16, UINT16, uint16_t) + HANDLE_TYPE(uint32, UINT32, uint32_t) + HANDLE_TYPE(uint64, UINT64, uint64_t) + HANDLE_TYPE(float32, FLOAT32, float) + HANDLE_TYPE(float64, FLOAT64, double) +#undef HANDLE_TYPE + + case schema::Type::TEXT: + return builder.getPointerElement(bounded(index) * ELEMENTS) + .getBlob(nullptr, ZERO * BYTES); + case schema::Type::DATA: + return builder.getPointerElement(bounded(index) * ELEMENTS) + .getBlob(nullptr, ZERO * BYTES); + + case schema::Type::LIST: { + ListSchema elementType = schema.getListElementType(); + if (elementType.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(elementType, + builder.getPointerElement(bounded(index) * ELEMENTS) + .getStructList(structSizeFromSchema(elementType.getStructElementType()), + nullptr)); + } else { + return DynamicList::Builder(elementType, + builder.getPointerElement(bounded(index) * ELEMENTS) + .getList(elementSizeFor(elementType.whichElementType()), nullptr)); + } + } + + case schema::Type::STRUCT: + return DynamicStruct::Builder(schema.getStructElementType(), + builder.getStructElement(bounded(index) * ELEMENTS)); + + case schema::Type::ENUM: + return DynamicEnum(schema.getEnumElementType(), + builder.getDataElement(bounded(index) * ELEMENTS)); + + case schema::Type::ANY_POINTER: + KJ_FAIL_ASSERT("List(AnyPointer) not supported."); + return nullptr; + + case schema::Type::INTERFACE: + return DynamicCapability::Client(schema.getInterfaceElementType(), + builder.getPointerElement(bounded(index) * ELEMENTS) + .getCapability()); + } + + return nullptr; +} + +void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) { + KJ_REQUIRE(index < size(), "List index out-of-bounds.") { + return; + } + + switch (schema.whichElementType()) { +#define HANDLE_TYPE(name, discrim, typeName) \ + case schema::Type::discrim: \ + builder.setDataElement(bounded(index) * ELEMENTS, value.as()); \ + return; + + HANDLE_TYPE(void, VOID, Void) + HANDLE_TYPE(bool, BOOL, bool) + HANDLE_TYPE(int8, INT8, int8_t) + HANDLE_TYPE(int16, INT16, int16_t) + HANDLE_TYPE(int32, INT32, int32_t) + HANDLE_TYPE(int64, INT64, int64_t) + HANDLE_TYPE(uint8, UINT8, uint8_t) + HANDLE_TYPE(uint16, UINT16, uint16_t) + HANDLE_TYPE(uint32, UINT32, uint32_t) + HANDLE_TYPE(uint64, UINT64, uint64_t) + HANDLE_TYPE(float32, FLOAT32, float) + HANDLE_TYPE(float64, FLOAT64, double) +#undef HANDLE_TYPE + + case schema::Type::TEXT: + builder.getPointerElement(bounded(index) * ELEMENTS).setBlob(value.as()); + return; + case schema::Type::DATA: + builder.getPointerElement(bounded(index) * ELEMENTS).setBlob(value.as()); + return; + + case schema::Type::LIST: { + auto listValue = value.as(); + KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") { + return; + } + builder.getPointerElement(bounded(index) * ELEMENTS).setList(listValue.reader); + return; + } + + case schema::Type::STRUCT: { + auto structValue = value.as(); + KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") { + return; + } + builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(structValue.reader); + return; + } + + case schema::Type::ENUM: { + uint16_t rawValue; + if (value.getType() == DynamicValue::TEXT) { + // Convert from text. + rawValue = schema.getEnumElementType().getEnumerantByName(value.as()).getOrdinal(); + } else { + DynamicEnum enumValue = value.as(); + KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(), + "Type mismatch when using DynamicList::Builder::set().") { + return; + } + rawValue = enumValue.getRaw(); + } + builder.setDataElement(bounded(index) * ELEMENTS, rawValue); + return; + } + + case schema::Type::ANY_POINTER: + KJ_FAIL_ASSERT("List(AnyPointer) not supported.") { + return; + } + + case schema::Type::INTERFACE: { + auto capValue = value.as(); + KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()), + "Value type mismatch.") { + return; + } + builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(capValue.hook)); + return; + } + } + + KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) { + return; + } +} + +DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) { + KJ_REQUIRE(index < this->size(), "List index out-of-bounds."); + + switch (schema.whichElementType()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + KJ_FAIL_REQUIRE("Expected a list or blob."); + return nullptr; + + case schema::Type::TEXT: + return builder.getPointerElement(bounded(index) * ELEMENTS) + .initBlob(bounded(size) * BYTES); + + case schema::Type::DATA: + return builder.getPointerElement(bounded(index) * ELEMENTS) + .initBlob(bounded(size) * BYTES); + + case schema::Type::LIST: { + auto elementType = schema.getListElementType(); + + if (elementType.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(elementType, + builder.getPointerElement(bounded(index) * ELEMENTS) + .initStructList(bounded(size) * ELEMENTS, + structSizeFromSchema(elementType.getStructElementType()))); + } else { + return DynamicList::Builder(elementType, + builder.getPointerElement(bounded(index) * ELEMENTS) + .initList(elementSizeFor(elementType.whichElementType()), + bounded(size) * ELEMENTS)); + } + } + + case schema::Type::ANY_POINTER: { + KJ_FAIL_ASSERT("List(AnyPointer) not supported."); + return nullptr; + } + } + + return nullptr; +} + +void DynamicList::Builder::adopt(uint index, Orphan&& orphan) { + switch (schema.whichElementType()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + set(index, orphan.getReader()); + return; + + case schema::Type::TEXT: + KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch."); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder)); + return; + + case schema::Type::DATA: + KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch."); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder)); + return; + + case schema::Type::LIST: { + ListSchema elementType = schema.getListElementType(); + KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType, + "Value type mismatch."); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder)); + return; + } + + case schema::Type::STRUCT: { + auto elementType = schema.getStructElementType(); + KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == elementType, + "Value type mismatch."); + builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom( + orphan.builder.asStruct(structSizeFromSchema(elementType))); + return; + } + + case schema::Type::ANY_POINTER: + KJ_FAIL_ASSERT("List(AnyPointer) not supported."); + + case schema::Type::INTERFACE: { + auto elementType = schema.getInterfaceElementType(); + KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY && + orphan.interfaceSchema.extends(elementType), + "Value type mismatch."); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder)); + return; + } + } + + KJ_UNREACHABLE; +} + +Orphan DynamicList::Builder::disown(uint index) { + switch (schema.whichElementType()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: { + auto result = Orphan(operator[](index), _::OrphanBuilder()); + switch (elementSizeFor(schema.whichElementType())) { + case ElementSize::VOID: break; + case ElementSize::BIT: builder.setDataElement(bounded(index) * ELEMENTS, false); break; + case ElementSize::BYTE: builder.setDataElement(bounded(index) * ELEMENTS, 0); break; + case ElementSize::TWO_BYTES: builder.setDataElement(bounded(index) * ELEMENTS, 0); break; + case ElementSize::FOUR_BYTES: builder.setDataElement(bounded(index) * ELEMENTS, 0); break; + case ElementSize::EIGHT_BYTES: builder.setDataElement(bounded(index) * ELEMENTS, 0);break; + + case ElementSize::POINTER: + case ElementSize::INLINE_COMPOSITE: + KJ_UNREACHABLE; + } + return kj::mv(result); + } + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::ANY_POINTER: + case schema::Type::INTERFACE: { + auto value = operator[](index); + return Orphan(value, builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + case schema::Type::STRUCT: { + // We have to make a copy. + Orphan result = + Orphanage::getForMessageContaining(*this).newOrphan(schema.getStructElementType()); + auto element = builder.getStructElement(bounded(index) * ELEMENTS); + result.get().builder.transferContentFrom(element); + element.clearAll(); + return kj::mv(result); + } + } + KJ_UNREACHABLE; +} + +void DynamicList::Builder::copyFrom(std::initializer_list value) { + KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size."); + uint i = 0; + for (auto element: value) { + set(i++, element); + } +} + +DynamicList::Reader DynamicList::Builder::asReader() const { + return DynamicList::Reader(schema, builder.asReader()); +} + +// ======================================================================================= + +DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) { + auto type = constant.getType(); + auto value = constant.getProto().getConst().getValue(); + switch (type.which()) { + case schema::Type::VOID: *this = capnp::VOID; break; + case schema::Type::BOOL: *this = value.getBool(); break; + case schema::Type::INT8: *this = value.getInt8(); break; + case schema::Type::INT16: *this = value.getInt16(); break; + case schema::Type::INT32: *this = value.getInt32(); break; + case schema::Type::INT64: *this = value.getInt64(); break; + case schema::Type::UINT8: *this = value.getUint8(); break; + case schema::Type::UINT16: *this = value.getUint16(); break; + case schema::Type::UINT32: *this = value.getUint32(); break; + case schema::Type::UINT64: *this = value.getUint64(); break; + case schema::Type::FLOAT32: *this = value.getFloat32(); break; + case schema::Type::FLOAT64: *this = value.getFloat64(); break; + case schema::Type::TEXT: *this = value.getText(); break; + case schema::Type::DATA: *this = value.getData(); break; + + case schema::Type::ENUM: + *this = DynamicEnum(type.asEnum(), value.getEnum()); + break; + + case schema::Type::STRUCT: + *this = value.getStruct().getAs(type.asStruct()); + break; + + case schema::Type::LIST: + *this = value.getList().getAs(type.asList()); + break; + + case schema::Type::ANY_POINTER: + *this = value.getAnyPointer(); + break; + + case schema::Type::INTERFACE: + KJ_FAIL_ASSERT("Constants can't have interface type."); + } +} + +DynamicValue::Reader::Reader(const Reader& other) { + switch (other.type) { + case UNKNOWN: + case VOID: + case BOOL: + case INT: + case UINT: + case FLOAT: + case TEXT: + case DATA: + case LIST: + case ENUM: + case STRUCT: + case ANY_POINTER: + KJ_ASSERT_CAN_MEMCPY(Text::Reader); + KJ_ASSERT_CAN_MEMCPY(Data::Reader); + KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader); + KJ_ASSERT_CAN_MEMCPY(DynamicEnum); + KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader); + KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader); + break; + + case CAPABILITY: + type = CAPABILITY; + kj::ctor(capabilityValue, other.capabilityValue); + return; + } + + memcpy(this, &other, sizeof(*this)); +} +DynamicValue::Reader::Reader(Reader&& other) noexcept { + switch (other.type) { + case UNKNOWN: + case VOID: + case BOOL: + case INT: + case UINT: + case FLOAT: + case TEXT: + case DATA: + case LIST: + case ENUM: + case STRUCT: + case ANY_POINTER: + KJ_ASSERT_CAN_MEMCPY(Text::Reader); + KJ_ASSERT_CAN_MEMCPY(Data::Reader); + KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader); + KJ_ASSERT_CAN_MEMCPY(DynamicEnum); + KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader); + KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader); + break; + + case CAPABILITY: + type = CAPABILITY; + kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); + return; + } + + memcpy(this, &other, sizeof(*this)); +} +DynamicValue::Reader::~Reader() noexcept(false) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } +} + +DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } + kj::ctor(*this, other); + return *this; +} +DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } + kj::ctor(*this, kj::mv(other)); + return *this; +} + +DynamicValue::Builder::Builder(Builder& other) { + switch (other.type) { + case UNKNOWN: + case VOID: + case BOOL: + case INT: + case UINT: + case FLOAT: + case TEXT: + case DATA: + case LIST: + case ENUM: + case STRUCT: + case ANY_POINTER: + // Unfortunately canMemcpy() doesn't work on these types due to the use of + // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types + // become non-trivial. + static_assert(__has_trivial_destructor(Text::Builder) && + __has_trivial_destructor(Data::Builder) && + __has_trivial_destructor(DynamicList::Builder) && + __has_trivial_destructor(DynamicEnum) && + __has_trivial_destructor(DynamicStruct::Builder) && + __has_trivial_destructor(AnyPointer::Builder), + "Assumptions here don't hold."); + break; + + case CAPABILITY: + type = CAPABILITY; + kj::ctor(capabilityValue, other.capabilityValue); + return; + } + + memcpy(this, &other, sizeof(*this)); +} +DynamicValue::Builder::Builder(Builder&& other) noexcept { + switch (other.type) { + case UNKNOWN: + case VOID: + case BOOL: + case INT: + case UINT: + case FLOAT: + case TEXT: + case DATA: + case LIST: + case ENUM: + case STRUCT: + case ANY_POINTER: + // Unfortunately __has_trivial_copy doesn't work on these types due to the use of + // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types + // become non-trivial. + static_assert(__has_trivial_destructor(Text::Builder) && + __has_trivial_destructor(Data::Builder) && + __has_trivial_destructor(DynamicList::Builder) && + __has_trivial_destructor(DynamicEnum) && + __has_trivial_destructor(DynamicStruct::Builder) && + __has_trivial_destructor(AnyPointer::Builder), + "Assumptions here don't hold."); + break; + + case CAPABILITY: + type = CAPABILITY; + kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); + return; + } + + memcpy(this, &other, sizeof(*this)); +} +DynamicValue::Builder::~Builder() noexcept(false) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } +} + +DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } + kj::ctor(*this, other); + return *this; +} +DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) { + if (type == CAPABILITY) { + kj::dtor(capabilityValue); + } + kj::ctor(*this, kj::mv(other)); + return *this; +} + +DynamicValue::Reader DynamicValue::Builder::asReader() const { + switch (type) { + case UNKNOWN: return Reader(); + case VOID: return Reader(voidValue); + case BOOL: return Reader(boolValue); + case INT: return Reader(intValue); + case UINT: return Reader(uintValue); + case FLOAT: return Reader(floatValue); + case TEXT: return Reader(textValue.asReader()); + case DATA: return Reader(dataValue.asReader()); + case LIST: return Reader(listValue.asReader()); + case ENUM: return Reader(enumValue); + case STRUCT: return Reader(structValue.asReader()); + case CAPABILITY: return Reader(capabilityValue); + case ANY_POINTER: return Reader(anyPointerValue.asReader()); + } + KJ_FAIL_ASSERT("Missing switch case."); + return Reader(); +} + +DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) { + switch (type) { + case UNKNOWN: break; + case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break; + case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break; + default: + KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type); + type = UNKNOWN; + break; + } +} +DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) { + kj::dtor(*this); + kj::ctor(*this, kj::mv(other)); + return *this; +} +DynamicValue::Pipeline::~Pipeline() noexcept(false) { + switch (type) { + case UNKNOWN: break; + case STRUCT: kj::dtor(structValue); break; + case CAPABILITY: kj::dtor(capabilityValue); break; + default: + KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; } + break; + } +} + +namespace { + +template +T signedToUnsigned(long long value) { + KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) { + // Use it anyway. + break; + } + return value; +} + +template <> +uint64_t signedToUnsigned(long long value) { + KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) { + // Use it anyway. + break; + } + return value; +} + +template +T unsignedToSigned(unsigned long long value) { + KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value, + "Value out-of-range for requested type.", value) { + // Use it anyway. + break; + } + return value; +} + +template <> +int64_t unsignedToSigned(unsigned long long value) { + KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) { + // Use it anyway. + break; + } + return value; +} + +template +T checkRoundTrip(U value) { + KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) { + // Use it anyway. + break; + } + return value; +} + +} // namespace + +#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \ +typeName DynamicValue::Reader::AsImpl::apply(const Reader& reader) { \ + switch (reader.type) { \ + case INT: \ + return ifInt(reader.intValue); \ + case UINT: \ + return ifUint(reader.uintValue); \ + case FLOAT: \ + return ifFloat(reader.floatValue); \ + default: \ + KJ_FAIL_REQUIRE("Value type mismatch.") { \ + return 0; \ + } \ + } \ +} \ +typeName DynamicValue::Builder::AsImpl::apply(Builder& builder) { \ + switch (builder.type) { \ + case INT: \ + return ifInt(builder.intValue); \ + case UINT: \ + return ifUint(builder.uintValue); \ + case FLOAT: \ + return ifFloat(builder.floatValue); \ + default: \ + KJ_FAIL_REQUIRE("Value type mismatch.") { \ + return 0; \ + } \ + } \ +} + +HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip) +HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip) +HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip) +HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip) +HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip) +HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip) +HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip) +HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTrip) +HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast) +HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast) + +#undef HANDLE_NUMERIC_TYPE + +#define HANDLE_TYPE(name, discrim, typeName) \ +ReaderFor DynamicValue::Reader::AsImpl::apply(const Reader& reader) { \ + KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \ + return ReaderFor(); \ + } \ + return reader.name##Value; \ +} \ +BuilderFor DynamicValue::Builder::AsImpl::apply(Builder& builder) { \ + KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \ + return builder.name##Value; \ +} + +//HANDLE_TYPE(void, VOID, Void) +HANDLE_TYPE(bool, BOOL, bool) + +HANDLE_TYPE(text, TEXT, Text) +HANDLE_TYPE(list, LIST, DynamicList) +HANDLE_TYPE(struct, STRUCT, DynamicStruct) +HANDLE_TYPE(enum, ENUM, DynamicEnum) +HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer) + +#undef HANDLE_TYPE + +PipelineFor DynamicValue::Pipeline::AsImpl::apply( + Pipeline& pipeline) { + KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch."); + return kj::mv(pipeline.structValue); +} + +ReaderFor DynamicValue::Reader::AsImpl::apply( + const Reader& reader) { + KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") { + return DynamicCapability::Client(); + } + return reader.capabilityValue; +} +BuilderFor DynamicValue::Builder::AsImpl::apply( + Builder& builder) { + KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") { + return DynamicCapability::Client(); + } + return builder.capabilityValue; +} +PipelineFor DynamicValue::Pipeline::AsImpl::apply( + Pipeline& pipeline) { + KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") { + return DynamicCapability::Client(); + } + return kj::mv(pipeline.capabilityValue); +} + +Data::Reader DynamicValue::Reader::AsImpl::apply(const Reader& reader) { + if (reader.type == TEXT) { + // Coerce text to data. + return reader.textValue.asBytes(); + } + KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") { + return Data::Reader(); + } + return reader.dataValue; +} +Data::Builder DynamicValue::Builder::AsImpl::apply(Builder& builder) { + if (builder.type == TEXT) { + // Coerce text to data. + return builder.textValue.asBytes(); + } + KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") { + return BuilderFor(); + } + return builder.dataValue; +} + +// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7. +Void DynamicValue::Reader::AsImpl::apply(const Reader& reader) { + KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") { + return Void(); + } + return reader.voidValue; +} +Void DynamicValue::Builder::AsImpl::apply(Builder& builder) { + KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") { + return Void(); + } + return builder.voidValue; +} + +// ======================================================================================= + +namespace _ { // private + +DynamicStruct::Reader PointerHelpers::getDynamic( + PointerReader reader, StructSchema schema) { + KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(), + "Cannot form pointer to group type."); + return DynamicStruct::Reader(schema, reader.getStruct(nullptr)); +} +DynamicStruct::Builder PointerHelpers::getDynamic( + PointerBuilder builder, StructSchema schema) { + KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(), + "Cannot form pointer to group type."); + return DynamicStruct::Builder(schema, builder.getStruct( + structSizeFromSchema(schema), nullptr)); +} +void PointerHelpers::set( + PointerBuilder builder, const DynamicStruct::Reader& value) { + KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(), + "Cannot form pointer to group type."); + builder.setStruct(value.reader); +} +DynamicStruct::Builder PointerHelpers::init( + PointerBuilder builder, StructSchema schema) { + KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(), + "Cannot form pointer to group type."); + return DynamicStruct::Builder(schema, + builder.initStruct(structSizeFromSchema(schema))); +} + +DynamicList::Reader PointerHelpers::getDynamic( + PointerReader reader, ListSchema schema) { + return DynamicList::Reader(schema, + reader.getList(elementSizeFor(schema.whichElementType()), nullptr)); +} +DynamicList::Builder PointerHelpers::getDynamic( + PointerBuilder builder, ListSchema schema) { + if (schema.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(schema, + builder.getStructList( + structSizeFromSchema(schema.getStructElementType()), + nullptr)); + } else { + return DynamicList::Builder(schema, + builder.getList(elementSizeFor(schema.whichElementType()), nullptr)); + } +} +void PointerHelpers::set( + PointerBuilder builder, const DynamicList::Reader& value) { + builder.setList(value.reader); +} +DynamicList::Builder PointerHelpers::init( + PointerBuilder builder, ListSchema schema, uint size) { + if (schema.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(schema, + builder.initStructList(bounded(size) * ELEMENTS, + structSizeFromSchema(schema.getStructElementType()))); + } else { + return DynamicList::Builder(schema, + builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS)); + } +} + +DynamicCapability::Client PointerHelpers::getDynamic( + PointerReader reader, InterfaceSchema schema) { + return DynamicCapability::Client(schema, reader.getCapability()); +} +DynamicCapability::Client PointerHelpers::getDynamic( + PointerBuilder builder, InterfaceSchema schema) { + return DynamicCapability::Client(schema, builder.getCapability()); +} +void PointerHelpers::set( + PointerBuilder builder, DynamicCapability::Client& value) { + builder.setCapability(value.hook->addRef()); +} +void PointerHelpers::set( + PointerBuilder builder, DynamicCapability::Client&& value) { + builder.setCapability(kj::mv(value.hook)); +} + +} // namespace _ (private) + +template <> +void AnyPointer::Builder::adopt(Orphan&& orphan) { + switch (orphan.getType()) { + case DynamicValue::UNKNOWN: + case DynamicValue::VOID: + case DynamicValue::BOOL: + case DynamicValue::INT: + case DynamicValue::UINT: + case DynamicValue::FLOAT: + case DynamicValue::ENUM: + KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value."); + + case DynamicValue::STRUCT: + case DynamicValue::LIST: + case DynamicValue::TEXT: + case DynamicValue::DATA: + case DynamicValue::CAPABILITY: + case DynamicValue::ANY_POINTER: + builder.adopt(kj::mv(orphan.builder)); + break; + } +} + +DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan) + : schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {} +DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan) + : schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {} + +DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan) + : schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {} +DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan) + : schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT + ? orphan.asStructList(structSizeFromSchema(schema.getStructElementType())) + : orphan.asList(elementSizeFor(schema.whichElementType()))) {} + +// ------------------------------------------------------------------- + +Orphan Orphanage::newOrphan(StructSchema schema) const { + return Orphan( + schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema))); +} + +Orphan Orphanage::newOrphan(ListSchema schema, uint size) const { + if (schema.whichElementType() == schema::Type::STRUCT) { + return Orphan(schema, _::OrphanBuilder::initStructList( + arena, capTable, bounded(size) * ELEMENTS, + structSizeFromSchema(schema.getStructElementType()))); + } else { + return Orphan(schema, _::OrphanBuilder::initList( + arena, capTable, bounded(size) * ELEMENTS, + elementSizeFor(schema.whichElementType()))); + } +} + +DynamicStruct::Builder Orphan::get() { + return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema))); +} + +DynamicStruct::Reader Orphan::getReader() const { + return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema))); +} + +DynamicList::Builder Orphan::get() { + if (schema.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder( + schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType()))); + } else { + return DynamicList::Builder( + schema, builder.asList(elementSizeFor(schema.whichElementType()))); + } +} + +DynamicList::Reader Orphan::getReader() const { + return DynamicList::Reader( + schema, builder.asListReader(elementSizeFor(schema.whichElementType()))); +} + +DynamicCapability::Client Orphan::get() { + return DynamicCapability::Client(schema, builder.asCapability()); +} + +DynamicCapability::Client Orphan::getReader() const { + return DynamicCapability::Client(schema, builder.asCapability()); +} + +Orphan::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder) + : type(value.getType()), builder(kj::mv(builder)) { + switch (type) { + case DynamicValue::UNKNOWN: break; + case DynamicValue::VOID: voidValue = value.voidValue; break; + case DynamicValue::BOOL: boolValue = value.boolValue; break; + case DynamicValue::INT: intValue = value.intValue; break; + case DynamicValue::UINT: uintValue = value.uintValue; break; + case DynamicValue::FLOAT: floatValue = value.floatValue; break; + case DynamicValue::ENUM: enumValue = value.enumValue; break; + + case DynamicValue::TEXT: break; + case DynamicValue::DATA: break; + case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break; + case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break; + case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break; + case DynamicValue::ANY_POINTER: break; + } +} + +DynamicValue::Builder Orphan::get() { + switch (type) { + case DynamicValue::UNKNOWN: return nullptr; + case DynamicValue::VOID: return voidValue; + case DynamicValue::BOOL: return boolValue; + case DynamicValue::INT: return intValue; + case DynamicValue::UINT: return uintValue; + case DynamicValue::FLOAT: return floatValue; + case DynamicValue::ENUM: return enumValue; + + case DynamicValue::TEXT: return builder.asText(); + case DynamicValue::DATA: return builder.asData(); + case DynamicValue::LIST: + if (listSchema.whichElementType() == schema::Type::STRUCT) { + return DynamicList::Builder(listSchema, + builder.asStructList(structSizeFromSchema(listSchema.getStructElementType()))); + } else { + return DynamicList::Builder(listSchema, + builder.asList(elementSizeFor(listSchema.whichElementType()))); + } + case DynamicValue::STRUCT: + return DynamicStruct::Builder(structSchema, + builder.asStruct(structSizeFromSchema(structSchema))); + case DynamicValue::CAPABILITY: + return DynamicCapability::Client(interfaceSchema, builder.asCapability()); + case DynamicValue::ANY_POINTER: + KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to " + "wrap in an AnyPointer::Builder."); + } + KJ_UNREACHABLE; +} +DynamicValue::Reader Orphan::getReader() const { + switch (type) { + case DynamicValue::UNKNOWN: return nullptr; + case DynamicValue::VOID: return voidValue; + case DynamicValue::BOOL: return boolValue; + case DynamicValue::INT: return intValue; + case DynamicValue::UINT: return uintValue; + case DynamicValue::FLOAT: return floatValue; + case DynamicValue::ENUM: return enumValue; + + case DynamicValue::TEXT: return builder.asTextReader(); + case DynamicValue::DATA: return builder.asDataReader(); + case DynamicValue::LIST: + return DynamicList::Reader(listSchema, + builder.asListReader(elementSizeFor(listSchema.whichElementType()))); + case DynamicValue::STRUCT: + return DynamicStruct::Reader(structSchema, + builder.asStructReader(structSizeFromSchema(structSchema))); + case DynamicValue::CAPABILITY: + return DynamicCapability::Client(interfaceSchema, builder.asCapability()); + case DynamicValue::ANY_POINTER: + KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to " + "wrap in an AnyPointer::Builder."); + } + KJ_UNREACHABLE; +} + +template <> +Orphan Orphan::releaseAs() { + KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch."); + type = DynamicValue::UNKNOWN; + return Orphan(kj::mv(builder)); +} +template <> +Orphan Orphan::releaseAs() { + KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch."); + type = DynamicValue::UNKNOWN; + return Orphan(structSchema, kj::mv(builder)); +} +template <> +Orphan Orphan::releaseAs() { + KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch."); + type = DynamicValue::UNKNOWN; + return Orphan(listSchema, kj::mv(builder)); +} + +template <> +Orphan Orphanage::newOrphanCopy( + DynamicValue::Reader copyFrom) const { + switch (copyFrom.getType()) { + case DynamicValue::UNKNOWN: return nullptr; + case DynamicValue::VOID: return copyFrom.voidValue; + case DynamicValue::BOOL: return copyFrom.boolValue; + case DynamicValue::INT: return copyFrom.intValue; + case DynamicValue::UINT: return copyFrom.uintValue; + case DynamicValue::FLOAT: return copyFrom.floatValue; + case DynamicValue::ENUM: return copyFrom.enumValue; + + case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue); + case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue); + case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue); + case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue); + case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue); + case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue); + } + KJ_UNREACHABLE; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/dynamic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/dynamic.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1643 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file defines classes that can be used to manipulate messages based on schemas that are not +// known until runtime. This is also useful for writing generic code that uses schemas to handle +// arbitrary types in a generic way. +// +// Each of the classes defined here has a to() template method which converts an instance back to a +// native type. This method will throw an exception if the requested type does not match the +// schema. To convert native types to dynamic, use DynamicFactory. +// +// As always, underlying data is validated lazily, so you have to actually traverse the whole +// message if you want to validate all content. + +#ifndef CAPNP_DYNAMIC_H_ +#define CAPNP_DYNAMIC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema.h" +#include "layout.h" +#include "message.h" +#include "any.h" +#include "capability.h" + +namespace capnp { + +class MessageReader; +class MessageBuilder; + +struct DynamicValue { + DynamicValue() = delete; + + enum Type { + UNKNOWN, + // Means that the value has unknown type and content because it comes from a newer version of + // the schema, or from a newer version of Cap'n Proto that has new features that this version + // doesn't understand. + + VOID, + BOOL, + INT, + UINT, + FLOAT, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + CAPABILITY, + ANY_POINTER + }; + + class Reader; + class Builder; + class Pipeline; +}; +class DynamicEnum; +struct DynamicStruct { + DynamicStruct() = delete; + class Reader; + class Builder; + class Pipeline; +}; +struct DynamicList { + DynamicList() = delete; + class Reader; + class Builder; +}; +struct DynamicCapability { + DynamicCapability() = delete; + class Client; + class Server; +}; +template <> class Orphan; + +template struct DynamicTypeFor_; +template <> struct DynamicTypeFor_ { typedef DynamicEnum Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicStruct Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicList Type; }; +template <> struct DynamicTypeFor_ { typedef DynamicCapability Type; }; + +template +using DynamicTypeFor = typename DynamicTypeFor_()>::Type; + +template +ReaderFor>> toDynamic(T&& value); +template +BuilderFor>> toDynamic(T&& value); +template +DynamicTypeFor> toDynamic(T&& value); +template +typename DynamicTypeFor>::Client toDynamic(kj::Own&& value); + +namespace _ { // private + +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; + +} // namespace _ (private) + +template <> inline constexpr Style style() { return Style::POINTER; } +template <> inline constexpr Style style() { return Style::PRIMITIVE; } +template <> inline constexpr Style style() { return Style::STRUCT; } +template <> inline constexpr Style style() { return Style::POINTER; } +template <> inline constexpr Style style() { return Style::CAPABILITY; } + +// ------------------------------------------------------------------- + +class DynamicEnum { +public: + DynamicEnum() = default; + inline DynamicEnum(EnumSchema::Enumerant enumerant) + : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {} + inline DynamicEnum(EnumSchema schema, uint16_t value) + : schema(schema), value(value) {} + + template () == Kind::ENUM>> + inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} + + template + inline T as() const { return static_cast(asImpl(typeId())); } + // Cast to a native enum type. + + inline EnumSchema getSchema() const { return schema; } + + kj::Maybe getEnumerant() const; + // Get which enumerant this enum value represents. Returns nullptr if the numeric value does not + // correspond to any enumerant in the schema -- this can happen if the data was built using a + // newer schema that has more values defined. + + inline uint16_t getRaw() const { return value; } + // Returns the raw underlying enum value. + +private: + EnumSchema schema; + uint16_t value; + + uint16_t asImpl(uint64_t requestedTypeId) const; + + friend struct DynamicStruct; + friend struct DynamicList; + friend struct DynamicValue; + template + friend DynamicTypeFor> toDynamic(T&& value); +}; + +// ------------------------------------------------------------------- + +class DynamicStruct::Reader { +public: + typedef DynamicStruct Reads; + + Reader() = default; + + template >() == Kind::STRUCT>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } + + template + typename T::Reader as() const; + // Convert the dynamic struct to its compiled-in type. + + inline StructSchema getSchema() const { return schema; } + + DynamicValue::Reader get(StructSchema::Field field) const; + // Read the given field value. + + bool has(StructSchema::Field field) const; + // Tests whether the given field is set to its default value. For pointer values, this does + // not actually traverse the value comparing it with the default, but simply returns true if the + // pointer is non-null. For members of unions, has() returns false if the union member is not + // active, but does not necessarily return true if the member is active (depends on the field's + // value). + + kj::Maybe which() const; + // If the struct contains an (unnamed) union, and the currently-active field within that union + // is known, this returns that field. Otherwise, it returns null. In other words, this returns + // null if there is no union present _or_ if the union's discriminant is set to an unrecognized + // value. This could happen in particular when receiving a message from a sender who has a + // newer version of the protocol and is using a field of the union that you don't know about yet. + + DynamicValue::Reader get(kj::StringPtr name) const; + bool has(kj::StringPtr name) const; + // Shortcuts to access fields by name. These throw exceptions if no such field exists. + +private: + StructSchema schema; + _::StructReader reader; + + inline Reader(StructSchema schema, _::StructReader reader) + : schema(schema), reader(reader) {} + Reader(StructSchema schema, const _::OrphanBuilder& orphan); + + bool isSetInUnion(StructSchema::Field field) const; + void verifySetInUnion(StructSchema::Field field) const; + static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field); + + template + friend struct _::PointerHelpers; + friend class DynamicStruct::Builder; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template + friend struct ::capnp::ToDynamic_; + friend kj::StringTree _::structString( + _::StructReader reader, const _::RawBrandedSchema& schema); + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicStruct::Builder { +public: + typedef DynamicStruct Builds; + + Builder() = default; + inline Builder(decltype(nullptr)) {} + + template >() == Kind::STRUCT>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + inline MessageSize totalSize() const { return asReader().totalSize(); } + + template + typename T::Builder as(); + // Cast to a particular struct type. + + inline StructSchema getSchema() const { return schema; } + + DynamicValue::Builder get(StructSchema::Field field); + // Read the given field value. + + inline bool has(StructSchema::Field field) { return asReader().has(field); } + // Tests whether the given field is set to its default value. For pointer values, this does + // not actually traverse the value comparing it with the default, but simply returns true if the + // pointer is non-null. For members of unions, has() returns whether the field is currently + // active and the union as a whole is non-default -- so, the only time has() will return false + // for an active union field is if it is the default active field and it has its default value. + + kj::Maybe which(); + // If the struct contains an (unnamed) union, and the currently-active field within that union + // is known, this returns that field. Otherwise, it returns null. In other words, this returns + // null if there is no union present _or_ if the union's discriminant is set to an unrecognized + // value. This could happen in particular when receiving a message from a sender who has a + // newer version of the protocol and is using a field of the union that you don't know about yet. + + void set(StructSchema::Field field, const DynamicValue::Reader& value); + // Set the given field value. + + DynamicValue::Builder init(StructSchema::Field field); + DynamicValue::Builder init(StructSchema::Field field, uint size); + // Init a struct, list, or blob field. + + void adopt(StructSchema::Field field, Orphan&& orphan); + Orphan disown(StructSchema::Field field); + // Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set() + // and disown() becomes like get() followed by clear(). + + void clear(StructSchema::Field field); + // Clear a field, setting it to its default value. For pointer fields, this actually makes the + // field null. + + DynamicValue::Builder get(kj::StringPtr name); + bool has(kj::StringPtr name); + void set(kj::StringPtr name, const DynamicValue::Reader& value); + void set(kj::StringPtr name, std::initializer_list value); + DynamicValue::Builder init(kj::StringPtr name); + DynamicValue::Builder init(kj::StringPtr name, uint size); + void adopt(kj::StringPtr name, Orphan&& orphan); + Orphan disown(kj::StringPtr name); + void clear(kj::StringPtr name); + // Shortcuts to access fields by name. These throw exceptions if no such field exists. + + Reader asReader() const; + +private: + StructSchema schema; + _::StructBuilder builder; + + inline Builder(StructSchema schema, _::StructBuilder builder) + : schema(schema), builder(builder) {} + Builder(StructSchema schema, _::OrphanBuilder& orphan); + + bool isSetInUnion(StructSchema::Field field); + void verifySetInUnion(StructSchema::Field field); + void setInUnion(StructSchema::Field field); + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicStruct::Pipeline { +public: + typedef DynamicStruct Pipelines; + + inline Pipeline(decltype(nullptr)): typeless(nullptr) {} + + template + typename T::Pipeline releaseAs(); + // Convert the dynamic pipeline to its compiled-in type. + + inline StructSchema getSchema() { return schema; } + + DynamicValue::Pipeline get(StructSchema::Field field); + // Read the given field value. + + DynamicValue::Pipeline get(kj::StringPtr name); + // Get by string name. + +private: + StructSchema schema; + AnyPointer::Pipeline typeless; + + inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless) + : schema(schema), typeless(kj::mv(typeless)) {} + + friend class Request; +}; + +// ------------------------------------------------------------------- + +class DynamicList::Reader { +public: + typedef DynamicList Reads; + + inline Reader(): reader(ElementSize::VOID) {} + + template >() == Kind::LIST>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + template + typename T::Reader as() const; + // Try to convert to any List, Data, or Text. Throws an exception if the underlying data + // can't possibly represent the requested type. + + inline ListSchema getSchema() const { return schema; } + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + DynamicValue::Reader operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + ListSchema schema; + _::ListReader reader; + + Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {} + Reader(ListSchema schema, const _::OrphanBuilder& orphan); + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend class DynamicList::Builder; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +class DynamicList::Builder { +public: + typedef DynamicList Builds; + + inline Builder(): builder(ElementSize::VOID) {} + inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} + + template >() == Kind::LIST>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + template + typename T::Builder as(); + // Try to convert to any List, Data, or Text. Throws an exception if the underlying data + // can't possibly represent the requested type. + + inline ListSchema getSchema() const { return schema; } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + DynamicValue::Builder operator[](uint index); + void set(uint index, const DynamicValue::Reader& value); + DynamicValue::Builder init(uint index, uint size); + void adopt(uint index, Orphan&& orphan); + Orphan disown(uint index); + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + void copyFrom(std::initializer_list value); + + Reader asReader() const; + +private: + ListSchema schema; + _::ListBuilder builder; + + Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} + Builder(ListSchema schema, _::OrphanBuilder& orphan); + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + template + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + template + friend struct _::OrphanGetImpl; + friend class Orphan; + friend class Orphan; + friend class Orphan; +}; + +// ------------------------------------------------------------------- + +class DynamicCapability::Client: public Capability::Client { +public: + typedef DynamicCapability Calls; + typedef DynamicCapability Reads; + + Client() = default; + + template >() == Kind::INTERFACE>> + inline Client(T&& client); + + template ()>> + inline Client(kj::Own&& server); + + template () == Kind::INTERFACE>> + typename T::Client as(); + template () == Kind::INTERFACE>> + typename T::Client releaseAs(); + // Convert to any client type. + + Client upcast(InterfaceSchema requestedSchema); + // Upcast to a superclass. Throws an exception if `schema` is not a superclass. + + inline InterfaceSchema getSchema() { return schema; } + + Request newRequest( + InterfaceSchema::Method method, kj::Maybe sizeHint = nullptr); + Request newRequest( + kj::StringPtr methodName, kj::Maybe sizeHint = nullptr); + +private: + InterfaceSchema schema; + + Client(InterfaceSchema schema, kj::Own&& hook) + : Capability::Client(kj::mv(hook)), schema(schema) {} + + template + inline Client(InterfaceSchema schema, kj::Own&& server); + + friend struct Capability; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct DynamicValue; + friend class Orphan; + friend class Orphan; + friend class Orphan; + template + friend struct _::PointerHelpers; +}; + +class DynamicCapability::Server: public Capability::Server { +public: + typedef DynamicCapability Serves; + + Server(InterfaceSchema schema): schema(schema) {} + + virtual kj::Promise call(InterfaceSchema::Method method, + CallContext context) = 0; + + kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + CallContext context) override final; + + inline InterfaceSchema getSchema() const { return schema; } + +private: + InterfaceSchema schema; +}; + +template <> +class Request: public DynamicStruct::Builder { + // Specialization of `Request` for DynamicStruct. + +public: + inline Request(DynamicStruct::Builder builder, kj::Own&& hook, + StructSchema resultSchema) + : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} + + RemotePromise send(); + // Send the call and return a promise for the results. + +private: + kj::Own hook; + StructSchema resultSchema; + + friend class Capability::Client; + friend struct DynamicCapability; + template + friend class CallContext; + friend class RequestHook; +}; + +template <> +class CallContext: public kj::DisallowConstCopy { + // Wrapper around CallContextHook with a specific return type. + // + // Methods of this class may only be called from within the server's event loop, not from other + // threads. + +public: + explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType); + + DynamicStruct::Reader getParams(); + void releaseParams(); + DynamicStruct::Builder getResults(kj::Maybe sizeHint = nullptr); + DynamicStruct::Builder initResults(kj::Maybe sizeHint = nullptr); + void setResults(DynamicStruct::Reader value); + void adoptResults(Orphan&& value); + Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); + template + kj::Promise tailCall(Request&& tailRequest); + void allowCancellation(); + +private: + CallContextHook* hook; + StructSchema paramType; + StructSchema resultType; + + friend class DynamicCapability::Server; +}; + +// ------------------------------------------------------------------- + +// Make sure ReaderFor and BuilderFor work for DynamicEnum, DynamicStruct, and +// DynamicList, so that we can define DynamicValue::as(). + +template <> struct ReaderFor_ { typedef DynamicEnum Type; }; +template <> struct BuilderFor_ { typedef DynamicEnum Type; }; +template <> struct ReaderFor_ { typedef DynamicStruct::Reader Type; }; +template <> struct BuilderFor_ { typedef DynamicStruct::Builder Type; }; +template <> struct ReaderFor_ { typedef DynamicList::Reader Type; }; +template <> struct BuilderFor_ { typedef DynamicList::Builder Type; }; +template <> struct ReaderFor_ { typedef DynamicCapability::Client Type; }; +template <> struct BuilderFor_ { typedef DynamicCapability::Client Type; }; +template <> struct PipelineFor_ { typedef DynamicCapability::Client Type; }; + +class DynamicValue::Reader { +public: + typedef DynamicValue Reads; + + inline Reader(decltype(nullptr) n = nullptr); // UNKNOWN + inline Reader(Void value); + inline Reader(bool value); + inline Reader(char value); + inline Reader(signed char value); + inline Reader(short value); + inline Reader(int value); + inline Reader(long value); + inline Reader(long long value); + inline Reader(unsigned char value); + inline Reader(unsigned short value); + inline Reader(unsigned int value); + inline Reader(unsigned long value); + inline Reader(unsigned long long value); + inline Reader(float value); + inline Reader(double value); + inline Reader(const char* value); // Text + inline Reader(const Text::Reader& value); + inline Reader(const Data::Reader& value); + inline Reader(const DynamicList::Reader& value); + inline Reader(DynamicEnum value); + inline Reader(const DynamicStruct::Reader& value); + inline Reader(const AnyPointer::Reader& value); + inline Reader(DynamicCapability::Client& value); + inline Reader(DynamicCapability::Client&& value); + template ()>> + inline Reader(kj::Own&& value); + Reader(ConstSchema constant); + + template ()))> + inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {} + + Reader(const Reader& other); + Reader(Reader&& other) noexcept; + ~Reader() noexcept(false); + Reader& operator=(const Reader& other); + Reader& operator=(Reader&& other); + // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not + // trivially copyable. + + template + inline ReaderFor as() const { return AsImpl::apply(*this); } + // Use to interpret the value as some Cap'n Proto type. Allowed types are: + // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value. + // - Text, Data, AnyPointer, any struct type: Returns the corresponding Reader. + // - List for any T listed above: Returns List::Reader. + // - DynamicEnum: Returns the corresponding type. + // - DynamicStruct, DynamicList: Returns the corresponding Reader. + // - Any capability type, including DynamicCapability: Returns the corresponding Client. + // - DynamicValue: Returns an identical Reader. Useful to avoid special-casing in generic code. + // (TODO(perf): On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids + // refcounting.) + // + // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier. + // - Any integer can be converted to any other integer type so long as the actual value is within + // the new type's range. + // - Floating-point types can be converted to integers as long as no information would be lost + // in the conversion. + // - Integers can be converted to floating points. This may lose information, but won't throw. + // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose + // information, but won't throw. + // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not + // vice-versa). + // - Capabilities can be upcast (cast to a supertype), but not downcast. + // + // Any other conversion attempt will throw an exception. + + inline Type getType() const { return type; } + // Get the type of this value. + +private: + Type type; + + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + Text::Reader textValue; + Data::Reader dataValue; + DynamicList::Reader listValue; + DynamicEnum enumValue; + DynamicStruct::Reader structValue; + AnyPointer::Reader anyPointerValue; + + mutable DynamicCapability::Client capabilityValue; + // Declared mutable because `Client`s normally cannot be const. + + // Warning: Copy/move constructors assume all these types are trivially copyable except + // Capability. + }; + + template ()> struct AsImpl; + // Implementation backing the as() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. + + friend class Orphanage; // to speed up newOrphanCopy(DynamicValue::Reader) +}; + +class DynamicValue::Builder { +public: + typedef DynamicValue Builds; + + inline Builder(decltype(nullptr) n = nullptr); // UNKNOWN + inline Builder(Void value); + inline Builder(bool value); + inline Builder(char value); + inline Builder(signed char value); + inline Builder(short value); + inline Builder(int value); + inline Builder(long value); + inline Builder(long long value); + inline Builder(unsigned char value); + inline Builder(unsigned short value); + inline Builder(unsigned int value); + inline Builder(unsigned long value); + inline Builder(unsigned long long value); + inline Builder(float value); + inline Builder(double value); + inline Builder(Text::Builder value); + inline Builder(Data::Builder value); + inline Builder(DynamicList::Builder value); + inline Builder(DynamicEnum value); + inline Builder(DynamicStruct::Builder value); + inline Builder(AnyPointer::Builder value); + inline Builder(DynamicCapability::Client& value); + inline Builder(DynamicCapability::Client&& value); + + template ()))> + inline Builder(T value): Builder(toDynamic(value)) {} + + Builder(Builder& other); + Builder(Builder&& other) noexcept; + ~Builder() noexcept(false); + Builder& operator=(Builder& other); + Builder& operator=(Builder&& other); + // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not + // trivially copyable. + + template + inline BuilderFor as() { return AsImpl::apply(*this); } + // See DynamicValue::Reader::as(). + + inline Type getType() { return type; } + // Get the type of this value. + + Reader asReader() const; + +private: + Type type; + + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + Text::Builder textValue; + Data::Builder dataValue; + DynamicList::Builder listValue; + DynamicEnum enumValue; + DynamicStruct::Builder structValue; + AnyPointer::Builder anyPointerValue; + + mutable DynamicCapability::Client capabilityValue; + // Declared mutable because `Client`s normally cannot be const. + }; + + template ()> struct AsImpl; + // Implementation backing the as() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. + + friend class Orphan; +}; + +class DynamicValue::Pipeline { +public: + typedef DynamicValue Pipelines; + + inline Pipeline(decltype(nullptr) n = nullptr); + inline Pipeline(DynamicStruct::Pipeline&& value); + inline Pipeline(DynamicCapability::Client&& value); + + Pipeline(Pipeline&& other) noexcept; + Pipeline& operator=(Pipeline&& other); + ~Pipeline() noexcept(false); + + template + inline PipelineFor releaseAs() { return AsImpl::apply(*this); } + + inline Type getType() { return type; } + // Get the type of this value. + +private: + Type type; + union { + DynamicStruct::Pipeline structValue; + DynamicCapability::Client capabilityValue; + }; + + template ()> struct AsImpl; + // Implementation backing the releaseAs() method. Needs to be a struct to allow partial + // specialization. Has a method apply() which does the work. +}; + +kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value); +kj::StringTree KJ_STRINGIFY(DynamicEnum value); +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value); +kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value); +kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value); + +// ------------------------------------------------------------------- +// Orphan <-> Dynamic glue + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::STRUCT>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicStruct::Builder get(); + DynamicStruct::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + StructSchema schema; + _::OrphanBuilder builder; + + inline Orphan(StructSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; + friend class MessageBuilder; +}; + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::LIST>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicList::Builder get(); + DynamicList::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + // TODO(someday): Support truncate(). + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + ListSchema schema; + _::OrphanBuilder builder; + + inline Orphan(ListSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; +}; + +template <> +class Orphan { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template () == Kind::INTERFACE>> + inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} + + DynamicCapability::Client get(); + DynamicCapability::Client getReader() const; + + template + Orphan releaseAs(); + // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + +private: + InterfaceSchema schema; + _::OrphanBuilder builder; + + inline Orphan(InterfaceSchema schema, _::OrphanBuilder&& builder) + : schema(schema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan; + friend class Orphan; +}; + +template <> +class Orphan { +public: + inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {} + inline Orphan(Void value); + inline Orphan(bool value); + inline Orphan(char value); + inline Orphan(signed char value); + inline Orphan(short value); + inline Orphan(int value); + inline Orphan(long value); + inline Orphan(long long value); + inline Orphan(unsigned char value); + inline Orphan(unsigned short value); + inline Orphan(unsigned int value); + inline Orphan(unsigned long value); + inline Orphan(unsigned long long value); + inline Orphan(float value); + inline Orphan(double value); + inline Orphan(DynamicEnum value); + Orphan(Orphan&&) = default; + template + Orphan(Orphan&&); + Orphan(Orphan&&); + Orphan(void*) = delete; // So Orphan(bool) doesn't accept pointers. + KJ_DISALLOW_COPY(Orphan); + + Orphan& operator=(Orphan&&) = default; + + inline DynamicValue::Type getType() { return type; } + + DynamicValue::Builder get(); + DynamicValue::Reader getReader() const; + + template + Orphan releaseAs(); + // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan is no longer valid after this call; ownership is + // transferred to the returned Orphan. + +private: + DynamicValue::Type type; + union { + Void voidValue; + bool boolValue; + int64_t intValue; + uint64_t uintValue; + double floatValue; + DynamicEnum enumValue; + StructSchema structSchema; + ListSchema listSchema; + InterfaceSchema interfaceSchema; + }; + + _::OrphanBuilder builder; + // Only used if `type` is a pointer type. + + Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder); + Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder) + : type(type), builder(kj::mv(builder)) {} + Orphan(StructSchema structSchema, _::OrphanBuilder&& builder) + : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {} + Orphan(ListSchema listSchema, _::OrphanBuilder&& builder) + : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {} + + template + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct AnyPointer; + friend class Orphanage; +}; + +template +inline Orphan::Orphan(Orphan&& other) + : Orphan(other.get(), kj::mv(other.builder)) {} + +inline Orphan::Orphan(Orphan&& other) + : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + return Orphan(kj::mv(builder)); +} + +template +Orphan Orphan::releaseAs() { + get().as(); // type check + type = DynamicValue::UNKNOWN; + return Orphan(kj::mv(builder)); +} + +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); +template <> +Orphan Orphan::releaseAs(); + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(DynamicStruct::Builder& t) { + return t.builder; + } +}; + +template <> +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(DynamicList::Builder& t) { + return t.builder; + } +}; + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicStruct::Reader copyFrom) const { + return Orphan( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicList::Reader copyFrom) const { + return Orphan(copyFrom.getSchema(), + _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan Orphanage::newOrphanCopy( + DynamicCapability::Client copyFrom) const { + return Orphan( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); +} + +template <> +Orphan Orphanage::newOrphanCopy( + DynamicValue::Reader copyFrom) const; + +namespace _ { // private + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema); + static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema); + static void set(PointerBuilder builder, const DynamicStruct::Reader& value); + static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, StructSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema); + static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema); + static void set(PointerBuilder builder, const DynamicList::Reader& value); + static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, ListSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers { + // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for + // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we + // don't want people to accidentally be able to provide their own default value. + static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema); + static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema); + static void set(PointerBuilder builder, DynamicCapability::Client& value); + static void set(PointerBuilder builder, DynamicCapability::Client&& value); + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder, InterfaceSchema schema) { + return Orphan(schema, builder.disown()); + } +}; + +} // namespace _ (private) + +template +inline ReaderFor AnyPointer::Reader::getAs(StructSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline ReaderFor AnyPointer::Reader::getAs(ListSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline ReaderFor AnyPointer::Reader::getAs(InterfaceSchema schema) const { + return _::PointerHelpers::getDynamic(reader, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(StructSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(ListSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::getAs(InterfaceSchema schema) { + return _::PointerHelpers::getDynamic(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::initAs(StructSchema schema) { + return _::PointerHelpers::init(builder, schema); +} +template +inline BuilderFor AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { + return _::PointerHelpers::init(builder, schema, elementCount); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicStruct::Reader value) { + return _::PointerHelpers::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicList::Reader value) { + return _::PointerHelpers::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs(DynamicCapability::Client value) { + return _::PointerHelpers::set(builder, kj::mv(value)); +} +template <> +void AnyPointer::Builder::adopt(Orphan&& orphan); +template +inline Orphan AnyPointer::Builder::disownAs(StructSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} +template +inline Orphan AnyPointer::Builder::disownAs(ListSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} +template +inline Orphan AnyPointer::Builder::disownAs(InterfaceSchema schema) { + return _::PointerHelpers::disown(builder, schema); +} + +// We have to declare the methods below inline because Clang and GCC disagree about how to mangle +// their symbol names. +template <> +inline DynamicStruct::Builder Orphan::getAs(StructSchema schema) { + return DynamicStruct::Builder(schema, builder); +} +template <> +inline DynamicStruct::Reader Orphan::getAsReader( + StructSchema schema) const { + return DynamicStruct::Reader(schema, builder); +} +template <> +inline Orphan Orphan::releaseAs(StructSchema schema) { + return Orphan(schema, kj::mv(builder)); +} +template <> +inline DynamicList::Builder Orphan::getAs(ListSchema schema) { + return DynamicList::Builder(schema, builder); +} +template <> +inline DynamicList::Reader Orphan::getAsReader(ListSchema schema) const { + return DynamicList::Reader(schema, builder); +} +template <> +inline Orphan Orphan::releaseAs(ListSchema schema) { + return Orphan(schema, kj::mv(builder)); +} +template <> +inline DynamicCapability::Client Orphan::getAs( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline DynamicCapability::Client Orphan::getAsReader( + InterfaceSchema schema) const { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline Orphan Orphan::releaseAs( + InterfaceSchema schema) { + return Orphan(schema, kj::mv(builder)); +} + +// ======================================================================================= +// Inline implementation details. + +template +struct ToDynamic_ { + static inline DynamicStruct::Reader apply(const typename T::Reader& value) { + return DynamicStruct::Reader(Schema::from(), value._reader); + } + static inline DynamicStruct::Builder apply(typename T::Builder& value) { + return DynamicStruct::Builder(Schema::from(), value._builder); + } +}; + +template +struct ToDynamic_ { + static inline DynamicList::Reader apply(const typename T::Reader& value) { + return DynamicList::Reader(Schema::from(), value.reader); + } + static inline DynamicList::Builder apply(typename T::Builder& value) { + return DynamicList::Builder(Schema::from(), value.builder); + } +}; + +template +struct ToDynamic_ { + static inline DynamicCapability::Client apply(typename T::Client value) { + return DynamicCapability::Client(kj::mv(value)); + } + static inline DynamicCapability::Client apply(typename T::Client&& value) { + return DynamicCapability::Client(kj::mv(value)); + } +}; + +template +ReaderFor>> toDynamic(T&& value) { + return ToDynamic_>::apply(value); +} +template +BuilderFor>> toDynamic(T&& value) { + return ToDynamic_>::apply(value); +} +template +DynamicTypeFor> toDynamic(T&& value) { + return DynamicEnum(Schema::from>(), static_cast(value)); +} +template +typename DynamicTypeFor>::Client toDynamic(kj::Own&& value) { + return typename FromServer::Client(kj::mv(value)); +} + +inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {} +inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {} + +#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ +inline DynamicValue::Reader::Reader(cppType value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline DynamicValue::Builder::Builder(cppType value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline Orphan::Orphan(cppType value) \ + : type(DynamicValue::typeTag), fieldName##Value(value) {} + +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum); +#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR + +#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ +inline DynamicValue::Reader::Reader(const cppType::Reader& value) \ + : type(typeTag), fieldName##Value(value) {} \ +inline DynamicValue::Builder::Builder(cppType::Builder value) \ + : type(typeTag), fieldName##Value(value) {} + +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct); +CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer); + +#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR + +inline DynamicValue::Reader::Reader(DynamicCapability::Client& value) + : type(CAPABILITY), capabilityValue(value) {} +inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} +template +inline DynamicValue::Reader::Reader(kj::Own&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} +inline DynamicValue::Builder::Builder(DynamicCapability::Client& value) + : type(CAPABILITY), capabilityValue(value) {} +inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} + +inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {} + +#define CAPNP_DECLARE_TYPE(discrim, typeName) \ +template <> \ +struct DynamicValue::Reader::AsImpl { \ + static ReaderFor apply(const Reader& reader); \ +}; \ +template <> \ +struct DynamicValue::Builder::AsImpl { \ + static BuilderFor apply(Builder& builder); \ +}; + +//CAPNP_DECLARE_TYPE(VOID, Void) +CAPNP_DECLARE_TYPE(BOOL, bool) +CAPNP_DECLARE_TYPE(INT8, int8_t) +CAPNP_DECLARE_TYPE(INT16, int16_t) +CAPNP_DECLARE_TYPE(INT32, int32_t) +CAPNP_DECLARE_TYPE(INT64, int64_t) +CAPNP_DECLARE_TYPE(UINT8, uint8_t) +CAPNP_DECLARE_TYPE(UINT16, uint16_t) +CAPNP_DECLARE_TYPE(UINT32, uint32_t) +CAPNP_DECLARE_TYPE(UINT64, uint64_t) +CAPNP_DECLARE_TYPE(FLOAT32, float) +CAPNP_DECLARE_TYPE(FLOAT64, double) + +CAPNP_DECLARE_TYPE(TEXT, Text) +CAPNP_DECLARE_TYPE(DATA, Data) +CAPNP_DECLARE_TYPE(LIST, DynamicList) +CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct) +CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability) +CAPNP_DECLARE_TYPE(ENUM, DynamicEnum) +CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer) +#undef CAPNP_DECLARE_TYPE + +// CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the +// ReaderFor<> and BuilderFor<> wrappers, it works. +template <> +struct DynamicValue::Reader::AsImpl { + static Void apply(const Reader& reader); +}; +template <> +struct DynamicValue::Builder::AsImpl { + static Void apply(Builder& builder); +}; + +template +struct DynamicValue::Reader::AsImpl { + static T apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static T apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Reader apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Builder apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Reader apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Builder apply(Builder& builder) { + return builder.as().as(); + } +}; + +template +struct DynamicValue::Reader::AsImpl { + static typename T::Client apply(const Reader& reader) { + return reader.as().as(); + } +}; +template +struct DynamicValue::Builder::AsImpl { + static typename T::Client apply(Builder& builder) { + return builder.as().as(); + } +}; + +template <> +struct DynamicValue::Reader::AsImpl { + static DynamicValue::Reader apply(const Reader& reader) { + return reader; + } +}; +template <> +struct DynamicValue::Builder::AsImpl { + static DynamicValue::Builder apply(Builder& builder) { + return builder; + } +}; + +inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {} +inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value) + : type(STRUCT), structValue(kj::mv(value)) {} +inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value) + : type(CAPABILITY), capabilityValue(kj::mv(value)) {} + +template +struct DynamicValue::Pipeline::AsImpl { + static typename T::Pipeline apply(Pipeline& pipeline) { + return pipeline.releaseAs().releaseAs(); + } +}; +template +struct DynamicValue::Pipeline::AsImpl { + static typename T::Client apply(Pipeline& pipeline) { + return pipeline.releaseAs().releaseAs(); + } +}; +template <> +struct DynamicValue::Pipeline::AsImpl { + static PipelineFor apply(Pipeline& pipeline); +}; +template <> +struct DynamicValue::Pipeline::AsImpl { + static PipelineFor apply(Pipeline& pipeline); +}; + +// ------------------------------------------------------------------- + +template +typename T::Reader DynamicStruct::Reader::as() const { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Reader::as() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Reader(reader); +} + +template +typename T::Builder DynamicStruct::Builder::as() { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Builder::as() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Builder(builder); +} + +template <> +inline DynamicStruct::Reader DynamicStruct::Reader::as() const { + return *this; +} +template <> +inline DynamicStruct::Builder DynamicStruct::Builder::as() { + return *this; +} + +inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { + return DynamicStruct::Reader(schema, builder.asReader()); +} + +template <> +inline AnyStruct::Reader DynamicStruct::Reader::as() const { + return AnyStruct::Reader(reader); +} + +template <> +inline AnyStruct::Builder DynamicStruct::Builder::as() { + return AnyStruct::Builder(builder); +} + +template +typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { + static_assert(kind() == Kind::STRUCT, + "DynamicStruct::Pipeline::releaseAs() can only convert to struct types."); + schema.requireUsableAs(); + return typename T::Pipeline(kj::mv(typeless)); +} + +// ------------------------------------------------------------------- + +template +typename T::Reader DynamicList::Reader::as() const { + static_assert(kind() == Kind::LIST, + "DynamicStruct::Reader::as() can only convert to list types."); + schema.requireUsableAs(); + return typename T::Reader(reader); +} +template +typename T::Builder DynamicList::Builder::as() { + static_assert(kind() == Kind::LIST, + "DynamicStruct::Builder::as() can only convert to list types."); + schema.requireUsableAs(); + return typename T::Builder(builder); +} + +template <> +inline DynamicList::Reader DynamicList::Reader::as() const { + return *this; +} +template <> +inline DynamicList::Builder DynamicList::Builder::as() { + return *this; +} + +template <> +inline AnyList::Reader DynamicList::Reader::as() const { + return AnyList::Reader(reader); +} + +template <> +inline AnyList::Builder DynamicList::Builder::as() { + return AnyList::Builder(builder); +} + +// ------------------------------------------------------------------- + +template +inline DynamicCapability::Client::Client(T&& client) + : Capability::Client(kj::mv(client)), schema(Schema::from>()) {} + +template +inline DynamicCapability::Client::Client(kj::Own&& server) + : Client(server->getSchema(), kj::mv(server)) {} +template +inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own&& server) + : Capability::Client(kj::mv(server)), schema(schema) {} + +template +typename T::Client DynamicCapability::Client::as() { + static_assert(kind() == Kind::INTERFACE, + "DynamicCapability::Client::as() can only convert to interface types."); + schema.requireUsableAs(); + return typename T::Client(hook->addRef()); +} + +template +typename T::Client DynamicCapability::Client::releaseAs() { + static_assert(kind() == Kind::INTERFACE, + "DynamicCapability::Client::as() can only convert to interface types."); + schema.requireUsableAs(); + return typename T::Client(kj::mv(hook)); +} + +inline CallContext::CallContext( + CallContextHook& hook, StructSchema paramType, StructSchema resultType) + : hook(&hook), paramType(paramType), resultType(resultType) {} +inline DynamicStruct::Reader CallContext::getParams() { + return hook->getParams().getAs(paramType); +} +inline void CallContext::releaseParams() { + hook->releaseParams(); +} +inline DynamicStruct::Builder CallContext::getResults( + kj::Maybe sizeHint) { + return hook->getResults(sizeHint).getAs(resultType); +} +inline DynamicStruct::Builder CallContext::initResults( + kj::Maybe sizeHint) { + return hook->getResults(sizeHint).initAs(resultType); +} +inline void CallContext::setResults(DynamicStruct::Reader value) { + hook->getResults(value.totalSize()).setAs(value); +} +inline void CallContext::adoptResults(Orphan&& value) { + hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); +} +inline Orphanage CallContext::getResultsOrphanage( + kj::Maybe sizeHint) { + return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); +} +template +inline kj::Promise CallContext::tailCall( + Request&& tailRequest) { + return hook->tailCall(kj::mv(tailRequest.hook)); +} +inline void CallContext::allowCancellation() { + hook->allowCancellation(); +} + +template <> +inline DynamicCapability::Client Capability::Client::castAs( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, hook->addRef()); +} + +// ------------------------------------------------------------------- + +template +ReaderFor ConstSchema::as() const { + return DynamicValue::Reader(*this).as(); +} + +} // namespace capnp + +#endif // CAPNP_DYNAMIC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/encoding-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/encoding-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1934 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include "message.h" +#include +#include +#include "test-util.h" +#include "schema-lite.h" +#include "serialize-packed.h" + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Encoding, AllTypes) { + MallocMessageBuilder builder; + + initTestMessage(builder.initRoot()); + checkTestMessage(builder.getRoot()); + checkTestMessage(builder.getRoot().asReader()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + + checkTestMessage(reader.getRoot()); + + ASSERT_EQ(1u, builder.getSegmentsForOutput().size()); + + checkTestMessage(readMessageUnchecked(builder.getSegmentsForOutput()[0].begin())); + + EXPECT_EQ(builder.getSegmentsForOutput()[0].size() - 1, // -1 for root pointer + reader.getRoot().totalSize().wordCount); +} + +TEST(Encoding, AllTypesMultiSegment) { + MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE); + + initTestMessage(builder.initRoot()); + checkTestMessage(builder.getRoot()); + checkTestMessage(builder.getRoot().asReader()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Encoding, Defaults) { + AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}}; + kj::ArrayPtr segments[1] = {kj::arrayPtr(nullRoot.words, 1)}; + SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + + checkTestMessage(reader.getRoot()); + checkTestMessage(readMessageUnchecked(nullRoot.words)); + + checkTestMessage(TestDefaults::Reader()); +} + +TEST(Encoding, DefaultInitialization) { + MallocMessageBuilder builder; + + checkTestMessage(builder.getRoot()); // first pass initializes to defaults + checkTestMessage(builder.getRoot().asReader()); + + checkTestMessage(builder.getRoot()); // second pass just reads the initialized structure + checkTestMessage(builder.getRoot().asReader()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Encoding, DefaultInitializationMultiSegment) { + MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE); + + // first pass initializes to defaults + checkTestMessage(builder.getRoot()); + checkTestMessage(builder.getRoot().asReader()); + + // second pass just reads the initialized structure + checkTestMessage(builder.getRoot()); + checkTestMessage(builder.getRoot().asReader()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Encoding, DefaultsFromEmptyMessage) { + AlignedData<1> emptyMessage = {{0, 0, 0, 0, 0, 0, 0, 0}}; + + kj::ArrayPtr segments[1] = {kj::arrayPtr(emptyMessage.words, 1)}; + SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); + + checkTestMessage(reader.getRoot()); + checkTestMessage(readMessageUnchecked(emptyMessage.words)); +} + +TEST(Encoding, Unions) { + MallocMessageBuilder builder; + TestUnion::Builder root = builder.getRoot(); + + EXPECT_EQ(TestUnion::Union0::U0F0S0, root.getUnion0().which()); + EXPECT_EQ(VOID, root.getUnion0().getU0f0s0()); + EXPECT_DEBUG_ANY_THROW(root.getUnion0().getU0f0s1()); + + root.getUnion0().setU0f0s1(true); + EXPECT_EQ(TestUnion::Union0::U0F0S1, root.getUnion0().which()); + EXPECT_TRUE(root.getUnion0().getU0f0s1()); + EXPECT_DEBUG_ANY_THROW(root.getUnion0().getU0f0s0()); + + root.getUnion0().setU0f0s8(123); + EXPECT_EQ(TestUnion::Union0::U0F0S8, root.getUnion0().which()); + EXPECT_EQ(123, root.getUnion0().getU0f0s8()); + EXPECT_DEBUG_ANY_THROW(root.getUnion0().getU0f0s1()); +} + +struct UnionState { + uint discriminants[4]; + int dataOffset; + + UnionState(std::initializer_list discriminants, int dataOffset) + : dataOffset(dataOffset) { + memcpy(this->discriminants, discriminants.begin(), sizeof(this->discriminants)); + } + + bool operator==(const UnionState& other) const { + for (uint i = 0; i < 4; i++) { + if (discriminants[i] != other.discriminants[i]) { + return false; + } + } + + return dataOffset == other.dataOffset; + } +}; + +kj::String KJ_STRINGIFY(const UnionState& us) { + return kj::str("UnionState({", kj::strArray(us.discriminants, ", "), "}, ", us.dataOffset, ")"); +} + +template +UnionState initUnion(Func&& initializer) { + // Use the given setter to initialize the given union field and then return a struct indicating + // the location of the data that was written as well as the values of the four union + // discriminants. + + MallocMessageBuilder builder; + initializer(builder.getRoot()); + kj::ArrayPtr segment = builder.getSegmentsForOutput()[0]; + + KJ_ASSERT(segment.size() > 2, segment.size()); + + // Find the offset of the first set bit after the union discriminants. + int offset = 0; + for (const uint8_t* p = reinterpret_cast(segment.begin() + 2); + p < reinterpret_cast(segment.end()); p++) { + if (*p != 0) { + uint8_t bits = *p; + while ((bits & 1) == 0) { + ++offset; + bits >>= 1; + } + goto found; + } + offset += 8; + } + offset = -1; + +found: + const uint8_t* discriminants = reinterpret_cast(segment.begin() + 1); + return UnionState({discriminants[0], discriminants[2], discriminants[4], discriminants[6]}, + offset); +} + +TEST(Encoding, UnionLayout) { +#define INIT_UNION(setter) \ + initUnion([](TestUnion::Builder b) {b.setter;}) + + EXPECT_EQ(UnionState({ 0,0,0,0}, -1), INIT_UNION(getUnion0().setU0f0s0(VOID))); + EXPECT_EQ(UnionState({ 1,0,0,0}, 0), INIT_UNION(getUnion0().setU0f0s1(1))); + EXPECT_EQ(UnionState({ 2,0,0,0}, 0), INIT_UNION(getUnion0().setU0f0s8(1))); + EXPECT_EQ(UnionState({ 3,0,0,0}, 0), INIT_UNION(getUnion0().setU0f0s16(1))); + EXPECT_EQ(UnionState({ 4,0,0,0}, 0), INIT_UNION(getUnion0().setU0f0s32(1))); + EXPECT_EQ(UnionState({ 5,0,0,0}, 0), INIT_UNION(getUnion0().setU0f0s64(1))); + EXPECT_EQ(UnionState({ 6,0,0,0}, 448), INIT_UNION(getUnion0().setU0f0sp("1"))); + + EXPECT_EQ(UnionState({ 7,0,0,0}, -1), INIT_UNION(getUnion0().setU0f1s0(VOID))); + EXPECT_EQ(UnionState({ 8,0,0,0}, 0), INIT_UNION(getUnion0().setU0f1s1(1))); + EXPECT_EQ(UnionState({ 9,0,0,0}, 0), INIT_UNION(getUnion0().setU0f1s8(1))); + EXPECT_EQ(UnionState({10,0,0,0}, 0), INIT_UNION(getUnion0().setU0f1s16(1))); + EXPECT_EQ(UnionState({11,0,0,0}, 0), INIT_UNION(getUnion0().setU0f1s32(1))); + EXPECT_EQ(UnionState({12,0,0,0}, 0), INIT_UNION(getUnion0().setU0f1s64(1))); + EXPECT_EQ(UnionState({13,0,0,0}, 448), INIT_UNION(getUnion0().setU0f1sp("1"))); + + EXPECT_EQ(UnionState({0, 0,0,0}, -1), INIT_UNION(getUnion1().setU1f0s0(VOID))); + EXPECT_EQ(UnionState({0, 1,0,0}, 65), INIT_UNION(getUnion1().setU1f0s1(1))); + EXPECT_EQ(UnionState({0, 2,0,0}, 65), INIT_UNION(getUnion1().setU1f1s1(1))); + EXPECT_EQ(UnionState({0, 3,0,0}, 72), INIT_UNION(getUnion1().setU1f0s8(1))); + EXPECT_EQ(UnionState({0, 4,0,0}, 72), INIT_UNION(getUnion1().setU1f1s8(1))); + EXPECT_EQ(UnionState({0, 5,0,0}, 80), INIT_UNION(getUnion1().setU1f0s16(1))); + EXPECT_EQ(UnionState({0, 6,0,0}, 80), INIT_UNION(getUnion1().setU1f1s16(1))); + EXPECT_EQ(UnionState({0, 7,0,0}, 96), INIT_UNION(getUnion1().setU1f0s32(1))); + EXPECT_EQ(UnionState({0, 8,0,0}, 96), INIT_UNION(getUnion1().setU1f1s32(1))); + EXPECT_EQ(UnionState({0, 9,0,0}, 128), INIT_UNION(getUnion1().setU1f0s64(1))); + EXPECT_EQ(UnionState({0,10,0,0}, 128), INIT_UNION(getUnion1().setU1f1s64(1))); + EXPECT_EQ(UnionState({0,11,0,0}, 512), INIT_UNION(getUnion1().setU1f0sp("1"))); + EXPECT_EQ(UnionState({0,12,0,0}, 512), INIT_UNION(getUnion1().setU1f1sp("1"))); + + EXPECT_EQ(UnionState({0,13,0,0}, -1), INIT_UNION(getUnion1().setU1f2s0(VOID))); + EXPECT_EQ(UnionState({0,14,0,0}, 65), INIT_UNION(getUnion1().setU1f2s1(1))); + EXPECT_EQ(UnionState({0,15,0,0}, 72), INIT_UNION(getUnion1().setU1f2s8(1))); + EXPECT_EQ(UnionState({0,16,0,0}, 80), INIT_UNION(getUnion1().setU1f2s16(1))); + EXPECT_EQ(UnionState({0,17,0,0}, 96), INIT_UNION(getUnion1().setU1f2s32(1))); + EXPECT_EQ(UnionState({0,18,0,0}, 128), INIT_UNION(getUnion1().setU1f2s64(1))); + EXPECT_EQ(UnionState({0,19,0,0}, 512), INIT_UNION(getUnion1().setU1f2sp("1"))); + + EXPECT_EQ(UnionState({0,0,0,0}, 192), INIT_UNION(getUnion2().setU2f0s1(1))); + EXPECT_EQ(UnionState({0,0,0,0}, 193), INIT_UNION(getUnion3().setU3f0s1(1))); + EXPECT_EQ(UnionState({0,0,1,0}, 200), INIT_UNION(getUnion2().setU2f0s8(1))); + EXPECT_EQ(UnionState({0,0,0,1}, 208), INIT_UNION(getUnion3().setU3f0s8(1))); + EXPECT_EQ(UnionState({0,0,2,0}, 224), INIT_UNION(getUnion2().setU2f0s16(1))); + EXPECT_EQ(UnionState({0,0,0,2}, 240), INIT_UNION(getUnion3().setU3f0s16(1))); + EXPECT_EQ(UnionState({0,0,3,0}, 256), INIT_UNION(getUnion2().setU2f0s32(1))); + EXPECT_EQ(UnionState({0,0,0,3}, 288), INIT_UNION(getUnion3().setU3f0s32(1))); + EXPECT_EQ(UnionState({0,0,4,0}, 320), INIT_UNION(getUnion2().setU2f0s64(1))); + EXPECT_EQ(UnionState({0,0,0,4}, 384), INIT_UNION(getUnion3().setU3f0s64(1))); + +#undef INIT_UNION +} + +TEST(Encoding, UnnamedUnion) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + EXPECT_EQ(test::TestUnnamedUnion::FOO, root.which()); + + root.setBar(321); + EXPECT_EQ(test::TestUnnamedUnion::BAR, root.which()); + EXPECT_EQ(test::TestUnnamedUnion::BAR, root.asReader().which()); + EXPECT_EQ(321u, root.getBar()); + EXPECT_EQ(321u, root.asReader().getBar()); + EXPECT_DEBUG_ANY_THROW(root.getFoo()); + EXPECT_DEBUG_ANY_THROW(root.asReader().getFoo()); + + root.setFoo(123); + EXPECT_EQ(test::TestUnnamedUnion::FOO, root.which()); + EXPECT_EQ(test::TestUnnamedUnion::FOO, root.asReader().which()); + EXPECT_EQ(123u, root.getFoo()); + EXPECT_EQ(123u, root.asReader().getFoo()); + EXPECT_DEBUG_ANY_THROW(root.getBar()); + EXPECT_DEBUG_ANY_THROW(root.asReader().getBar()); + +#if !CAPNP_LITE + StructSchema schema = Schema::from(); + + // The discriminant is allocated just before allocating "bar". + EXPECT_EQ(2u, schema.getProto().getStruct().getDiscriminantOffset()); + EXPECT_EQ(0u, schema.getFieldByName("foo").getProto().getSlot().getOffset()); + EXPECT_EQ(2u, schema.getFieldByName("bar").getProto().getSlot().getOffset()); +#endif // !CAPNP_LITE +} + +TEST(Encoding, Groups) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + { + auto foo = root.getGroups().initFoo(); + foo.setCorge(12345678); + foo.setGrault(123456789012345ll); + foo.setGarply("foobar"); + + EXPECT_EQ(12345678, foo.getCorge()); + EXPECT_EQ(123456789012345ll, foo.getGrault()); + EXPECT_EQ("foobar", foo.getGarply()); + } + + { + auto bar = root.getGroups().initBar(); + bar.setCorge(23456789); + bar.setGrault("barbaz"); + bar.setGarply(234567890123456ll); + + EXPECT_EQ(23456789, bar.getCorge()); + EXPECT_EQ("barbaz", bar.getGrault()); + EXPECT_EQ(234567890123456ll, bar.getGarply()); + } + + { + auto baz = root.getGroups().initBaz(); + baz.setCorge(34567890); + baz.setGrault("bazqux"); + baz.setGarply("quxquux"); + + EXPECT_EQ(34567890, baz.getCorge()); + EXPECT_EQ("bazqux", baz.getGrault()); + EXPECT_EQ("quxquux", baz.getGarply()); + } +} + +TEST(Encoding, InterleavedGroups) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + // Init both groups to different values. + { + auto group = root.getGroup1(); + group.setFoo(12345678u); + group.setBar(123456789012345llu); + auto corge = group.initCorge(); + corge.setGrault(987654321098765llu); + corge.setGarply(12345u); + corge.setPlugh("plugh"); + corge.setXyzzy("xyzzy"); + group.setWaldo("waldo"); + } + + { + auto group = root.getGroup2(); + group.setFoo(23456789u); + group.setBar(234567890123456llu); + auto corge = group.initCorge(); + corge.setGrault(876543210987654llu); + corge.setGarply(23456u); + corge.setPlugh("hgulp"); + corge.setXyzzy("yzzyx"); + group.setWaldo("odlaw"); + } + + // Check group1 is still set correctly. + { + auto group = root.asReader().getGroup1(); + EXPECT_EQ(12345678u, group.getFoo()); + EXPECT_EQ(123456789012345llu, group.getBar()); + auto corge = group.getCorge(); + EXPECT_EQ(987654321098765llu, corge.getGrault()); + EXPECT_EQ(12345u, corge.getGarply()); + EXPECT_EQ("plugh", corge.getPlugh()); + EXPECT_EQ("xyzzy", corge.getXyzzy()); + EXPECT_EQ("waldo", group.getWaldo()); + } + + // Zero out group 1 and see if it is zero'd. + { + auto group = root.initGroup1().asReader(); + EXPECT_EQ(0u, group.getFoo()); + EXPECT_EQ(0u, group.getBar()); + EXPECT_EQ(test::TestInterleavedGroups::Group1::QUX, group.which()); + EXPECT_EQ(0u, group.getQux()); + EXPECT_FALSE(group.hasWaldo()); + } + + // Group 2 should not have been touched. + { + auto group = root.asReader().getGroup2(); + EXPECT_EQ(23456789u, group.getFoo()); + EXPECT_EQ(234567890123456llu, group.getBar()); + auto corge = group.getCorge(); + EXPECT_EQ(876543210987654llu, corge.getGrault()); + EXPECT_EQ(23456u, corge.getGarply()); + EXPECT_EQ("hgulp", corge.getPlugh()); + EXPECT_EQ("yzzyx", corge.getXyzzy()); + EXPECT_EQ("odlaw", group.getWaldo()); + } +} + +TEST(Encoding, UnionDefault) { + MallocMessageBuilder builder; + TestUnionDefaults::Reader reader = builder.getRoot().asReader(); + + { + auto field = reader.getS16s8s64s8Set(); + EXPECT_EQ(TestUnion::Union0::U0F0S16, field.getUnion0().which()); + EXPECT_EQ(TestUnion::Union1::U1F0S8 , field.getUnion1().which()); + EXPECT_EQ(TestUnion::Union2::U2F0S64, field.getUnion2().which()); + EXPECT_EQ(TestUnion::Union3::U3F0S8 , field.getUnion3().which()); + EXPECT_EQ(321, field.getUnion0().getU0f0s16()); + EXPECT_EQ(123, field.getUnion1().getU1f0s8()); + EXPECT_EQ(12345678901234567ll, field.getUnion2().getU2f0s64()); + EXPECT_EQ(55, field.getUnion3().getU3f0s8()); + } + + { + auto field = reader.getS0sps1s32Set(); + EXPECT_EQ(TestUnion::Union0::U0F1S0 , field.getUnion0().which()); + EXPECT_EQ(TestUnion::Union1::U1F0SP , field.getUnion1().which()); + EXPECT_EQ(TestUnion::Union2::U2F0S1 , field.getUnion2().which()); + EXPECT_EQ(TestUnion::Union3::U3F0S32, field.getUnion3().which()); + EXPECT_EQ(VOID, field.getUnion0().getU0f1s0()); + EXPECT_EQ("foo", field.getUnion1().getU1f0sp()); + EXPECT_EQ(true, field.getUnion2().getU2f0s1()); + EXPECT_EQ(12345678, field.getUnion3().getU3f0s32()); + } + + { + auto field = reader.getUnnamed1(); + EXPECT_EQ(test::TestUnnamedUnion::FOO, field.which()); + EXPECT_EQ(123u, field.getFoo()); + EXPECT_FALSE(field.hasBefore()); + EXPECT_FALSE(field.hasAfter()); + } + + { + auto field = reader.getUnnamed2(); + EXPECT_EQ(test::TestUnnamedUnion::BAR, field.which()); + EXPECT_EQ(321u, field.getBar()); + EXPECT_EQ("foo", field.getBefore()); + EXPECT_EQ("bar", field.getAfter()); + } +} + +// ======================================================================================= + +TEST(Encoding, ListDefaults) { + MallocMessageBuilder builder; + TestListDefaults::Builder root = builder.getRoot(); + + checkTestMessage(root.asReader()); + checkTestMessage(root); + checkTestMessage(root.asReader()); +} + +TEST(Encoding, BuildListDefaults) { + MallocMessageBuilder builder; + TestListDefaults::Builder root = builder.getRoot(); + + initTestMessage(root); + checkTestMessage(root.asReader()); + checkTestMessage(root); + checkTestMessage(root.asReader()); +} + +TEST(Encoding, SmallStructLists) { + // In this test, we will manually initialize TestListDefaults.lists to match the default + // value and verify that we end up with the same encoding that the compiler produces. + + MallocMessageBuilder builder; + auto root = builder.getRoot(); + auto sl = root.initLists(); + + // Verify that all the lists are actually empty. + EXPECT_EQ(0u, sl.getList0 ().size()); + EXPECT_EQ(0u, sl.getList1 ().size()); + EXPECT_EQ(0u, sl.getList8 ().size()); + EXPECT_EQ(0u, sl.getList16().size()); + EXPECT_EQ(0u, sl.getList32().size()); + EXPECT_EQ(0u, sl.getList64().size()); + EXPECT_EQ(0u, sl.getListP ().size()); + EXPECT_EQ(0u, sl.getInt32ListList().size()); + EXPECT_EQ(0u, sl.getTextListList().size()); + EXPECT_EQ(0u, sl.getStructListList().size()); + + { auto l = sl.initList0 (2); l[0].setF(VOID); l[1].setF(VOID); } + { auto l = sl.initList1 (4); l[0].setF(true); l[1].setF(false); + l[2].setF(true); l[3].setF(true); } + { auto l = sl.initList8 (2); l[0].setF(123u); l[1].setF(45u); } + { auto l = sl.initList16(2); l[0].setF(12345u); l[1].setF(6789u); } + { auto l = sl.initList32(2); l[0].setF(123456789u); l[1].setF(234567890u); } + { auto l = sl.initList64(2); l[0].setF(1234567890123456u); l[1].setF(2345678901234567u); } + { auto l = sl.initListP (2); l[0].setF("foo"); l[1].setF("bar"); } + + { + auto l = sl.initInt32ListList(3); + l.set(0, {1, 2, 3}); + l.set(1, {4, 5}); + l.set(2, {12341234}); + } + + { + auto l = sl.initTextListList(3); + l.set(0, {"foo", "bar"}); + l.set(1, {"baz"}); + l.set(2, {"qux", "corge"}); + } + + { + auto l = sl.initStructListList(2); + l.init(0, 2); + l.init(1, 1); + + l[0][0].setInt32Field(123); + l[0][1].setInt32Field(456); + l[1][0].setInt32Field(789); + } + + kj::ArrayPtr segment = builder.getSegmentsForOutput()[0]; + + // Initialize another message such that it copies the default value for that field. + MallocMessageBuilder defaultBuilder; + defaultBuilder.getRoot().getLists(); + kj::ArrayPtr defaultSegment = defaultBuilder.getSegmentsForOutput()[0]; + + // Should match... + EXPECT_EQ(defaultSegment.size(), segment.size()); + + for (size_t i = 0; i < kj::min(segment.size(), defaultSegment.size()); i++) { + EXPECT_EQ(reinterpret_cast(defaultSegment.begin())[i], + reinterpret_cast(segment.begin())[i]); + } +} + +TEST(Encoding, SetListToEmpty) { + // Test initializing list fields from various ways of constructing zero-sized lists. + // At one point this would often fail because the lists would have ElementSize::VOID which is + // incompatible with other list sizes. + +#define ALL_LIST_TYPES(MACRO) \ + MACRO(Void, Void) \ + MACRO(Bool, bool) \ + MACRO(UInt8, uint8_t) \ + MACRO(UInt16, uint16_t) \ + MACRO(UInt32, uint32_t) \ + MACRO(UInt64, uint64_t) \ + MACRO(Int8, int8_t) \ + MACRO(Int16, int16_t) \ + MACRO(Int32, int32_t) \ + MACRO(Int64, int64_t) \ + MACRO(Float32, float) \ + MACRO(Float64, double) \ + MACRO(Text, Text) \ + MACRO(Data, Data) \ + MACRO(Struct, TestAllTypes) + +#define SET_FROM_READER_ACCESSOR(name, type) \ + root.set##name##List(reader.get##name##List()); + +#define SET_FROM_BUILDER_ACCESSOR(name, type) \ + root.set##name##List(root.get##name##List()); + +#define SET_FROM_READER_CONSTRUCTOR(name, type) \ + root.set##name##List(List::Reader()); + +#define SET_FROM_BUILDER_CONSTRUCTOR(name, type) \ + root.set##name##List(List::Builder()); + +#define CHECK_EMPTY_NONNULL(name, type) \ + EXPECT_TRUE(root.has##name##List()); \ + EXPECT_EQ(0, root.get##name##List().size()); + + { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + auto reader = root.asReader(); + ALL_LIST_TYPES(SET_FROM_READER_ACCESSOR) + ALL_LIST_TYPES(CHECK_EMPTY_NONNULL) + } + + { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + ALL_LIST_TYPES(SET_FROM_BUILDER_ACCESSOR) + ALL_LIST_TYPES(CHECK_EMPTY_NONNULL) + } + + { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + ALL_LIST_TYPES(SET_FROM_READER_CONSTRUCTOR) + ALL_LIST_TYPES(CHECK_EMPTY_NONNULL) + } + + { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + ALL_LIST_TYPES(SET_FROM_BUILDER_CONSTRUCTOR) + ALL_LIST_TYPES(CHECK_EMPTY_NONNULL) + } + +#undef SET_FROM_READER_ACCESSOR +#undef SET_FROM_BUILDER_ACCESSOR +#undef SET_FROM_READER_CONSTRUCTOR +#undef SET_FROM_BUILDER_CONSTRUCTOR +#undef CHECK_EMPTY_NONNULL +} + +#if CAPNP_EXPENSIVE_TESTS +TEST(Encoding, LongList) { + // This test allocates 512MB of contiguous memory and takes several seconds, so we usually don't + // run it. It is run before release, though. + + MallocMessageBuilder builder; + + auto root = builder.initRoot(); + uint length = 1 << 27; + auto list = root.initUInt64List(length); + for (uint ii = 0; ii < length; ++ii) { + list.set(ii, ii); + } + for (uint ii = 0; ii < length; ++ii) { + ASSERT_EQ(list[ii], ii); + } +} +#endif + +// ======================================================================================= + +TEST(Encoding, ListUpgrade) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({12, 34, 56}); + + checkList(root.getAnyPointerField().getAs>(), {12, 34, 56}); + + { + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(3u, l.size()); + EXPECT_EQ(12u, l[0].getF()); + EXPECT_EQ(34u, l[1].getF()); + EXPECT_EQ(56u, l[2].getF()); + } + + checkList(root.getAnyPointerField().getAs>(), {12, 34, 56}); + + auto reader = root.asReader(); + + checkList(reader.getAnyPointerField().getAs>(), {12, 34, 56}); + + { + auto l = reader.getAnyPointerField().getAs>(); + ASSERT_EQ(3u, l.size()); + EXPECT_EQ(12u, l[0].getF()); + EXPECT_EQ(34u, l[1].getF()); + EXPECT_EQ(56u, l[2].getF()); + } + + root.getAnyPointerField().setAs>({12, 34, 56}); + + { + kj::Maybe e = kj::runCatchingExceptions([&]() { + reader.getAnyPointerField().getAs>(); +#if !KJ_NO_EXCEPTIONS + ADD_FAILURE() << "Should have thrown an exception."; +#endif + }); + + KJ_EXPECT(e != nullptr, "Should have thrown an exception."); + } + + { + auto l = reader.getAnyPointerField().getAs>(); + ASSERT_EQ(3u, l.size()); + + // These should return default values because the structs aren't big enough. + EXPECT_EQ(0u, l[0].getF()); + EXPECT_EQ(0u, l[1].getF()); + EXPECT_EQ(0u, l[2].getF()); + } + + checkList(reader.getAnyPointerField().getAs>(), {12, 34, 56}); +} + +TEST(Encoding, BitListDowngrade) { + // NO LONGER SUPPORTED -- We check for exceptions thrown. + + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({0x1201u, 0x3400u, 0x5601u, 0x7801u}); + + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + { + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_TRUE(l[0].getF()); + EXPECT_FALSE(l[1].getF()); + EXPECT_TRUE(l[2].getF()); + EXPECT_TRUE(l[3].getF()); + } + + checkList(root.getAnyPointerField().getAs>(), + {0x1201u, 0x3400u, 0x5601u, 0x7801u}); + + auto reader = root.asReader(); + + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + { + auto l = reader.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_TRUE(l[0].getF()); + EXPECT_FALSE(l[1].getF()); + EXPECT_TRUE(l[2].getF()); + EXPECT_TRUE(l[3].getF()); + } + + checkList(reader.getAnyPointerField().getAs>(), + {0x1201u, 0x3400u, 0x5601u, 0x7801u}); +} + +TEST(Encoding, BitListDowngradeFromStruct) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + { + auto list = root.getAnyPointerField().initAs>(4); + list[0].setF(true); + list[1].setF(false); + list[2].setF(true); + list[3].setF(true); + } + + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + { + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_TRUE(l[0].getF()); + EXPECT_FALSE(l[1].getF()); + EXPECT_TRUE(l[2].getF()); + EXPECT_TRUE(l[3].getF()); + } + + auto reader = root.asReader(); + + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + { + auto l = reader.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_TRUE(l[0].getF()); + EXPECT_FALSE(l[1].getF()); + EXPECT_TRUE(l[2].getF()); + EXPECT_TRUE(l[3].getF()); + } +} + +TEST(Encoding, BitListUpgrade) { + // No longer supported! + + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({true, false, true, true}); + + { + kj::Maybe e = kj::runCatchingExceptions([&]() { + root.getAnyPointerField().getAs>(); +#if !KJ_NO_EXCEPTIONS + ADD_FAILURE() << "Should have thrown an exception."; +#endif + }); + + KJ_EXPECT(e != nullptr, "Should have thrown an exception."); + } + + auto reader = root.asReader(); + + { + kj::Maybe e = kj::runCatchingExceptions([&]() { + reader.getAnyPointerField().getAs>(); +#if !KJ_NO_EXCEPTIONS + ADD_FAILURE() << "Should have thrown an exception."; +#endif + }); + + KJ_EXPECT(e != nullptr, "Should have thrown an exception."); + } +} + +TEST(Encoding, UpgradeStructInBuilder) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + test::TestOldVersion::Reader oldReader; + + { + auto oldVersion = root.getAnyPointerField().initAs(); + oldVersion.setOld1(123); + oldVersion.setOld2("foo"); + auto sub = oldVersion.initOld3(); + sub.setOld1(456); + sub.setOld2("bar"); + + oldReader = oldVersion; + } + + size_t size = builder.getSegmentsForOutput()[0].size(); + size_t size2; + + { + auto newVersion = root.getAnyPointerField().getAs(); + + // The old instance should have been zero'd. + EXPECT_EQ(0, oldReader.getOld1()); + EXPECT_EQ("", oldReader.getOld2()); + EXPECT_EQ(0, oldReader.getOld3().getOld1()); + EXPECT_EQ("", oldReader.getOld3().getOld2()); + + // Size should have increased due to re-allocating the struct. + size_t size1 = builder.getSegmentsForOutput()[0].size(); + EXPECT_GT(size1, size); + + auto sub = newVersion.getOld3(); + + // Size should have increased due to re-allocating the sub-struct. + size2 = builder.getSegmentsForOutput()[0].size(); + EXPECT_GT(size2, size1); + + // Check contents. + EXPECT_EQ(123, newVersion.getOld1()); + EXPECT_EQ("foo", newVersion.getOld2()); + EXPECT_EQ(987, newVersion.getNew1()); + EXPECT_EQ("baz", newVersion.getNew2()); + + EXPECT_EQ(456, sub.getOld1()); + EXPECT_EQ("bar", sub.getOld2()); + EXPECT_EQ(987, sub.getNew1()); + EXPECT_EQ("baz", sub.getNew2()); + + newVersion.setOld1(234); + newVersion.setOld2("qux"); + newVersion.setNew1(321); + newVersion.setNew2("quux"); + + sub.setOld1(567); + sub.setOld2("corge"); + sub.setNew1(654); + sub.setNew2("grault"); + } + + // We set four small text fields and implicitly initialized two to defaults, so the size should + // have raised by six words. + size_t size3 = builder.getSegmentsForOutput()[0].size(); + EXPECT_EQ(size2 + 6, size3); + + { + // Go back to old version. It should have the values set on the new version. + auto oldVersion = root.getAnyPointerField().getAs(); + EXPECT_EQ(234, oldVersion.getOld1()); + EXPECT_EQ("qux", oldVersion.getOld2()); + + auto sub = oldVersion.getOld3(); + EXPECT_EQ(567, sub.getOld1()); + EXPECT_EQ("corge", sub.getOld2()); + + // Overwrite the old fields. The new fields should remain intact. + oldVersion.setOld1(345); + oldVersion.setOld2("garply"); + sub.setOld1(678); + sub.setOld2("waldo"); + } + + // We set two small text fields, so the size should have raised by two words. + size_t size4 = builder.getSegmentsForOutput()[0].size(); + EXPECT_EQ(size3 + 2, size4); + + { + // Back to the new version again. + auto newVersion = root.getAnyPointerField().getAs(); + EXPECT_EQ(345, newVersion.getOld1()); + EXPECT_EQ("garply", newVersion.getOld2()); + EXPECT_EQ(321, newVersion.getNew1()); + EXPECT_EQ("quux", newVersion.getNew2()); + + auto sub = newVersion.getOld3(); + EXPECT_EQ(678, sub.getOld1()); + EXPECT_EQ("waldo", sub.getOld2()); + EXPECT_EQ(654, sub.getNew1()); + EXPECT_EQ("grault", sub.getNew2()); + } + + // Size should not have changed because we didn't write anything and the structs were already + // the right size. + EXPECT_EQ(size4, builder.getSegmentsForOutput()[0].size()); +} + +TEST(Encoding, UpgradeStructInBuilderMultiSegment) { + // Exactly like the previous test, except that we force multiple segments. Since we force a + // separate segment for every object, every pointer is a far pointer, and far pointers are easily + // transferred, so this is actually not such a complicated case. + + MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE); + auto root = builder.initRoot(); + + // Start with a 1-word first segment and the root object in the second segment. + size_t size = builder.getSegmentsForOutput().size(); + EXPECT_EQ(2u, size); + + { + auto oldVersion = root.getAnyPointerField().initAs(); + oldVersion.setOld1(123); + oldVersion.setOld2("foo"); + auto sub = oldVersion.initOld3(); + sub.setOld1(456); + sub.setOld2("bar"); + } + + // Allocated two structs and two strings. + size_t size2 = builder.getSegmentsForOutput().size(); + EXPECT_EQ(size + 4, size2); + + size_t size4; + + { + auto newVersion = root.getAnyPointerField().getAs(); + + // Allocated a new struct. + size_t size3 = builder.getSegmentsForOutput().size(); + EXPECT_EQ(size2 + 1, size3); + + auto sub = newVersion.getOld3(); + + // Allocated another new struct for its string field. + size4 = builder.getSegmentsForOutput().size(); + EXPECT_EQ(size3 + 1, size4); + + // Check contents. + EXPECT_EQ(123, newVersion.getOld1()); + EXPECT_EQ("foo", newVersion.getOld2()); + EXPECT_EQ(987, newVersion.getNew1()); + EXPECT_EQ("baz", newVersion.getNew2()); + + EXPECT_EQ(456, sub.getOld1()); + EXPECT_EQ("bar", sub.getOld2()); + EXPECT_EQ(987, sub.getNew1()); + EXPECT_EQ("baz", sub.getNew2()); + + newVersion.setOld1(234); + newVersion.setOld2("qux"); + newVersion.setNew1(321); + newVersion.setNew2("quux"); + + sub.setOld1(567); + sub.setOld2("corge"); + sub.setNew1(654); + sub.setNew2("grault"); + } + + // Set four strings and implicitly initialized two. + size_t size5 = builder.getSegmentsForOutput().size(); + EXPECT_EQ(size4 + 6, size5); + + { + // Go back to old version. It should have the values set on the new version. + auto oldVersion = root.getAnyPointerField().getAs(); + EXPECT_EQ(234, oldVersion.getOld1()); + EXPECT_EQ("qux", oldVersion.getOld2()); + + auto sub = oldVersion.getOld3(); + EXPECT_EQ(567, sub.getOld1()); + EXPECT_EQ("corge", sub.getOld2()); + + // Overwrite the old fields. The new fields should remain intact. + oldVersion.setOld1(345); + oldVersion.setOld2("garply"); + sub.setOld1(678); + sub.setOld2("waldo"); + } + + // Set two new strings. + size_t size6 = builder.getSegmentsForOutput().size(); + EXPECT_EQ(size5 + 2, size6); + + { + // Back to the new version again. + auto newVersion = root.getAnyPointerField().getAs(); + EXPECT_EQ(345, newVersion.getOld1()); + EXPECT_EQ("garply", newVersion.getOld2()); + EXPECT_EQ(321, newVersion.getNew1()); + EXPECT_EQ("quux", newVersion.getNew2()); + + auto sub = newVersion.getOld3(); + EXPECT_EQ(678, sub.getOld1()); + EXPECT_EQ("waldo", sub.getOld2()); + EXPECT_EQ(654, sub.getNew1()); + EXPECT_EQ("grault", sub.getNew2()); + } + + // Size should not have changed because we didn't write anything and the structs were already + // the right size. + EXPECT_EQ(size6, builder.getSegmentsForOutput().size()); +} + +TEST(Encoding, UpgradeStructInBuilderFarPointers) { + // Force allocation of a Far pointer. + + MallocMessageBuilder builder(7, AllocationStrategy::FIXED_SIZE); + auto root = builder.initRoot(); + + root.getAnyPointerField().initAs().setOld2("foo"); + + // We should have allocated all but one word of the first segment. + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); + EXPECT_EQ(6u, builder.getSegmentsForOutput()[0].size()); + + // Now if we upgrade... + EXPECT_EQ("foo", root.getAnyPointerField().getAs().getOld2()); + + // We should have allocated the new struct in a new segment, but allocated the far pointer + // landing pad back in the first segment. + ASSERT_EQ(2u, builder.getSegmentsForOutput().size()); + EXPECT_EQ(7u, builder.getSegmentsForOutput()[0].size()); + EXPECT_EQ(6u, builder.getSegmentsForOutput()[1].size()); +} + +TEST(Encoding, UpgradeStructInBuilderDoubleFarPointers) { + // Force allocation of a double-Far pointer. + + MallocMessageBuilder builder(6, AllocationStrategy::FIXED_SIZE); + auto root = builder.initRoot(); + + root.getAnyPointerField().initAs().setOld2("foo"); + + // We should have allocated all of the first segment. + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); + EXPECT_EQ(6u, builder.getSegmentsForOutput()[0].size()); + + // Now if we upgrade... + EXPECT_EQ("foo", root.getAnyPointerField().getAs().getOld2()); + + // We should have allocated the new struct in a new segment, and also allocated the far pointer + // landing pad in yet another segment. + ASSERT_EQ(3u, builder.getSegmentsForOutput().size()); + EXPECT_EQ(6u, builder.getSegmentsForOutput()[0].size()); + EXPECT_EQ(6u, builder.getSegmentsForOutput()[1].size()); + EXPECT_EQ(2u, builder.getSegmentsForOutput()[2].size()); +} + +void checkUpgradedList(test::TestAnyPointer::Builder root, + std::initializer_list expectedData, + std::initializer_list expectedPointers) { + { + auto builder = root.getAnyPointerField().getAs>(); + + ASSERT_EQ(expectedData.size(), builder.size()); + for (uint i = 0; i < expectedData.size(); i++) { + EXPECT_EQ(expectedData.begin()[i], builder[i].getOld1()); + EXPECT_EQ(expectedPointers.begin()[i], builder[i].getOld2()); + + // Other fields shouldn't be set. + EXPECT_EQ(0, builder[i].asReader().getOld3().getOld1()); + EXPECT_EQ("", builder[i].asReader().getOld3().getOld2()); + EXPECT_EQ(987, builder[i].getNew1()); + EXPECT_EQ("baz", builder[i].getNew2()); + + // Write some new data. + builder[i].setOld1(i * 123); + builder[i].setOld2(kj::str("qux", i, '\0').begin()); + builder[i].setNew1(i * 456); + builder[i].setNew2(kj::str("corge", i, '\0').begin()); + } + } + + // Read the newly-written data as TestOldVersion to ensure it was updated. + { + auto builder = root.getAnyPointerField().getAs>(); + + ASSERT_EQ(expectedData.size(), builder.size()); + for (uint i = 0; i < expectedData.size(); i++) { + EXPECT_EQ(i * 123, builder[i].getOld1()); + EXPECT_EQ(Text::Reader(kj::str("qux", i, "\0").begin()), builder[i].getOld2()); + } + } + + // Also read back as TestNewVersion again. + { + auto builder = root.getAnyPointerField().getAs>(); + + ASSERT_EQ(expectedData.size(), builder.size()); + for (uint i = 0; i < expectedData.size(); i++) { + EXPECT_EQ(i * 123, builder[i].getOld1()); + EXPECT_EQ(Text::Reader(kj::str("qux", i, '\0').begin()), builder[i].getOld2()); + EXPECT_EQ(i * 456, builder[i].getNew1()); + EXPECT_EQ(Text::Reader(kj::str("corge", i, '\0').begin()), builder[i].getNew2()); + } + } +} + +TEST(Encoding, UpgradeListInBuilder) { + // Test every damned list upgrade. + + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + // ----------------------------------------------------------------- + + root.getAnyPointerField().setAs>({VOID, VOID, VOID, VOID}); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkUpgradedList(root, {0, 0, 0, 0}, {"", "", "", ""}); + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({true, false, true, true}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {true, false, true, true}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + checkList(orig, {true, false, true, true}); + + // Can't upgrade bit lists. (This used to be supported.) + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + } + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({0x12, 0x23, 0x33, 0x44}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0x12, 0x23, 0x33, 0x44}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + checkList(orig, {0x12, 0x23, 0x33, 0x44}); + checkUpgradedList(root, {0x12, 0x23, 0x33, 0x44}, {"", "", "", ""}); + checkList(orig, {0, 0, 0, 0}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({0x5612, 0x7823, 0xab33, 0xcd44}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0x12, 0x23, 0x33, 0x44}); + checkList(root.getAnyPointerField().getAs>(), {0x5612, 0x7823, 0xab33, 0xcd44}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + checkList(orig, {0x5612, 0x7823, 0xab33, 0xcd44}); + checkUpgradedList(root, {0x5612, 0x7823, 0xab33, 0xcd44}, {"", "", "", ""}); + checkList(orig, {0, 0, 0, 0}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({0x17595612, 0x29347823, 0x5923ab32, 0x1a39cd45}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0x12, 0x23, 0x32, 0x45}); + checkList(root.getAnyPointerField().getAs>(), {0x5612, 0x7823, 0xab32, 0xcd45}); + checkList(root.getAnyPointerField().getAs>(), {0x17595612u, 0x29347823u, 0x5923ab32u, 0x1a39cd45u}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + checkList(orig, {0x17595612u, 0x29347823u, 0x5923ab32u, 0x1a39cd45u}); + checkUpgradedList(root, {0x17595612, 0x29347823, 0x5923ab32, 0x1a39cd45}, {"", "", "", ""}); + checkList(orig, {0u, 0u, 0u, 0u}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({0x1234abcd8735fe21, 0x7173bc0e1923af36}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0x21, 0x36}); + checkList(root.getAnyPointerField().getAs>(), {0xfe21, 0xaf36}); + checkList(root.getAnyPointerField().getAs>(), {0x8735fe21u, 0x1923af36u}); + checkList(root.getAnyPointerField().getAs>(), {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + checkList(orig, {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull}); + checkUpgradedList(root, {0x1234abcd8735fe21ull, 0x7173bc0e1923af36ull}, {"", ""}); + checkList(orig, {0u, 0u}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + + { + root.getAnyPointerField().setAs>({"foo", "bar", "baz"}); + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {"foo", "bar", "baz"}); + + checkList(orig, {"foo", "bar", "baz"}); + checkUpgradedList(root, {0, 0, 0}, {"foo", "bar", "baz"}); + checkList(orig, {"", "", ""}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + + { + { + auto l = root.getAnyPointerField().initAs>(3); + l[0].setOld1(0x1234567890abcdef); + l[1].setOld1(0x234567890abcdef1); + l[2].setOld1(0x34567890abcdef12); + l[0].setOld2("foo"); + l[1].setOld2("bar"); + l[2].setOld2("baz"); + } + auto orig = root.asReader().getAnyPointerField().getAs>(); + + checkList(root.getAnyPointerField().getAs>(), {VOID, VOID, VOID}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0xefu, 0xf1u, 0x12u}); + checkList(root.getAnyPointerField().getAs>(), {0xcdefu, 0xdef1u, 0xef12u}); + checkList(root.getAnyPointerField().getAs>(), {0x90abcdefu, 0x0abcdef1u, 0xabcdef12u}); + checkList(root.getAnyPointerField().getAs>(), + {0x1234567890abcdefull, 0x234567890abcdef1ull, 0x34567890abcdef12ull}); + checkList(root.getAnyPointerField().getAs>(), {"foo", "bar", "baz"}); + + checkList(orig, {0x1234567890abcdefull, 0x234567890abcdef1ull, 0x34567890abcdef12ull}, + {"foo", "bar", "baz"}); + checkUpgradedList(root, {0x1234567890abcdefull, 0x234567890abcdef1ull, 0x34567890abcdef12ull}, + {"foo", "bar", "baz"}); + checkList(orig, {0u, 0u, 0u}, {"", "", ""}); // old location zero'd during upgrade + } + + // ----------------------------------------------------------------- + // OK, now we've tested upgrading every primitive list to every primitive list, every primitive + // list to a multi-word struct, and a multi-word struct to every primitive list. But we haven't + // tried upgrading primitive lists to sub-word structs. + + // Upgrade from multi-byte, sub-word data. + root.getAnyPointerField().setAs>({12u, 34u, 56u, 78u}); + { + auto orig = root.asReader().getAnyPointerField().getAs>(); + checkList(orig, {12u, 34u, 56u, 78u}); + auto l = root.getAnyPointerField().getAs>(); + checkList(orig, {0u, 0u, 0u, 0u}); // old location zero'd during upgrade + ASSERT_EQ(4u, l.size()); + EXPECT_EQ(12u, l[0].getF()); + EXPECT_EQ(34u, l[1].getF()); + EXPECT_EQ(56u, l[2].getF()); + EXPECT_EQ(78u, l[3].getF()); + l[0].setF(0x65ac1235u); + l[1].setF(0x13f12879u); + l[2].setF(0x33423082u); + l[3].setF(0x12988948u); + } + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {0x35u, 0x79u, 0x82u, 0x48u}); + checkList(root.getAnyPointerField().getAs>(), {0x1235u, 0x2879u, 0x3082u, 0x8948u}); + checkList(root.getAnyPointerField().getAs>(), + {0x65ac1235u, 0x13f12879u, 0x33423082u, 0x12988948u}); + checkList(root.getAnyPointerField().getAs>(), + {0x65ac1235u, 0x13f12879u, 0x33423082u, 0x12988948u}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + // Upgrade from void -> data struct + root.getAnyPointerField().setAs>({VOID, VOID, VOID, VOID}); + { + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_EQ(0u, l[0].getF()); + EXPECT_EQ(0u, l[1].getF()); + EXPECT_EQ(0u, l[2].getF()); + EXPECT_EQ(0u, l[3].getF()); + l[0].setF(12573); + l[1].setF(3251); + l[2].setF(9238); + l[3].setF(5832); + } + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {12573u, 3251u, 9238u, 5832u}); + checkList(root.getAnyPointerField().getAs>(), {12573u, 3251u, 9238u, 5832u}); + checkList(root.getAnyPointerField().getAs>(), {12573u, 3251u, 9238u, 5832u}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + + // Upgrade from void -> pointer struct + root.getAnyPointerField().setAs>({VOID, VOID, VOID, VOID}); + { + auto l = root.getAnyPointerField().getAs>(); + ASSERT_EQ(4u, l.size()); + EXPECT_EQ("", l[0].getF()); + EXPECT_EQ("", l[1].getF()); + EXPECT_EQ("", l[2].getF()); + EXPECT_EQ("", l[3].getF()); + l[0].setF("foo"); + l[1].setF("bar"); + l[2].setF("baz"); + l[3].setF("qux"); + } + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + checkList(root.getAnyPointerField().getAs>(), {"foo", "bar", "baz", "qux"}); + + // Verify that we cannot "side-grade" a pointer list to a data list, or a data list to + // a pointer struct list. + root.getAnyPointerField().setAs>({"foo", "bar", "baz", "qux"}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); + root.getAnyPointerField().setAs>({12, 34, 56, 78}); + EXPECT_NONFATAL_FAILURE(root.getAnyPointerField().getAs>()); +} + +TEST(Encoding, UpgradeUnion) { + // This tests for a specific case that was broken originally. + MallocMessageBuilder builder; + + { + auto root = builder.getRoot(); + root.setB(123); + } + + { + auto root = builder.getRoot(); + ASSERT_TRUE(root.isB()) + EXPECT_EQ(123, root.getB()); + } +} + +// ======================================================================================= +// Tests of generated code, not really of the encoding. +// TODO(cleanup): Move to a different test? + +TEST(Encoding, NestedTypes) { + // This is more of a test of the generated code than the encoding. + + MallocMessageBuilder builder; + TestNestedTypes::Reader reader = builder.getRoot().asReader(); + + EXPECT_EQ(TestNestedTypes::NestedEnum::BAR, reader.getOuterNestedEnum()); + EXPECT_EQ(TestNestedTypes::NestedStruct::NestedEnum::QUUX, reader.getInnerNestedEnum()); + + TestNestedTypes::NestedStruct::Reader nested = reader.getNestedStruct(); + EXPECT_EQ(TestNestedTypes::NestedEnum::BAR, nested.getOuterNestedEnum()); + EXPECT_EQ(TestNestedTypes::NestedStruct::NestedEnum::QUUX, nested.getInnerNestedEnum()); +} + +TEST(Encoding, Imports) { + // Also just testing the generated code. + + { + MallocMessageBuilder builder; + TestImport::Builder root = builder.getRoot(); + initTestMessage(root.initField()); + checkTestMessage(root.asReader().getField()); + } + + { + MallocMessageBuilder builder; + TestImport2::Builder root = builder.getRoot(); + initTestMessage(root.initFoo()); + checkTestMessage(root.asReader().getFoo()); + root.setBar(schemaProto()); + initTestMessage(root.initBaz().initField()); + checkTestMessage(root.asReader().getBaz().getField()); + } +} + +TEST(Encoding, Using) { + MallocMessageBuilder builder; + TestUsing::Reader reader = builder.getRoot().asReader(); + EXPECT_EQ(TestNestedTypes::NestedEnum::BAR, reader.getOuterNestedEnum()); + EXPECT_EQ(TestNestedTypes::NestedStruct::NestedEnum::QUUX, reader.getInnerNestedEnum()); +} + +TEST(Encoding, StructSetters) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + initTestMessage(root); + + { + MallocMessageBuilder builder2; + builder2.setRoot(root.asReader()); + checkTestMessage(builder2.getRoot()); + } + + { + MallocMessageBuilder builder2; + auto root2 = builder2.getRoot(); + root2.setStructField(root); + checkTestMessage(root2.getStructField()); + } + + { + MallocMessageBuilder builder2; + auto root2 = builder2.getRoot(); + root2.getAnyPointerField().setAs(root); + checkTestMessage(root2.getAnyPointerField().getAs()); + } +} + +TEST(Encoding, OneBitStructSetters) { + // Test case of setting a 1-bit struct. + + MallocMessageBuilder builder; + auto root = builder.getRoot(); + auto list = root.initList1(8); + list[0].setF(true); + list[1].setF(true); + list[2].setF(false); + list[3].setF(true); + list[4].setF(true); + list[5].setF(false); + list[6].setF(true); + list[7].setF(false); + + MallocMessageBuilder builder2; + builder2.setRoot(list.asReader()[2]); + EXPECT_FALSE(builder2.getRoot().getF()); + builder2.setRoot(list.asReader()[6]); + EXPECT_TRUE(builder2.getRoot().getF()); +} + +TEST(Encoding, ListSetters) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + initTestMessage(root); + + { + MallocMessageBuilder builder2; + auto root2 = builder2.getRoot(); + + root2.getLists().setList0(root.getLists().getList0()); + root2.getLists().setList1(root.getLists().getList1()); + root2.getLists().setList8(root.getLists().getList8()); + root2.getLists().setList16(root.getLists().getList16()); + root2.getLists().setList32(root.getLists().getList32()); + root2.getLists().setList64(root.getLists().getList64()); + root2.getLists().setListP(root.getLists().getListP()); + + { + auto dst = root2.getLists().initInt32ListList(3); + auto src = root.getLists().getInt32ListList(); + dst.set(0, src[0]); + dst.set(1, src[1]); + dst.set(2, src[2]); + } + + { + auto dst = root2.getLists().initTextListList(3); + auto src = root.getLists().getTextListList(); + dst.set(0, src[0]); + dst.set(1, src[1]); + dst.set(2, src[2]); + } + + { + auto dst = root2.getLists().initStructListList(2); + auto src = root.getLists().getStructListList(); + dst.set(0, src[0]); + dst.set(1, src[1]); + } + } +} + +TEST(Encoding, ZeroOldObject) { + MallocMessageBuilder builder; + + auto root = builder.initRoot(); + initTestMessage(root); + + auto oldRoot = root.asReader(); + checkTestMessage(oldRoot); + + auto oldSub = oldRoot.getStructField(); + auto oldSub2 = oldRoot.getStructList()[0]; + + root = builder.initRoot(); + checkTestMessageAllZero(oldRoot); + checkTestMessageAllZero(oldSub); + checkTestMessageAllZero(oldSub2); +} + +TEST(Encoding, Has) { + MallocMessageBuilder builder; + + auto root = builder.initRoot(); + + EXPECT_FALSE(root.hasTextField()); + EXPECT_FALSE(root.hasDataField()); + EXPECT_FALSE(root.hasStructField()); + EXPECT_FALSE(root.hasInt32List()); + + EXPECT_FALSE(root.asReader().hasTextField()); + EXPECT_FALSE(root.asReader().hasDataField()); + EXPECT_FALSE(root.asReader().hasStructField()); + EXPECT_FALSE(root.asReader().hasInt32List()); + + initTestMessage(root); + + EXPECT_TRUE(root.hasTextField()); + EXPECT_TRUE(root.hasDataField()); + EXPECT_TRUE(root.hasStructField()); + EXPECT_TRUE(root.hasInt32List()); + + EXPECT_TRUE(root.asReader().hasTextField()); + EXPECT_TRUE(root.asReader().hasDataField()); + EXPECT_TRUE(root.asReader().hasStructField()); + EXPECT_TRUE(root.asReader().hasInt32List()); +} + +TEST(Encoding, VoidListAmplification) { + MallocMessageBuilder builder; + builder.initRoot().getAnyPointerField().initAs>(1u << 28); + + auto segments = builder.getSegmentsForOutput(); + EXPECT_EQ(1, segments.size()); + EXPECT_LT(segments[0].size(), 16); // quite small for such a big list! + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + auto root = reader.getRoot().getAnyPointerField(); + EXPECT_NONFATAL_FAILURE(root.getAs>()); + + MallocMessageBuilder copy; + EXPECT_NONFATAL_FAILURE(copy.setRoot(reader.getRoot())); +} + +TEST(Encoding, EmptyStructListAmplification) { + MallocMessageBuilder builder(1024); + auto listList = builder.initRoot().getAnyPointerField() + .initAs>>(500); + + for (uint i = 0; i < listList.size(); i++) { + listList.init(i, 1u << 28); + } + + auto segments = builder.getSegmentsForOutput(); + ASSERT_EQ(1, segments.size()); + + SegmentArrayMessageReader reader(builder.getSegmentsForOutput()); + auto root = reader.getRoot(); + auto listListReader = root.getAnyPointerField().getAs>>(); + EXPECT_NONFATAL_FAILURE(listListReader[0]); + EXPECT_NONFATAL_FAILURE(listListReader[10]); + + EXPECT_EQ(segments[0].size() - 1, root.totalSize().wordCount); +} + +TEST(Encoding, Constants) { + EXPECT_EQ(VOID, test::TestConstants::VOID_CONST); + EXPECT_EQ(true, test::TestConstants::BOOL_CONST); + EXPECT_EQ(-123, test::TestConstants::INT8_CONST); + EXPECT_EQ(-12345, test::TestConstants::INT16_CONST); + EXPECT_EQ(-12345678, test::TestConstants::INT32_CONST); + EXPECT_EQ(-123456789012345ll, test::TestConstants::INT64_CONST); + EXPECT_EQ(234u, test::TestConstants::UINT8_CONST); + EXPECT_EQ(45678u, test::TestConstants::UINT16_CONST); + EXPECT_EQ(3456789012u, test::TestConstants::UINT32_CONST); + EXPECT_EQ(12345678901234567890ull, test::TestConstants::UINT64_CONST); + EXPECT_FLOAT_EQ(1234.5f, test::TestConstants::FLOAT32_CONST); + EXPECT_DOUBLE_EQ(-123e45, test::TestConstants::FLOAT64_CONST); + EXPECT_EQ("foo", *test::TestConstants::TEXT_CONST); + EXPECT_EQ(data("bar"), test::TestConstants::DATA_CONST); + { + TestAllTypes::Reader subReader = test::TestConstants::STRUCT_CONST; + EXPECT_EQ(VOID, subReader.getVoidField()); + EXPECT_EQ(true, subReader.getBoolField()); + EXPECT_EQ(-12, subReader.getInt8Field()); + EXPECT_EQ(3456, subReader.getInt16Field()); + EXPECT_EQ(-78901234, subReader.getInt32Field()); + EXPECT_EQ(56789012345678ll, subReader.getInt64Field()); + EXPECT_EQ(90u, subReader.getUInt8Field()); + EXPECT_EQ(1234u, subReader.getUInt16Field()); + EXPECT_EQ(56789012u, subReader.getUInt32Field()); + EXPECT_EQ(345678901234567890ull, subReader.getUInt64Field()); + EXPECT_FLOAT_EQ(-1.25e-10f, subReader.getFloat32Field()); + EXPECT_DOUBLE_EQ(345, subReader.getFloat64Field()); + EXPECT_EQ("baz", subReader.getTextField()); + EXPECT_EQ(data("qux"), subReader.getDataField()); + { + auto subSubReader = subReader.getStructField(); + EXPECT_EQ("nested", subSubReader.getTextField()); + EXPECT_EQ("really nested", subSubReader.getStructField().getTextField()); + } + EXPECT_EQ(TestEnum::BAZ, subReader.getEnumField()); + + checkList(subReader.getVoidList(), {VOID, VOID, VOID}); + checkList(subReader.getBoolList(), {false, true, false, true, true}); + checkList(subReader.getInt8List(), {12, -34, -0x80, 0x7f}); + checkList(subReader.getInt16List(), {1234, -5678, -0x8000, 0x7fff}); + // gcc warns on -0x800... and the only work-around I could find was to do -0x7ff...-1. + checkList(subReader.getInt32List(), {12345678, -90123456, -0x7fffffff - 1, 0x7fffffff}); + checkList(subReader.getInt64List(), {123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll}); + checkList(subReader.getUInt8List(), {12u, 34u, 0u, 0xffu}); + checkList(subReader.getUInt16List(), {1234u, 5678u, 0u, 0xffffu}); + checkList(subReader.getUInt32List(), {12345678u, 90123456u, 0u, 0xffffffffu}); + checkList(subReader.getUInt64List(), {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); + checkList(subReader.getFloat32List(), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f}); + checkList(subReader.getFloat64List(), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306}); + checkList(subReader.getTextList(), {"quux", "corge", "grault"}); + checkList(subReader.getDataList(), {data("garply"), data("waldo"), data("fred")}); + { + auto listReader = subReader.getStructList(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("x structlist 1", listReader[0].getTextField()); + EXPECT_EQ("x structlist 2", listReader[1].getTextField()); + EXPECT_EQ("x structlist 3", listReader[2].getTextField()); + } + checkList(subReader.getEnumList(), {TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT}); + } + EXPECT_EQ(TestEnum::CORGE, test::TestConstants::ENUM_CONST); + + EXPECT_EQ(6u, test::TestConstants::VOID_LIST_CONST->size()); + checkList(*test::TestConstants::BOOL_LIST_CONST, {true, false, false, true}); + checkList(*test::TestConstants::INT8_LIST_CONST, {111, -111}); + checkList(*test::TestConstants::INT16_LIST_CONST, {11111, -11111}); + checkList(*test::TestConstants::INT32_LIST_CONST, {111111111, -111111111}); + checkList(*test::TestConstants::INT64_LIST_CONST, {1111111111111111111ll, -1111111111111111111ll}); + checkList(*test::TestConstants::UINT8_LIST_CONST, {111u, 222u}); + checkList(*test::TestConstants::UINT16_LIST_CONST, {33333u, 44444u}); + checkList(*test::TestConstants::UINT32_LIST_CONST, {3333333333u}); + checkList(*test::TestConstants::UINT64_LIST_CONST, {11111111111111111111ull}); + { + List::Reader listReader = test::TestConstants::FLOAT32_LIST_CONST; + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(5555.5f, listReader[0]); + EXPECT_EQ(kj::inf(), listReader[1]); + EXPECT_EQ(-kj::inf(), listReader[2]); + EXPECT_TRUE(listReader[3] != listReader[3]); + } + { + List::Reader listReader = test::TestConstants::FLOAT64_LIST_CONST; + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(7777.75, listReader[0]); + EXPECT_EQ(kj::inf(), listReader[1]); + EXPECT_EQ(-kj::inf(), listReader[2]); + EXPECT_TRUE(listReader[3] != listReader[3]); + } + checkList(*test::TestConstants::TEXT_LIST_CONST, {"plugh", "xyzzy", "thud"}); + checkList(*test::TestConstants::DATA_LIST_CONST, {data("oops"), data("exhausted"), data("rfc3092")}); + { + List::Reader listReader = test::TestConstants::STRUCT_LIST_CONST; + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("structlist 1", listReader[0].getTextField()); + EXPECT_EQ("structlist 2", listReader[1].getTextField()); + EXPECT_EQ("structlist 3", listReader[2].getTextField()); + } + checkList(*test::TestConstants::ENUM_LIST_CONST, {TestEnum::FOO, TestEnum::GARPLY}); +} + +TEST(Encoding, AnyPointerConstants) { + auto reader = test::ANY_POINTER_CONSTANTS.get(); + + EXPECT_EQ("baz", reader.getAnyKindAsStruct().getAs().getTextField()); + EXPECT_EQ("baz", reader.getAnyStructAsStruct().as().getTextField()); + + EXPECT_EQ(111111111, reader.getAnyKindAsList().getAs>()[0]); + EXPECT_EQ(111111111, reader.getAnyListAsList().as>()[0]); +} + +TEST(Encoding, GlobalConstants) { + EXPECT_EQ(12345u, test::GLOBAL_INT); + EXPECT_EQ("foobar", test::GLOBAL_TEXT.get()); + EXPECT_EQ(54321, test::GLOBAL_STRUCT->getInt32Field()); + + TestAllTypes::Reader reader = test::DERIVED_CONSTANT; + + EXPECT_EQ(12345, reader.getUInt32Field()); + EXPECT_EQ("foo", reader.getTextField()); + checkList(reader.getStructField().getTextList(), {"quux", "corge", "grault"}); + checkList(reader.getInt16List(), {11111, -11111}); + { + List::Reader listReader = reader.getStructList(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("structlist 1", listReader[0].getTextField()); + EXPECT_EQ("structlist 2", listReader[1].getTextField()); + EXPECT_EQ("structlist 3", listReader[2].getTextField()); + } +} + +TEST(Encoding, Embeds) { + { + kj::ArrayInputStream input(test::EMBEDDED_DATA); + PackedMessageReader reader(input); + checkTestMessage(reader.getRoot()); + } + +#if !CAPNP_LITE + + { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + initTestMessage(root); + kj::StringPtr text = test::EMBEDDED_TEXT; + EXPECT_EQ(kj::str(root, text.endsWith("\r\n") ? "\r\n" : "\n"), text); + } + +#endif // CAPNP_LITE + + { + checkTestMessage(test::EMBEDDED_STRUCT); + } +} + +TEST(Encoding, HasEmptyStruct) { + MallocMessageBuilder message; + auto root = message.initRoot(); + + EXPECT_EQ(1, root.totalSize().wordCount); + + EXPECT_FALSE(root.asReader().hasAnyPointerField()); + EXPECT_FALSE(root.hasAnyPointerField()); + root.getAnyPointerField().initAs(); + EXPECT_TRUE(root.asReader().hasAnyPointerField()); + EXPECT_TRUE(root.hasAnyPointerField()); + + EXPECT_EQ(1, root.totalSize().wordCount); +} + +TEST(Encoding, HasEmptyList) { + MallocMessageBuilder message; + auto root = message.initRoot(); + + EXPECT_EQ(1, root.totalSize().wordCount); + + EXPECT_FALSE(root.asReader().hasAnyPointerField()); + EXPECT_FALSE(root.hasAnyPointerField()); + root.getAnyPointerField().initAs>(0); + EXPECT_TRUE(root.asReader().hasAnyPointerField()); + EXPECT_TRUE(root.hasAnyPointerField()); + + EXPECT_EQ(1, root.totalSize().wordCount); +} + +TEST(Encoding, HasEmptyStructList) { + MallocMessageBuilder message; + auto root = message.initRoot(); + + EXPECT_EQ(1, root.totalSize().wordCount); + + EXPECT_FALSE(root.asReader().hasAnyPointerField()); + EXPECT_FALSE(root.hasAnyPointerField()); + root.getAnyPointerField().initAs>(0); + EXPECT_TRUE(root.asReader().hasAnyPointerField()); + EXPECT_TRUE(root.hasAnyPointerField()); + + EXPECT_EQ(2, root.totalSize().wordCount); +} + +TEST(Encoding, NameAnnotation) { + EXPECT_EQ(2, static_cast(test::RenamedStruct::RenamedEnum::QUX)); + EXPECT_EQ(2, static_cast(test::RenamedStruct::RenamedNestedStruct::RenamedDeeplyNestedEnum::GARPLY)); + + MallocMessageBuilder message; + auto root = message.initRoot(); + + root.setGoodFieldName(true); + EXPECT_EQ(true, root.getGoodFieldName()); + EXPECT_TRUE(root.isGoodFieldName()); + + root.setBar(0xff); + EXPECT_FALSE(root.isGoodFieldName()); + + root.setAnotherGoodFieldName(test::RenamedStruct::RenamedEnum::QUX); + EXPECT_EQ(test::RenamedStruct::RenamedEnum::QUX, root.getAnotherGoodFieldName()); + + EXPECT_FALSE(root.getRenamedUnion().isQux()); + auto quxBuilder = root.getRenamedUnion().initQux(); + EXPECT_TRUE(root.getRenamedUnion().isQux()); + EXPECT_FALSE(root.getRenamedUnion().getQux().hasAnotherGoodNestedFieldName()); + + quxBuilder.setGoodNestedFieldName(true); + EXPECT_EQ(true, quxBuilder.getGoodNestedFieldName()); + + EXPECT_FALSE(quxBuilder.hasAnotherGoodNestedFieldName()); + auto nestedFieldBuilder = quxBuilder.initAnotherGoodNestedFieldName(); + EXPECT_TRUE(quxBuilder.hasAnotherGoodNestedFieldName()); + + nestedFieldBuilder.setGoodNestedFieldName(true); + EXPECT_EQ(true, nestedFieldBuilder.getGoodNestedFieldName()); + EXPECT_FALSE(nestedFieldBuilder.hasAnotherGoodNestedFieldName()); + + EXPECT_FALSE(root.getRenamedUnion().isRenamedGroup()); + auto renamedGroupBuilder KJ_UNUSED = root.getRenamedUnion().initRenamedGroup(); + EXPECT_TRUE(root.getRenamedUnion().isRenamedGroup()); + + test::RenamedInterface::RenamedMethodParams::Reader renamedInterfaceParams; + renamedInterfaceParams.getRenamedParam(); +} + +TEST(Encoding, DefaultFloatPlusNan) { + MallocMessageBuilder message; + auto root = message.initRoot(); + + root.setFloat32Field(kj::nan()); + root.setFloat64Field(kj::nan()); + + float f = root.getFloat32Field(); + EXPECT_TRUE(f != f); + + double d = root.getFloat64Field(); + EXPECT_TRUE(d != d); +} + +TEST(Encoding, WholeFloatDefault) { + MallocMessageBuilder message; + auto root = message.initRoot(); + + EXPECT_EQ(123.0f, root.getField()); + EXPECT_EQ(2e30f, root.getBigField()); + EXPECT_EQ(456.0f, test::TestWholeFloatDefault::CONSTANT); + EXPECT_EQ(4e30f, test::TestWholeFloatDefault::BIG_CONSTANT); +} + +TEST(Encoding, Generics) { + MallocMessageBuilder message; + auto root = message.initRoot(); + auto reader = root.asReader(); + + initTestMessage(root.initBasic().initFoo()); + checkTestMessage(reader.getBasic().getFoo()); + + { + auto typed = root.getBasic(); + test::TestGenerics<>::Reader generic = typed.asGeneric<>(); + checkTestMessage(generic.getFoo().getAs()); + test::TestGenerics::Reader halfGeneric = typed.asGeneric(); + checkTestMessage(halfGeneric.getFoo()); + } + + { + auto typed = root.getBasic().asReader(); + test::TestGenerics<>::Reader generic = typed.asGeneric<>(); + checkTestMessage(generic.getFoo().getAs()); + test::TestGenerics::Reader halfGeneric = typed.asGeneric(); + checkTestMessage(halfGeneric.getFoo()); + } + + initTestMessage(root.initInner().initFoo()); + checkTestMessage(reader.getInner().getFoo()); + + { + auto typed = root.getInner(); + test::TestGenerics<>::Inner::Reader generic = typed.asTestGenericsGeneric<>(); + checkTestMessage(generic.getFoo().getAs()); + test::TestGenerics::Inner::Reader halfGeneric = typed.asTestGenericsGeneric(); + checkTestMessage(halfGeneric.getFoo()); + } + + { + auto typed = root.getInner().asReader(); + test::TestGenerics<>::Inner::Reader generic = typed.asTestGenericsGeneric<>(); + checkTestMessage(generic.getFoo().getAs()); + test::TestGenerics::Inner::Reader halfGeneric = typed.asTestGenericsGeneric(); + checkTestMessage(halfGeneric.getFoo()); + } + + root.initInner2().setBaz("foo"); + EXPECT_EQ("foo", reader.getInner2().getBaz()); + + initTestMessage(root.getInner2().initInnerBound().initFoo()); + checkTestMessage(reader.getInner2().getInnerBound().getFoo()); + + initTestMessage(root.getInner2().initInnerUnbound().getFoo().initAs()); + checkTestMessage(reader.getInner2().getInnerUnbound().getFoo().getAs()); + + initTestMessage(root.initUnspecified().getFoo().initAs()); + checkTestMessage(reader.getUnspecified().getFoo().getAs()); + + initTestMessage(root.initWrapper().initValue().initFoo()); + checkTestMessage(reader.getWrapper().getValue().getFoo()); +} + +TEST(Encoding, GenericDefaults) { + test::TestUseGenerics::Reader reader; + + EXPECT_EQ(123, reader.getDefault().getFoo().getInt16Field()); + EXPECT_EQ(123, reader.getDefaultInner().getFoo().getInt16Field()); + EXPECT_EQ("text", reader.getDefaultInner().getBar()); + EXPECT_EQ(123, reader.getDefaultUser().getBasic().getFoo().getInt16Field()); + EXPECT_EQ("text", reader.getDefaultWrapper().getValue().getFoo()); + EXPECT_EQ(321, reader.getDefaultWrapper().getValue().getRev().getFoo().getInt16Field()); + EXPECT_EQ("text", reader.getDefaultWrapper2().getValue().getValue().getFoo()); + EXPECT_EQ(321, reader.getDefaultWrapper2().getValue() + .getValue().getRev().getFoo().getInt16Field()); +} + +TEST(Encoding, UnionInGenerics) { + MallocMessageBuilder message; + auto builder = message.initRoot>(); + auto reader = builder.asReader(); + + //just call the methods to verify that generated code compiles + reader.which(); + builder.which(); + + reader.isUv(); + builder.isUv(); + reader.getUv(); + builder.getUv(); + builder.setUv(); + + builder.initUg(); + + reader.isUg(); + builder.isUg(); + reader.getUg(); + builder.getUg(); + builder.initUg(); +} + +TEST(Encoding, DefaultListBuilder) { + // At one point, this wouldn't compile. + + List::Builder(nullptr); + List::Builder(nullptr); + List>::Builder(nullptr); + List::Builder(nullptr); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/endian-fallback-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/endian-fallback-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,24 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Test that the shift-based implementation of WireValue works. +#define CAPNP_DISABLE_ENDIAN_DETECTION 1 +#include "endian-test.c++" diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/endian-reverse-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/endian-reverse-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,112 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !_MSC_VER +// (MSVC targets only little-endian platforms and so we haven't implemented any byte swapping +// intrinsics for it. So, this test would fail there.) + +// Test that the code for the opposite endianness of our CPU works. E.g. on x86 this will test +// the bswap-based code. +#define CAPNP_REVERSE_ENDIAN 1 +#include "endian.h" +#include + +namespace capnp { +namespace _ { // private +namespace { + +TEST(EndianReverse, Byte) { + byte bytes[] = {123, 45, 67, 89}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(123, vals[0].get()); + EXPECT_EQ(45, vals[1].get()); + EXPECT_EQ(67, vals[2].get()); + EXPECT_EQ(89, vals[3].get()); + + vals[0].set(21); + vals[1].set(43); + vals[2].set(65); + vals[3].set(87); + + EXPECT_EQ(21, bytes[0]); + EXPECT_EQ(43, bytes[1]); + EXPECT_EQ(65, bytes[2]); + EXPECT_EQ(87, bytes[3]); +} + +TEST(EndianReverse, TwoBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0x1234, vals[0].get()); + EXPECT_EQ(0x5678, vals[1].get()); + + vals[0].set(0x2345); + vals[1].set(0x6789); + + EXPECT_EQ(0x23, bytes[0]); + EXPECT_EQ(0x45, bytes[1]); + EXPECT_EQ(0x67, bytes[2]); + EXPECT_EQ(0x89, bytes[3]); +} + +TEST(EndianReverse, FourBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0x12345678u, vals[0].get()); + + vals[0].set(0x23456789); + + EXPECT_EQ(0x23, bytes[0]); + EXPECT_EQ(0x45, bytes[1]); + EXPECT_EQ(0x67, bytes[2]); + EXPECT_EQ(0x89, bytes[3]); +} + +TEST(EndianReverse, EightBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0x123456789abcdef0ull, vals[0].get()); + + vals[0].set(0x23456789abcdef01ull); + + EXPECT_EQ(0x23, bytes[0]); + EXPECT_EQ(0x45, bytes[1]); + EXPECT_EQ(0x67, bytes[2]); + EXPECT_EQ(0x89, bytes[3]); + EXPECT_EQ(0xab, bytes[4]); + EXPECT_EQ(0xcd, bytes[5]); + EXPECT_EQ(0xef, bytes[6]); + EXPECT_EQ(0x01, bytes[7]); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp + +#endif // !_MSC_VER diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/endian-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/endian-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,107 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "endian.h" +#include + +namespace capnp { +namespace _ { // private +namespace { + +#if CAPNP_DISABLE_ENDIAN_DETECTION +#define Endian EndianUnoptimized +#endif + +TEST(Endian, Byte) { + byte bytes[] = {123, 45, 67, 89}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(123, vals[0].get()); + EXPECT_EQ(45, vals[1].get()); + EXPECT_EQ(67, vals[2].get()); + EXPECT_EQ(89, vals[3].get()); + + vals[0].set(21); + vals[1].set(43); + vals[2].set(65); + vals[3].set(87); + + EXPECT_EQ(21, bytes[0]); + EXPECT_EQ(43, bytes[1]); + EXPECT_EQ(65, bytes[2]); + EXPECT_EQ(87, bytes[3]); +} + +TEST(Endian, TwoBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0x3412, vals[0].get()); + EXPECT_EQ(0x7856, vals[1].get()); + + vals[0].set(0x2345); + vals[1].set(0x6789); + + EXPECT_EQ(0x45, bytes[0]); + EXPECT_EQ(0x23, bytes[1]); + EXPECT_EQ(0x89, bytes[2]); + EXPECT_EQ(0x67, bytes[3]); +} + +TEST(Endian, FourBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0x78563412u, vals[0].get()); + + vals[0].set(0x23456789); + + EXPECT_EQ(0x89, bytes[0]); + EXPECT_EQ(0x67, bytes[1]); + EXPECT_EQ(0x45, bytes[2]); + EXPECT_EQ(0x23, bytes[3]); +} + +TEST(Endian, EightBytes) { + byte bytes[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; + + WireValue* vals = reinterpret_cast*>(bytes); + + EXPECT_EQ(0xf0debc9a78563412, vals[0].get()); + + vals[0].set(0x23456789abcdef01); + + EXPECT_EQ(0x01, bytes[0]); + EXPECT_EQ(0xef, bytes[1]); + EXPECT_EQ(0xcd, bytes[2]); + EXPECT_EQ(0xab, bytes[3]); + EXPECT_EQ(0x89, bytes[4]); + EXPECT_EQ(0x67, bytes[5]); + EXPECT_EQ(0x45, bytes[6]); + EXPECT_EQ(0x23, bytes[7]); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/endian.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/endian.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,309 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ENDIAN_H_ +#define CAPNP_ENDIAN_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" +#include +#include // memcpy + +namespace capnp { +namespace _ { // private + +// WireValue +// +// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the +// wire, because little-endian is the most common endianness in modern CPUs. +// +// Note: In general, code that depends cares about byte ordering is bad. See: +// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html +// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over +// allocation and layout of memory, in order to squeeze out every last drop of performance. + +#if _MSC_VER +// Assume Windows is little-endian. +// +// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or +// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC +// intrinsics. + +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ 4321 +#endif +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 1234 +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#endif + +#if CAPNP_REVERSE_ENDIAN +#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#else +#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#endif + +#if defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ + !CAPNP_DISABLE_ENDIAN_DETECTION +// CPU is little-endian. We can just read/write the memory directly. + +template +class DirectWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +using WireValue = DirectWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#elif defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ + defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION +// Big-endian, but GCC's __builtin_bswap() is available. + +// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have +// them. + +// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the +// compiler optimizes away the memcpy()s and keeps everything in registers. + +template +class SwappingWireValue; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + uint16_t swapped = (value << 8) | (value >> 8); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + value = (raw << 8) | (raw >> 8); + } + +private: + uint16_t value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t swapped = __builtin_bswap32(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap32(raw); + } + +private: + uint32_t value; +}; + +template +class SwappingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t swapped = __builtin_bswap64(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap64(raw); + } + +private: + uint64_t value; +}; + +template +using WireValue = SwappingWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#else +// Unknown endianness. Fall back to bit shifts. + +#if !CAPNP_DISABLE_ENDIAN_DETECTION +#if _MSC_VER +#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") +#pragma message("Consider changing this code to detect your platform and send us a patch!") +#else +#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." +#warning "Consider changing this code to detect your platform and send us a patch!" +#endif +#endif // !CAPNP_DISABLE_ENDIAN_DETECTION + +template +class ShiftingWireValue; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint16_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + } + +private: + union { + byte bytes[2]; + uint16_t align; + }; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8) | + (static_cast(bytes[2]) << 16) | + (static_cast(bytes[3]) << 24); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + } + +private: + union { + byte bytes[4]; + uint32_t align; + }; +}; + +template +class ShiftingWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t raw = (static_cast(bytes[0]) ) | + (static_cast(bytes[1]) << 8) | + (static_cast(bytes[2]) << 16) | + (static_cast(bytes[3]) << 24) | + (static_cast(bytes[4]) << 32) | + (static_cast(bytes[5]) << 40) | + (static_cast(bytes[6]) << 48) | + (static_cast(bytes[7]) << 56); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + bytes[4] = raw >> 32; + bytes[5] = raw >> 40; + bytes[6] = raw >> 48; + bytes[7] = raw >> 56; + } + +private: + union { + byte bytes[8]; + uint64_t align; + }; +}; + +template +using WireValue = ShiftingWireValue; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#endif + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_ENDIAN_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/ez-rpc-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/ez-rpc-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,73 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "ez-rpc.h" +#include "test-util.h" +#include + +namespace capnp { +namespace _ { +namespace { + +TEST(EzRpc, Basic) { + int callCount = 0; + EzRpcServer server(kj::heap(callCount), "localhost"); + + EzRpcClient client("localhost", server.getPort().wait(server.getWaitScope())); + + auto cap = client.getMain(); + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + + EXPECT_EQ(0, callCount); + auto response = request.send().wait(server.getWaitScope()); + EXPECT_EQ("foo", response.getX()); + EXPECT_EQ(1, callCount); +} + +TEST(EzRpc, DeprecatedNames) { + EzRpcServer server("localhost"); + int callCount = 0; + server.exportCap("cap1", kj::heap(callCount)); + server.exportCap("cap2", kj::heap()); + + EzRpcClient client("localhost", server.getPort().wait(server.getWaitScope())); + + auto cap = client.importCap("cap1"); + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + + EXPECT_EQ(0, callCount); + auto response = request.send().wait(server.getWaitScope()); + EXPECT_EQ("foo", response.getX()); + EXPECT_EQ(1, callCount); + + EXPECT_EQ(0, client.importCap("cap2").castAs() + .getCallSequenceRequest().send().wait(server.getWaitScope()).getN()); + EXPECT_EQ(1, client.importCap("cap2").castAs() + .getCallSequenceRequest().send().wait(server.getWaitScope()).getN()); +} + +} // namespace +} // namespace _ +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/ez-rpc.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/ez-rpc.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,358 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "ez-rpc.h" +#include "rpc-twoparty.h" +#include +#include +#include +#include +#include + +namespace capnp { + +KJ_THREADLOCAL_PTR(EzRpcContext) threadEzContext = nullptr; + +class EzRpcContext: public kj::Refcounted { +public: + EzRpcContext(): ioContext(kj::setupAsyncIo()) { + threadEzContext = this; + } + + ~EzRpcContext() noexcept(false) { + KJ_REQUIRE(threadEzContext == this, + "EzRpcContext destroyed from different thread than it was created.") { + return; + } + threadEzContext = nullptr; + } + + kj::WaitScope& getWaitScope() { + return ioContext.waitScope; + } + + kj::AsyncIoProvider& getIoProvider() { + return *ioContext.provider; + } + + kj::LowLevelAsyncIoProvider& getLowLevelIoProvider() { + return *ioContext.lowLevelProvider; + } + + static kj::Own getThreadLocal() { + EzRpcContext* existing = threadEzContext; + if (existing != nullptr) { + return kj::addRef(*existing); + } else { + return kj::refcounted(); + } + } + +private: + kj::AsyncIoContext ioContext; +}; + +// ======================================================================================= + +kj::Promise> connectAttach(kj::Own&& addr) { + return addr->connect().attach(kj::mv(addr)); +} + +struct EzRpcClient::Impl { + kj::Own context; + + struct ClientContext { + kj::Own stream; + TwoPartyVatNetwork network; + RpcSystem rpcSystem; + + ClientContext(kj::Own&& stream, ReaderOptions readerOpts) + : stream(kj::mv(stream)), + network(*this->stream, rpc::twoparty::Side::CLIENT, readerOpts), + rpcSystem(makeRpcClient(network)) {} + + Capability::Client getMain() { + word scratch[4]; + memset(scratch, 0, sizeof(scratch)); + MallocMessageBuilder message(scratch); + auto hostId = message.getRoot(); + hostId.setSide(rpc::twoparty::Side::SERVER); + return rpcSystem.bootstrap(hostId); + } + + Capability::Client restore(kj::StringPtr name) { + word scratch[64]; + memset(scratch, 0, sizeof(scratch)); + MallocMessageBuilder message(scratch); + + auto hostIdOrphan = message.getOrphanage().newOrphan(); + auto hostId = hostIdOrphan.get(); + hostId.setSide(rpc::twoparty::Side::SERVER); + + auto objectId = message.getRoot(); + objectId.setAs(name); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return rpcSystem.restore(hostId, objectId); +#pragma GCC diagnostic pop + } + }; + + kj::ForkedPromise setupPromise; + + kj::Maybe> clientContext; + // Filled in before `setupPromise` resolves. + + Impl(kj::StringPtr serverAddress, uint defaultPort, + ReaderOptions readerOpts) + : context(EzRpcContext::getThreadLocal()), + setupPromise(context->getIoProvider().getNetwork() + .parseAddress(serverAddress, defaultPort) + .then([](kj::Own&& addr) { + return connectAttach(kj::mv(addr)); + }).then([this, readerOpts](kj::Own&& stream) { + clientContext = kj::heap(kj::mv(stream), + readerOpts); + }).fork()) {} + + Impl(const struct sockaddr* serverAddress, uint addrSize, + ReaderOptions readerOpts) + : context(EzRpcContext::getThreadLocal()), + setupPromise( + connectAttach(context->getIoProvider().getNetwork() + .getSockaddr(serverAddress, addrSize)) + .then([this, readerOpts](kj::Own&& stream) { + clientContext = kj::heap(kj::mv(stream), + readerOpts); + }).fork()) {} + + Impl(int socketFd, ReaderOptions readerOpts) + : context(EzRpcContext::getThreadLocal()), + setupPromise(kj::Promise(kj::READY_NOW).fork()), + clientContext(kj::heap( + context->getLowLevelIoProvider().wrapSocketFd(socketFd), + readerOpts)) {} +}; + +EzRpcClient::EzRpcClient(kj::StringPtr serverAddress, uint defaultPort, ReaderOptions readerOpts) + : impl(kj::heap(serverAddress, defaultPort, readerOpts)) {} + +EzRpcClient::EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, ReaderOptions readerOpts) + : impl(kj::heap(serverAddress, addrSize, readerOpts)) {} + +EzRpcClient::EzRpcClient(int socketFd, ReaderOptions readerOpts) + : impl(kj::heap(socketFd, readerOpts)) {} + +EzRpcClient::~EzRpcClient() noexcept(false) {} + +Capability::Client EzRpcClient::getMain() { + KJ_IF_MAYBE(client, impl->clientContext) { + return client->get()->getMain(); + } else { + return impl->setupPromise.addBranch().then([this]() { + return KJ_ASSERT_NONNULL(impl->clientContext)->getMain(); + }); + } +} + +Capability::Client EzRpcClient::importCap(kj::StringPtr name) { + KJ_IF_MAYBE(client, impl->clientContext) { + return client->get()->restore(name); + } else { + return impl->setupPromise.addBranch().then(kj::mvCapture(kj::heapString(name), + [this](kj::String&& name) { + return KJ_ASSERT_NONNULL(impl->clientContext)->restore(name); + })); + } +} + +kj::WaitScope& EzRpcClient::getWaitScope() { + return impl->context->getWaitScope(); +} + +kj::AsyncIoProvider& EzRpcClient::getIoProvider() { + return impl->context->getIoProvider(); +} + +kj::LowLevelAsyncIoProvider& EzRpcClient::getLowLevelIoProvider() { + return impl->context->getLowLevelIoProvider(); +} + +// ======================================================================================= + +struct EzRpcServer::Impl final: public SturdyRefRestorer, + public kj::TaskSet::ErrorHandler { + Capability::Client mainInterface; + kj::Own context; + + struct ExportedCap { + kj::String name; + Capability::Client cap = nullptr; + + ExportedCap(kj::StringPtr name, Capability::Client cap) + : name(kj::heapString(name)), cap(cap) {} + + ExportedCap() = default; + ExportedCap(const ExportedCap&) = delete; + ExportedCap(ExportedCap&&) = default; + ExportedCap& operator=(const ExportedCap&) = delete; + ExportedCap& operator=(ExportedCap&&) = default; + // Make std::map happy... + }; + + std::map exportMap; + + kj::ForkedPromise portPromise; + + kj::TaskSet tasks; + + struct ServerContext { + kj::Own stream; + TwoPartyVatNetwork network; + RpcSystem rpcSystem; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ServerContext(kj::Own&& stream, SturdyRefRestorer& restorer, + ReaderOptions readerOpts) + : stream(kj::mv(stream)), + network(*this->stream, rpc::twoparty::Side::SERVER, readerOpts), + rpcSystem(makeRpcServer(network, restorer)) {} +#pragma GCC diagnostic pop + }; + + Impl(Capability::Client mainInterface, kj::StringPtr bindAddress, uint defaultPort, + ReaderOptions readerOpts) + : mainInterface(kj::mv(mainInterface)), + context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) { + auto paf = kj::newPromiseAndFulfiller(); + portPromise = paf.promise.fork(); + + tasks.add(context->getIoProvider().getNetwork().parseAddress(bindAddress, defaultPort) + .then(kj::mvCapture(paf.fulfiller, + [this, readerOpts](kj::Own>&& portFulfiller, + kj::Own&& addr) { + auto listener = addr->listen(); + portFulfiller->fulfill(listener->getPort()); + acceptLoop(kj::mv(listener), readerOpts); + }))); + } + + Impl(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts) + : mainInterface(kj::mv(mainInterface)), + context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) { + auto listener = context->getIoProvider().getNetwork() + .getSockaddr(bindAddress, addrSize)->listen(); + portPromise = kj::Promise(listener->getPort()).fork(); + acceptLoop(kj::mv(listener), readerOpts); + } + + Impl(Capability::Client mainInterface, int socketFd, uint port, ReaderOptions readerOpts) + : mainInterface(kj::mv(mainInterface)), + context(EzRpcContext::getThreadLocal()), + portPromise(kj::Promise(port).fork()), + tasks(*this) { + acceptLoop(context->getLowLevelIoProvider().wrapListenSocketFd(socketFd), readerOpts); + } + + void acceptLoop(kj::Own&& listener, ReaderOptions readerOpts) { + auto ptr = listener.get(); + tasks.add(ptr->accept().then(kj::mvCapture(kj::mv(listener), + [this, readerOpts](kj::Own&& listener, + kj::Own&& connection) { + acceptLoop(kj::mv(listener), readerOpts); + + auto server = kj::heap(kj::mv(connection), *this, readerOpts); + + // Arrange to destroy the server context when all references are gone, or when the + // EzRpcServer is destroyed (which will destroy the TaskSet). + tasks.add(server->network.onDisconnect().attach(kj::mv(server))); + }))); + } + + Capability::Client restore(AnyPointer::Reader objectId) override { + if (objectId.isNull()) { + return mainInterface; + } else { + auto name = objectId.getAs(); + auto iter = exportMap.find(name); + if (iter == exportMap.end()) { + KJ_FAIL_REQUIRE("Server exports no such capability.", name) { break; } + return nullptr; + } else { + return iter->second.cap; + } + } + } + + void taskFailed(kj::Exception&& exception) override { + kj::throwFatalException(kj::mv(exception)); + } +}; + +EzRpcServer::EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress, + uint defaultPort, ReaderOptions readerOpts) + : impl(kj::heap(kj::mv(mainInterface), bindAddress, defaultPort, readerOpts)) {} + +EzRpcServer::EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress, + uint addrSize, ReaderOptions readerOpts) + : impl(kj::heap(kj::mv(mainInterface), bindAddress, addrSize, readerOpts)) {} + +EzRpcServer::EzRpcServer(Capability::Client mainInterface, int socketFd, uint port, + ReaderOptions readerOpts) + : impl(kj::heap(kj::mv(mainInterface), socketFd, port, readerOpts)) {} + +EzRpcServer::EzRpcServer(kj::StringPtr bindAddress, uint defaultPort, + ReaderOptions readerOpts) + : EzRpcServer(nullptr, bindAddress, defaultPort, readerOpts) {} + +EzRpcServer::EzRpcServer(struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts) + : EzRpcServer(nullptr, bindAddress, addrSize, readerOpts) {} + +EzRpcServer::EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts) + : EzRpcServer(nullptr, socketFd, port, readerOpts) {} + +EzRpcServer::~EzRpcServer() noexcept(false) {} + +void EzRpcServer::exportCap(kj::StringPtr name, Capability::Client cap) { + Impl::ExportedCap entry(kj::heapString(name), cap); + impl->exportMap[entry.name] = kj::mv(entry); +} + +kj::Promise EzRpcServer::getPort() { + return impl->portPromise.addBranch(); +} + +kj::WaitScope& EzRpcServer::getWaitScope() { + return impl->context->getWaitScope(); +} + +kj::AsyncIoProvider& EzRpcServer::getIoProvider() { + return impl->context->getIoProvider(); +} + +kj::LowLevelAsyncIoProvider& EzRpcServer::getLowLevelIoProvider() { + return impl->context->getLowLevelIoProvider(); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/ez-rpc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/ez-rpc.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,254 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_EZ_RPC_H_ +#define CAPNP_EZ_RPC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "rpc.h" +#include "message.h" + +struct sockaddr; + +namespace kj { class AsyncIoProvider; class LowLevelAsyncIoProvider; } + +namespace capnp { + +class EzRpcContext; + +class EzRpcClient { + // Super-simple interface for setting up a Cap'n Proto RPC client. Example: + // + // # Cap'n Proto schema + // interface Adder { + // add @0 (left :Int32, right :Int32) -> (value :Int32); + // } + // + // // C++ client + // int main() { + // capnp::EzRpcClient client("localhost:3456"); + // Adder::Client adder = client.getMain(); + // auto request = adder.addRequest(); + // request.setLeft(12); + // request.setRight(34); + // auto response = request.send().wait(client.getWaitScope()); + // assert(response.getValue() == 46); + // return 0; + // } + // + // // C++ server + // class AdderImpl final: public Adder::Server { + // public: + // kj::Promise add(AddContext context) override { + // auto params = context.getParams(); + // context.getResults().setValue(params.getLeft() + params.getRight()); + // return kj::READY_NOW; + // } + // }; + // + // int main() { + // capnp::EzRpcServer server(kj::heap(), "*:3456"); + // kj::NEVER_DONE.wait(server.getWaitScope()); + // } + // + // This interface is easy, but it hides a lot of useful features available from the lower-level + // classes: + // - The server can only export a small set of public, singleton capabilities under well-known + // string names. This is fine for transient services where no state needs to be kept between + // connections, but hides the power of Cap'n Proto when it comes to long-lived resources. + // - EzRpcClient/EzRpcServer automatically set up a `kj::EventLoop` and make it current for the + // thread. Only one `kj::EventLoop` can exist per thread, so you cannot use these interfaces + // if you wish to set up your own event loop. (However, you can safely create multiple + // EzRpcClient / EzRpcServer objects in a single thread; they will make sure to make no more + // than one EventLoop.) + // - These classes only support simple two-party connections, not multilateral VatNetworks. + // - These classes only support communication over a raw, unencrypted socket. If you want to + // build on an abstract stream (perhaps one which supports encryption), you must use the + // lower-level interfaces. + // + // Some of these restrictions will probably be lifted in future versions, but some things will + // always require using the low-level interfaces directly. If you are interested in working + // at a lower level, start by looking at these interfaces: + // - `kj::setupAsyncIo()` in `kj/async-io.h`. + // - `RpcSystem` in `capnp/rpc.h`. + // - `TwoPartyVatNetwork` in `capnp/rpc-twoparty.h`. + +public: + explicit EzRpcClient(kj::StringPtr serverAddress, uint defaultPort = 0, + ReaderOptions readerOpts = ReaderOptions()); + // Construct a new EzRpcClient and connect to the given address. The connection is formed in + // the background -- if it fails, calls to capabilities returned by importCap() will fail with an + // appropriate exception. + // + // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. + // If unspecified, the port is required in `serverAddress`. + // + // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info + // on the address format, but basically it's what you'd expect. + // + // `readerOpts` is the ReaderOptions structure used to read each incoming message on the + // connection. Setting this may be necessary if you need to receive very large individual + // messages or messages. However, it is recommended that you instead think about how to change + // your protocol to send large data blobs in multiple small chunks -- this is much better for + // both security and performance. See `ReaderOptions` in `message.h` for more details. + + EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()); + // Like the above constructor, but connects to an already-resolved socket address. Any address + // format supported by `kj::Network` in `kj/async-io.h` is accepted. + + explicit EzRpcClient(int socketFd, ReaderOptions readerOpts = ReaderOptions()); + // Create a client on top of an already-connected socket. + // `readerOpts` acts as in the first constructor. + + ~EzRpcClient() noexcept(false); + + template + typename Type::Client getMain(); + Capability::Client getMain(); + // Get the server's main (aka "bootstrap") interface. + + template + typename Type::Client importCap(kj::StringPtr name) + KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); + Capability::Client importCap(kj::StringPtr name) + KJ_DEPRECATED("Change your server to export a main interface, then use getMain() instead."); + // ** DEPRECATED ** + // + // Ask the sever for the capability with the given name. You may specify a type to automatically + // down-cast to that type. It is up to you to specify the correct expected type. + // + // Named interfaces are deprecated. The new preferred usage pattern is for the server to export + // a "main" interface which itself has methods for getting any other interfaces. + + kj::WaitScope& getWaitScope(); + // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on + // promises. + + kj::AsyncIoProvider& getIoProvider(); + // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want + // to do some non-RPC I/O in asynchronous fashion. + + kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); + // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you + // want to do some non-RPC I/O in asynchronous fashion. + +private: + struct Impl; + kj::Own impl; +}; + +class EzRpcServer { + // The server counterpart to `EzRpcClient`. See `EzRpcClient` for an example. + +public: + explicit EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress, + uint defaultPort = 0, ReaderOptions readerOpts = ReaderOptions()); + // Construct a new `EzRpcServer` that binds to the given address. An address of "*" means to + // bind to all local addresses. + // + // `defaultPort` is the IP port number to use if `serverAddress` does not include it explicitly. + // If unspecified, a port is chosen automatically, and you must call getPort() to find out what + // it is. + // + // The address is parsed by `kj::Network` in `kj/async-io.h`. See that interface for more info + // on the address format, but basically it's what you'd expect. + // + // The server might not begin listening immediately, especially if `bindAddress` needs to be + // resolved. If you need to wait until the server is definitely up, wait on the promise returned + // by `getPort()`. + // + // `readerOpts` is the ReaderOptions structure used to read each incoming message on the + // connection. Setting this may be necessary if you need to receive very large individual + // messages or messages. However, it is recommended that you instead think about how to change + // your protocol to send large data blobs in multiple small chunks -- this is much better for + // both security and performance. See `ReaderOptions` in `message.h` for more details. + + EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()); + // Like the above constructor, but binds to an already-resolved socket address. Any address + // format supported by `kj::Network` in `kj/async-io.h` is accepted. + + EzRpcServer(Capability::Client mainInterface, int socketFd, uint port, + ReaderOptions readerOpts = ReaderOptions()); + // Create a server on top of an already-listening socket (i.e. one on which accept() may be + // called). `port` is returned by `getPort()` -- it serves no other purpose. + // `readerOpts` acts as in the other two above constructors. + + explicit EzRpcServer(kj::StringPtr bindAddress, uint defaultPort = 0, + ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + EzRpcServer(struct sockaddr* bindAddress, uint addrSize, + ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts = ReaderOptions()) + KJ_DEPRECATED("Please specify a main interface for your server."); + + ~EzRpcServer() noexcept(false); + + void exportCap(kj::StringPtr name, Capability::Client cap); + // Export a capability publicly under the given name, so that clients can import it. + // + // Keep in mind that you can implicitly convert `kj::Own&&` to + // `Capability::Client`, so it's typical to pass something like + // `kj::heap()` as the second parameter. + + kj::Promise getPort(); + // Get the IP port number on which this server is listening. This promise won't resolve until + // the server is actually listening. If the address was not an IP address (e.g. it was a Unix + // domain socket) then getPort() resolves to zero. + + kj::WaitScope& getWaitScope(); + // Get the `WaitScope` for the client's `EventLoop`, which allows you to synchronously wait on + // promises. + + kj::AsyncIoProvider& getIoProvider(); + // Get the underlying AsyncIoProvider set up by the RPC system. This is useful if you want + // to do some non-RPC I/O in asynchronous fashion. + + kj::LowLevelAsyncIoProvider& getLowLevelIoProvider(); + // Get the underlying LowLevelAsyncIoProvider set up by the RPC system. This is useful if you + // want to do some non-RPC I/O in asynchronous fashion. + +private: + struct Impl; + kj::Own impl; +}; + +// ======================================================================================= +// inline implementation details + +template +inline typename Type::Client EzRpcClient::getMain() { + return getMain().castAs(); +} + +template +inline typename Type::Client EzRpcClient::importCap(kj::StringPtr name) { + return importCap(name).castAs(); +} + +} // namespace capnp + +#endif // CAPNP_EZ_RPC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/fuzz-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/fuzz-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,286 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include "message.h" +#include "serialize.h" +#include +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +bool skipFuzzTest() { + if (getenv("CAPNP_SKIP_FUZZ_TEST") != nullptr) { + KJ_LOG(WARNING, "Skipping test because CAPNP_SKIP_FUZZ_TEST is set in environment."); + return true; + } else { + return false; + } +} + +class DisableStackTraces: public kj::ExceptionCallback { + // This test generates a lot of exceptions. Performing a backtrace on each one can be slow, + // especially on Windows (where it is very, very slow). So, disable them. + +public: + StackTraceMode stackTraceMode() override { + return StackTraceMode::NONE; + } +}; + +uint64_t traverse(AnyPointer::Reader reader); +uint64_t traverse(AnyStruct::Reader reader); +uint64_t traverse(AnyList::Reader reader); + +template +uint64_t traverseList(ListType list) { + // Traverse in reverse order in order to trigger segfaults before exceptions if we go + // out-of-bounds. + + uint64_t result = 0; + for (size_t i = list.size(); i != 0; i--) { + result += traverse(list[i-1]); + } + return result; +} + +uint64_t traverse(AnyStruct::Reader reader) { + uint64_t result = 0; + for (byte b: reader.getDataSection()) { + result += b; + } + result += traverseList(reader.getPointerSection()); + return result; +} + +uint64_t traverse(AnyList::Reader reader) { + uint64_t result = 0; + switch (reader.getElementSize()) { + case ElementSize::VOID: break; + case ElementSize::BIT: for (auto e: reader.as>()) result += e; break; + case ElementSize::BYTE: for (auto e: reader.as>()) result += e; break; + case ElementSize::TWO_BYTES: for (auto e: reader.as>()) result += e; break; + case ElementSize::FOUR_BYTES: for (auto e: reader.as>()) result += e; break; + case ElementSize::EIGHT_BYTES: for (auto e: reader.as>()) result += e; break; + case ElementSize::POINTER: + traverseList(reader.as>()); + break; + case ElementSize::INLINE_COMPOSITE: + traverseList(reader.as>()); + break; + } + return result; +} + +uint64_t traverse(AnyPointer::Reader reader) { + if (reader.isStruct()) { + return traverse(reader.getAs()); + } else if (reader.isList()) { + return traverse(reader.getAs()); + } else { + return 0; + } +} + +template +void traverseCatchingExceptions(kj::ArrayPtr data) { + // Try traversing through Checker. + kj::runCatchingExceptions([&]() { + FlatArrayMessageReader reader(data); + KJ_ASSERT(Checker::check(reader) != 0) { break; } + }); + + // Try traversing through AnyPointer. + kj::runCatchingExceptions([&]() { + FlatArrayMessageReader reader(data); + KJ_ASSERT(traverse(reader.getRoot()) != 0) { break; } + }); + + // Try counting the size.. + kj::runCatchingExceptions([&]() { + FlatArrayMessageReader reader(data); + KJ_ASSERT(reader.getRoot().targetSize().wordCount != 0) { break; } + }); + + // Try copying into a builder, and if that works, traversing it with Checker. + static word buffer[8192]; + kj::runCatchingExceptions([&]() { + FlatArrayMessageReader reader(data); + MallocMessageBuilder copyBuilder(buffer); + copyBuilder.setRoot(reader.getRoot()); + KJ_ASSERT(Checker::check(copyBuilder) != 0) { break; } + }); +} + +template +void fuzz(kj::ArrayPtr data, uint flipCount, uint startAt, uint endAt) { + if (flipCount == 0) { + traverseCatchingExceptions(data); + } else { + for (uint i = startAt; i < endAt; i++) { + byte bit = 1u << (i % 8); + byte old = data.asBytes()[i / 8]; + data.asBytes()[i / 8] |= bit; + fuzz(data, flipCount - 1, i + 1, endAt); + data.asBytes()[i / 8] &= ~bit; + fuzz(data, flipCount - 1, i + 1, endAt); + data.asBytes()[i / 8] = bit; + fuzz(data, flipCount - 1, i + 1, endAt); + data.asBytes()[i / 8] = old; + } + } +} + +struct StructChecker { + template + static uint check(ReaderOrBuilder& message) { + uint result = 0; + for (auto c: message.template getRoot().getTextField()) { + result += c; + } + return result; + } +}; + +KJ_TEST("fuzz-test struct pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder; + builder.getRoot().setTextField("foo"); + KJ_ASSERT(builder.getSegmentsForOutput().size() == 1); + fuzz(messageToFlatArray(builder), 2, 64, 192); +} + +struct ListChecker { + template + static uint check(ReaderOrBuilder& message) { + uint result = 0; + for (auto e: message.template getRoot>()) { + result += e; + } + return result; + } +}; + +KJ_TEST("fuzz-test list pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder; + auto list = builder.getRoot().initAs>(2); + list.set(0, 12345); + list.set(1, 67890); + fuzz(messageToFlatArray(builder), 2, 64, 192); +} + +struct StructListChecker { + template + static uint check(ReaderOrBuilder& message) { + uint result = 0; + auto l = message.template getRoot>(); + for (size_t i = l.size(); i > 0; i--) { + for (auto c: l[i-1].getTextField()) { + result += c; + } + } + return result; + } +}; + +KJ_TEST("fuzz-test struct list pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder; + auto list = builder.getRoot().initAs>(2); + list[0].setTextField("foo"); + list[1].setTextField("bar"); + KJ_ASSERT(builder.getSegmentsForOutput().size() == 1); + + fuzz(messageToFlatArray(builder), 2, 64, 192); +} + +struct TextChecker { + template + static uint check(ReaderOrBuilder& message) { + uint result = 0; + for (auto c: message.template getRoot()) { + result += c; + } + return result; + } +}; + +KJ_TEST("fuzz-test text pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder; + builder.template getRoot().setAs("foo"); + fuzz(messageToFlatArray(builder), 2, 64, 192); +} + +KJ_TEST("fuzz-test far pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE); + initTestMessage(builder.getRoot()); + + uint segmentCount = builder.getSegmentsForOutput().size(); + uint tableSize = segmentCount / 2 + 1; + + // Fuzz the root far pointer plus its landing pad, which should be in the next word. + fuzz(messageToFlatArray(builder), 2, tableSize * 64, tableSize * 64 + 128); +} + +KJ_TEST("fuzz-test double-far pointer") { + if (skipFuzzTest()) return; + DisableStackTraces disableStackTraces; + + MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE); + + // Carefully arrange for a double-far pointer to be created. + auto root = builder.getRoot(); + root.adopt(builder.getOrphanage().newOrphanCopy(Text::Reader("foo"))); + + // Verify that did what we expected. + KJ_ASSERT(builder.getSegmentsForOutput().size() == 3); + KJ_ASSERT(builder.getSegmentsForOutput()[0].size() == 1); // root pointer + KJ_ASSERT(builder.getSegmentsForOutput()[1].size() == 1); // "foo" + KJ_ASSERT(builder.getSegmentsForOutput()[2].size() == 2); // double-far landing pad + + // Fuzz the root far pointer. + fuzz(messageToFlatArray(builder), 2, 64, 128); + + // Fuzz the landing pad. + fuzz(messageToFlatArray(builder), 2, 192, 320); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/generated-header-support.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/generated-header-support.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,407 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file is included from all generated headers. + +#ifndef CAPNP_GENERATED_HEADER_SUPPORT_H_ +#define CAPNP_GENERATED_HEADER_SUPPORT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "raw-schema.h" +#include "layout.h" +#include "list.h" +#include "orphan.h" +#include "pointer-helpers.h" +#include "any.h" +#include +#include + +namespace capnp { + +class MessageBuilder; // So that it can be declared a friend. + +template +struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend. + +struct DynamicStruct; // So that it can be declared a friend. + +struct Capability; // To declare brandBindingFor() + +namespace _ { // private + +#if !CAPNP_LITE + +template +inline const RawSchema& rawSchema() { + return *CapnpPrivate::schema; +} +template ::typeId> +inline const RawSchema& rawSchema() { + return *schemas::EnumInfo::schema; +} + +template +inline const RawBrandedSchema& rawBrandedSchema() { + return *CapnpPrivate::brand(); +} +template ::typeId> +inline const RawBrandedSchema& rawBrandedSchema() { + return schemas::EnumInfo::schema->defaultBrand; +} + +template +struct ChooseBrand; +// If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a +// specific brand instance. TypeTag is the _capnpPrivate struct for the type in question. + +template +struct ChooseBrand { + // All params were AnyPointer. No specific brand needed. + static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; } +}; + +template +struct ChooseBrand: public ChooseBrand {}; +// The first parameter is AnyPointer, so recurse to check the rest. + +template +struct ChooseBrand { + // At least one parameter is not AnyPointer, so use the specificBrand constant. + static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::specificBrand; } +}; + +template ()> +struct BrandBindingFor_; + +#define HANDLE_TYPE(Type, which) \ + template <> \ + struct BrandBindingFor_ { \ + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \ + return { which, listDepth, nullptr }; \ + } \ + } +HANDLE_TYPE(Void, 0); +HANDLE_TYPE(bool, 1); +HANDLE_TYPE(int8_t, 2); +HANDLE_TYPE(int16_t, 3); +HANDLE_TYPE(int32_t, 4); +HANDLE_TYPE(int64_t, 5); +HANDLE_TYPE(uint8_t, 6); +HANDLE_TYPE(uint16_t, 7); +HANDLE_TYPE(uint32_t, 8); +HANDLE_TYPE(uint64_t, 9); +HANDLE_TYPE(float, 10); +HANDLE_TYPE(double, 11); +#undef HANDLE_TYPE + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 12, listDepth, nullptr }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 13, listDepth, nullptr }; + } +}; + +template +struct BrandBindingFor_, Kind::LIST> { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return BrandBindingFor_::get(listDepth + 1); + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 15, listDepth, nullptr }; + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 16, listDepth, T::_capnpPrivate::brand() }; + } +}; + +template +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 17, listDepth, T::_capnpPrivate::brand() }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 0 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 1 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 2 }; + } +}; + +template <> +struct BrandBindingFor_ { + static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { + return { 18, listDepth, 0, 3 }; + } +}; + +template +constexpr RawBrandedSchema::Binding brandBindingFor() { + return BrandBindingFor_::get(0); +} + +kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema); +kj::String enumString(uint16_t value, const RawBrandedSchema& schema); +// 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 +inline kj::StringTree structString(StructReader reader) { + return structString(reader, rawBrandedSchema()); +} +template +inline kj::String enumString(T value) { + return enumString(static_cast(value), rawBrandedSchema()); +} + +#endif // !CAPNP_LITE + +// TODO(cleanup): Unify ConstStruct and ConstList. +template +class ConstStruct { +public: + ConstStruct() = delete; + KJ_DISALLOW_COPY(ConstStruct); + inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {} + + inline typename T::Reader get() const { + return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs(); + } + + inline operator typename T::Reader() const { return get(); } + inline typename T::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +class ConstList { +public: + ConstList() = delete; + KJ_DISALLOW_COPY(ConstList); + inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {} + + inline typename List::Reader get() const { + return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs>(); + } + + inline operator typename List::Reader() const { return get(); } + inline typename List::Reader operator*() const { return get(); } + inline TemporaryPointer::Reader> operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +class ConstText { +public: + ConstText() = delete; + KJ_DISALLOW_COPY(ConstText); + inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {} + + inline Text::Reader get() const { + return Text::Reader(reinterpret_cast(ptr), size); + } + + inline operator Text::Reader() const { return get(); } + inline Text::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + + inline kj::StringPtr toString() const { + return get(); + } + +private: + const word* ptr; +}; + +template +inline kj::StringPtr KJ_STRINGIFY(const ConstText& s) { + return s.get(); +} + +template +class ConstData { +public: + ConstData() = delete; + KJ_DISALLOW_COPY(ConstData); + inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {} + + inline Data::Reader get() const { + return Data::Reader(reinterpret_cast(ptr), size); + } + + inline operator Data::Reader() const { return get(); } + inline Data::Reader operator*() const { return get(); } + inline TemporaryPointer operator->() const { return get(); } + +private: + const word* ptr; +}; + +template +inline auto KJ_STRINGIFY(const ConstData& s) -> decltype(kj::toCharSequence(s.get())) { + return kj::toCharSequence(s.get()); +} + +} // namespace _ (private) + +template +inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; } +template ::typeId> +inline constexpr uint64_t typeId() { return id; } +// typeId() returns the type ID as defined in the schema. Works with structs, enums, and +// interfaces. + +template +inline constexpr uint sizeInWords() { + // Return the size, in words, of a Struct type, if allocated free-standing (not in a list). + // May be useful for pre-computing space needed in order to precisely allocate messages. + + return unbound((upgradeBound(_::structSize().data) + + _::structSize().pointers * WORDS_PER_POINTER) / WORDS); +} + +} // namespace capnp + +#if _MSC_VER +// MSVC doesn't understand floating-point constexpr yet. +// +// TODO(msvc): Remove this hack when MSVC is fixed. +#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) +#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value +#else +#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value +#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) +#endif + +#if _MSC_VER +// TODO(msvc): A little hack to allow MSVC to use C++14 return type deduction in cases where the +// explicit type exposes bugs in the compiler. +#define CAPNP_AUTO_IF_MSVC(...) auto +#else +#define CAPNP_AUTO_IF_MSVC(...) __VA_ARGS__ +#endif + +#if CAPNP_LITE + +#define CAPNP_DECLARE_SCHEMA(id) \ + extern ::capnp::word const* const bp_##id + +#define CAPNP_DECLARE_ENUM(type, id) \ + inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ + return ::kj::str(static_cast(value)); \ + } \ + template <> struct EnumInfo { \ + struct IsEnum; \ + static constexpr uint64_t typeId = 0x##id; \ + static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ + } + +#if _MSC_VER +// TODO(msvc): MSVC dosen't expect constexprs to have definitions. +#define CAPNP_DEFINE_ENUM(type, id) +#else +#define CAPNP_DEFINE_ENUM(type, id) \ + constexpr uint64_t EnumInfo::typeId +#endif + +#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ + struct IsStruct; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr uint16_t dataWordSize = dataWordSize_; \ + static constexpr uint16_t pointerCount = pointerCount_; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } + +#else // CAPNP_LITE + +#define CAPNP_DECLARE_SCHEMA(id) \ + extern ::capnp::word const* const bp_##id; \ + extern const ::capnp::_::RawSchema s_##id + +#define CAPNP_DECLARE_ENUM(type, id) \ + inline ::kj::String KJ_STRINGIFY(type##_##id value) { \ + return ::capnp::_::enumString(value); \ + } \ + template <> struct EnumInfo { \ + struct IsEnum; \ + static constexpr uint64_t typeId = 0x##id; \ + static inline ::capnp::word const* encodedSchema() { return bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \ + } +#define CAPNP_DEFINE_ENUM(type, id) \ + constexpr uint64_t EnumInfo::typeId; \ + constexpr ::capnp::_::RawSchema const* EnumInfo::schema + +#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \ + struct IsStruct; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \ + static constexpr uint16_t dataWordSize = dataWordSize_; \ + static constexpr uint16_t pointerCount = pointerCount_; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; + +#define CAPNP_DECLARE_INTERFACE_HEADER(id) \ + struct IsInterface; \ + static constexpr uint64_t typeId = 0x##id; \ + static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \ + static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \ + static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; + +#endif // CAPNP_LITE, else + +#endif // CAPNP_GENERATED_HEADER_SUPPORT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/layout-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/layout-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,414 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE +#include "layout.h" +#include "message.h" +#include "arena.h" +#include + +#if CAPNP_DEBUG_TYPES +namespace kj { + template + String KJ_STRINGIFY(kj::Quantity value) { + return kj::str(unboundAs(value / kj::unit>())); + } + + // Hack: Allow direct comparisons and multiplications so that we don't have to rewrite the code + // below. + template + inline constexpr Bounded<65535, T> operator*(uint a, Bounded b) { + return assumeBits<16>(a * unbound(b)); + } + template + inline constexpr Bounded<65535, uint> operator*(uint a, BoundedConst) { + return assumeBits<16>(a * b); + } +} +#endif + +namespace capnp { +namespace _ { // private +namespace { + +TEST(WireFormat, SimpleRawDataStruct) { + AlignedData<2> data = {{ + // Struct ref, offset = 1, dataSize = 1, pointerCount = 0 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + // Content for the data section. + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef + }}; + + StructReader reader = PointerReader::getRootUnchecked(data.words).getStruct(nullptr); + + EXPECT_EQ(0xefcdab8967452301ull, reader.getDataField(0 * ELEMENTS)); + EXPECT_EQ(0u, reader.getDataField(1 * ELEMENTS)); + EXPECT_EQ(0x67452301u, reader.getDataField(0 * ELEMENTS)); + EXPECT_EQ(0xefcdab89u, reader.getDataField(1 * ELEMENTS)); + EXPECT_EQ(0u, reader.getDataField(2 * ELEMENTS)); + EXPECT_EQ(0x2301u, reader.getDataField(0 * ELEMENTS)); + EXPECT_EQ(0x6745u, reader.getDataField(1 * ELEMENTS)); + EXPECT_EQ(0xab89u, reader.getDataField(2 * ELEMENTS)); + EXPECT_EQ(0xefcdu, reader.getDataField(3 * ELEMENTS)); + EXPECT_EQ(0u, reader.getDataField(4 * ELEMENTS)); + + EXPECT_EQ(321u ^ 0xefcdab8967452301ull, reader.getDataField(0 * ELEMENTS, 321u)); + EXPECT_EQ(321u ^ 0x67452301u, reader.getDataField(0 * ELEMENTS, 321u)); + EXPECT_EQ(321u ^ 0x2301u, reader.getDataField(0 * ELEMENTS, 321u)); + EXPECT_EQ(321u, reader.getDataField(1 * ELEMENTS, 321u)); + EXPECT_EQ(321u, reader.getDataField(2 * ELEMENTS, 321u)); + EXPECT_EQ(321u, reader.getDataField(4 * ELEMENTS, 321u)); + + // Bits + EXPECT_TRUE (reader.getDataField(0 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(1 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(2 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(3 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(4 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(5 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(6 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(7 * ELEMENTS)); + + EXPECT_TRUE (reader.getDataField( 8 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField( 9 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(10 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(11 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(12 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField(13 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(14 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(15 * ELEMENTS)); + + EXPECT_TRUE (reader.getDataField(63 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(64 * ELEMENTS)); + + EXPECT_TRUE (reader.getDataField(0 * ELEMENTS, false)); + EXPECT_FALSE(reader.getDataField(1 * ELEMENTS, false)); + EXPECT_TRUE (reader.getDataField(63 * ELEMENTS, false)); + EXPECT_FALSE(reader.getDataField(64 * ELEMENTS, false)); + EXPECT_FALSE(reader.getDataField(0 * ELEMENTS, true)); + EXPECT_TRUE (reader.getDataField(1 * ELEMENTS, true)); + EXPECT_FALSE(reader.getDataField(63 * ELEMENTS, true)); + EXPECT_TRUE (reader.getDataField(64 * ELEMENTS, true)); +} + +static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; +static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT = + {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; + +static constexpr StructSize STRUCTLIST_ELEMENT_SIZE(1 * WORDS, 1 * POINTERS); + +static void setupStruct(StructBuilder builder) { + builder.setDataField(0 * ELEMENTS, 0x1011121314151617ull); + builder.setDataField(2 * ELEMENTS, 0x20212223u); + builder.setDataField(6 * ELEMENTS, 0x3031u); + builder.setDataField(14 * ELEMENTS, 0x40u); + builder.setDataField(120 * ELEMENTS, false); + builder.setDataField(121 * ELEMENTS, false); + builder.setDataField(122 * ELEMENTS, true); + builder.setDataField(123 * ELEMENTS, false); + builder.setDataField(124 * ELEMENTS, true); + builder.setDataField(125 * ELEMENTS, true); + builder.setDataField(126 * ELEMENTS, true); + builder.setDataField(127 * ELEMENTS, false); + + { + StructBuilder subStruct = builder.getPointerField(0 * POINTERS).initStruct( + StructSize(1 * WORDS, 0 * POINTERS)); + subStruct.setDataField(0 * ELEMENTS, 123); + } + + { + ListBuilder list = builder.getPointerField(1 * POINTERS) + .initList(ElementSize::FOUR_BYTES, 3 * ELEMENTS); + EXPECT_EQ(3 * ELEMENTS, list.size()); + list.setDataElement(0 * ELEMENTS, 200); + list.setDataElement(1 * ELEMENTS, 201); + list.setDataElement(2 * ELEMENTS, 202); + } + + { + ListBuilder list = builder.getPointerField(2 * POINTERS).initStructList( + 4 * ELEMENTS, STRUCTLIST_ELEMENT_SIZE); + EXPECT_EQ(4 * ELEMENTS, list.size()); + for (int i = 0; i < 4; i++) { + StructBuilder element = list.getStructElement(i * ELEMENTS); + element.setDataField(0 * ELEMENTS, 300 + i); + element.getPointerField(0 * POINTERS) + .initStruct(StructSize(1 * WORDS, 0 * POINTERS)) + .setDataField(0 * ELEMENTS, 400 + i); + } + } + + { + ListBuilder list = builder.getPointerField(3 * POINTERS) + .initList(ElementSize::POINTER, 5 * ELEMENTS); + EXPECT_EQ(5 * ELEMENTS, list.size()); + for (uint i = 0; i < 5; i++) { + ListBuilder element = list.getPointerElement(i * ELEMENTS) + .initList(ElementSize::TWO_BYTES, (i + 1) * ELEMENTS); + EXPECT_EQ((i + 1) * ELEMENTS, element.size()); + for (uint j = 0; j <= i; j++) { + element.setDataElement(j * ELEMENTS, 500 + j); + } + } + } +} + +static void checkStruct(StructBuilder builder) { + EXPECT_EQ(0x1011121314151617ull, builder.getDataField(0 * ELEMENTS)); + EXPECT_EQ(0x20212223u, builder.getDataField(2 * ELEMENTS)); + EXPECT_EQ(0x3031u, builder.getDataField(6 * ELEMENTS)); + EXPECT_EQ(0x40u, builder.getDataField(14 * ELEMENTS)); + EXPECT_FALSE(builder.getDataField(120 * ELEMENTS)); + EXPECT_FALSE(builder.getDataField(121 * ELEMENTS)); + EXPECT_TRUE (builder.getDataField(122 * ELEMENTS)); + EXPECT_FALSE(builder.getDataField(123 * ELEMENTS)); + EXPECT_TRUE (builder.getDataField(124 * ELEMENTS)); + EXPECT_TRUE (builder.getDataField(125 * ELEMENTS)); + EXPECT_TRUE (builder.getDataField(126 * ELEMENTS)); + EXPECT_FALSE(builder.getDataField(127 * ELEMENTS)); + + { + StructBuilder subStruct = builder.getPointerField(0 * POINTERS).getStruct( + StructSize(1 * WORDS, 0 * POINTERS), SUBSTRUCT_DEFAULT.words); + EXPECT_EQ(123u, subStruct.getDataField(0 * ELEMENTS)); + } + + { + ListBuilder list = builder.getPointerField(1 * POINTERS) + .getList(ElementSize::FOUR_BYTES, nullptr); + ASSERT_EQ(3 * ELEMENTS, list.size()); + EXPECT_EQ(200, list.getDataElement(0 * ELEMENTS)); + EXPECT_EQ(201, list.getDataElement(1 * ELEMENTS)); + EXPECT_EQ(202, list.getDataElement(2 * ELEMENTS)); + } + + { + ListBuilder list = builder.getPointerField(2 * POINTERS) + .getStructList(STRUCTLIST_ELEMENT_SIZE, nullptr); + ASSERT_EQ(4 * ELEMENTS, list.size()); + for (int i = 0; i < 4; i++) { + StructBuilder element = list.getStructElement(i * ELEMENTS); + EXPECT_EQ(300 + i, element.getDataField(0 * ELEMENTS)); + EXPECT_EQ(400 + i, + element.getPointerField(0 * POINTERS) + .getStruct(StructSize(1 * WORDS, 0 * POINTERS), + STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) + .getDataField(0 * ELEMENTS)); + } + } + + { + ListBuilder list = builder.getPointerField(3 * POINTERS).getList(ElementSize::POINTER, nullptr); + ASSERT_EQ(5 * ELEMENTS, list.size()); + for (uint i = 0; i < 5; i++) { + ListBuilder element = list.getPointerElement(i * ELEMENTS) + .getList(ElementSize::TWO_BYTES, nullptr); + ASSERT_EQ((i + 1) * ELEMENTS, element.size()); + for (uint j = 0; j <= i; j++) { + EXPECT_EQ(500u + j, element.getDataElement(j * ELEMENTS)); + } + } + } +} + +static void checkStruct(StructReader reader) { + EXPECT_EQ(0x1011121314151617ull, reader.getDataField(0 * ELEMENTS)); + EXPECT_EQ(0x20212223u, reader.getDataField(2 * ELEMENTS)); + EXPECT_EQ(0x3031u, reader.getDataField(6 * ELEMENTS)); + EXPECT_EQ(0x40u, reader.getDataField(14 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(120 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(121 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField(122 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(123 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField(124 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField(125 * ELEMENTS)); + EXPECT_TRUE (reader.getDataField(126 * ELEMENTS)); + EXPECT_FALSE(reader.getDataField(127 * ELEMENTS)); + + { + StructReader subStruct = reader.getPointerField(0 * POINTERS) + .getStruct(SUBSTRUCT_DEFAULT.words); + EXPECT_EQ(123u, subStruct.getDataField(0 * ELEMENTS)); + } + + { + ListReader list = reader.getPointerField(1 * POINTERS).getList(ElementSize::FOUR_BYTES, nullptr); + ASSERT_EQ(3 * ELEMENTS, list.size()); + EXPECT_EQ(200, list.getDataElement(0 * ELEMENTS)); + EXPECT_EQ(201, list.getDataElement(1 * ELEMENTS)); + EXPECT_EQ(202, list.getDataElement(2 * ELEMENTS)); + } + + { + ListReader list = reader.getPointerField(2 * POINTERS) + .getList(ElementSize::INLINE_COMPOSITE, nullptr); + ASSERT_EQ(4 * ELEMENTS, list.size()); + for (int i = 0; i < 4; i++) { + StructReader element = list.getStructElement(i * ELEMENTS); + EXPECT_EQ(300 + i, element.getDataField(0 * ELEMENTS)); + EXPECT_EQ(400 + i, + element.getPointerField(0 * POINTERS) + .getStruct(STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) + .getDataField(0 * ELEMENTS)); + } + } + + { + ListReader list = reader.getPointerField(3 * POINTERS).getList(ElementSize::POINTER, nullptr); + ASSERT_EQ(5 * ELEMENTS, list.size()); + for (uint i = 0; i < 5; i++) { + ListReader element = list.getPointerElement(i * ELEMENTS) + .getList(ElementSize::TWO_BYTES, nullptr); + ASSERT_EQ((i + 1) * ELEMENTS, element.size()); + for (uint j = 0; j <= i; j++) { + EXPECT_EQ(500u + j, element.getDataElement(j * ELEMENTS)); + } + } + } +} + +TEST(WireFormat, StructRoundTrip_OneSegment) { + MallocMessageBuilder message; + BuilderArena arena(&message); + auto allocation = arena.allocate(1 * WORDS); + SegmentBuilder* segment = allocation.segment; + word* rootLocation = allocation.words; + + StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) + .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); + setupStruct(builder); + + // word count: + // 1 root pointer + // 6 root struct + // 1 sub message + // 2 3-element int32 list + // 13 struct list + // 1 tag + // 12 4x struct + // 1 data section + // 1 pointer section + // 1 sub-struct + // 11 list list + // 5 pointers to sub-lists + // 6 sub-lists (4x 1 word, 1x 2 words) + // ----- + // 34 + kj::ArrayPtr> segments = arena.getSegmentsForOutput(); + ASSERT_EQ(1u, segments.size()); + EXPECT_EQ(34u, segments[0].size()); + + checkStruct(builder); + checkStruct(builder.asReader()); + checkStruct(PointerReader::getRootUnchecked(segment->getStartPtr()).getStruct(nullptr)); + checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) + .getStruct(nullptr)); +} + +TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { + MallocMessageBuilder message(0, AllocationStrategy::FIXED_SIZE); + BuilderArena arena(&message); + auto allocation = arena.allocate(1 * WORDS); + SegmentBuilder* segment = allocation.segment; + word* rootLocation = allocation.words; + + StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) + .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); + setupStruct(builder); + + // Verify that we made 15 segments. + kj::ArrayPtr> segments = arena.getSegmentsForOutput(); + ASSERT_EQ(15u, segments.size()); + + // Check that each segment has the expected size. Recall that the first word of each segment will + // actually be a pointer to the first thing allocated within that segment. + EXPECT_EQ( 1u, segments[ 0].size()); // root ref + EXPECT_EQ( 7u, segments[ 1].size()); // root struct + EXPECT_EQ( 2u, segments[ 2].size()); // sub-struct + EXPECT_EQ( 3u, segments[ 3].size()); // 3-element int32 list + EXPECT_EQ(10u, segments[ 4].size()); // struct list + EXPECT_EQ( 2u, segments[ 5].size()); // struct list substruct 1 + EXPECT_EQ( 2u, segments[ 6].size()); // struct list substruct 2 + EXPECT_EQ( 2u, segments[ 7].size()); // struct list substruct 3 + EXPECT_EQ( 2u, segments[ 8].size()); // struct list substruct 4 + EXPECT_EQ( 6u, segments[ 9].size()); // list list + EXPECT_EQ( 2u, segments[10].size()); // list list sublist 1 + EXPECT_EQ( 2u, segments[11].size()); // list list sublist 2 + EXPECT_EQ( 2u, segments[12].size()); // list list sublist 3 + EXPECT_EQ( 2u, segments[13].size()); // list list sublist 4 + EXPECT_EQ( 3u, segments[14].size()); // list list sublist 5 + + checkStruct(builder); + checkStruct(builder.asReader()); + checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) + .getStruct(nullptr)); +} + +TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { + MallocMessageBuilder message(8, AllocationStrategy::FIXED_SIZE); + BuilderArena arena(&message); + auto allocation = arena.allocate(1 * WORDS); + SegmentBuilder* segment = allocation.segment; + word* rootLocation = allocation.words; + + StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) + .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); + setupStruct(builder); + + // Verify that we made 6 segments. + kj::ArrayPtr> segments = arena.getSegmentsForOutput(); + ASSERT_EQ(6u, segments.size()); + + // Check that each segment has the expected size. Recall that each object will be prefixed by an + // extra word if its parent is in a different segment. + EXPECT_EQ( 8u, segments[0].size()); // root ref + struct + sub + EXPECT_EQ( 3u, segments[1].size()); // 3-element int32 list + EXPECT_EQ(10u, segments[2].size()); // struct list + EXPECT_EQ( 8u, segments[3].size()); // struct list substructs + EXPECT_EQ( 8u, segments[4].size()); // list list + sublist 1,2 + EXPECT_EQ( 7u, segments[5].size()); // list list sublist 3,4,5 + + checkStruct(builder); + checkStruct(builder.asReader()); + checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) + .getStruct(nullptr)); +} + +inline bool isNan(float f) { return f != f; } +inline bool isNan(double f) { return f != f; } + +TEST(WireFormat, NanPatching) { + EXPECT_EQ(0x7fc00000u, mask(kj::nan(), 0)); + EXPECT_TRUE(isNan(unmask(0x7fc00000u, 0))); + EXPECT_TRUE(isNan(unmask(0x7fc00001u, 0))); + EXPECT_TRUE(isNan(unmask(0x7fc00005u, 0))); + EXPECT_EQ(0x7fc00000u, mask(unmask(0x7fc00000u, 0), 0)); + EXPECT_EQ(0x7ff8000000000000ull, mask((double)kj::nan(), 0)); + EXPECT_TRUE(isNan(unmask(0x7ff8000000000000ull, 0))); + EXPECT_TRUE(isNan(unmask(0x7ff8000000000001ull, 0))); + EXPECT_TRUE(isNan(unmask(0x7ff8000000000005ull, 0))); + EXPECT_EQ(0x7ff8000000000000ull, mask(unmask(0x7ff8000000000000ull, 0), 0)); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/layout.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/layout.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,3764 @@ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE +#include "layout.h" +#include +#include "arena.h" +#include +#include + +#if !CAPNP_LITE +#include "capability.h" +#endif // !CAPNP_LITE + +namespace capnp { +namespace _ { // private + +#if !CAPNP_LITE +static BrokenCapFactory* brokenCapFactory = nullptr; +// Horrible hack: We need to be able to construct broken caps without any capability context, +// but we can't have a link-time dependency on libcapnp-rpc. + +void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory) { + // Called from capability.c++ when the capability API is used, to make sure that layout.c++ + // is ready for it. May be called multiple times but always with the same value. +#if __GNUC__ + __atomic_store_n(&brokenCapFactory, &factory, __ATOMIC_RELAXED); +#elif _MSC_VER + *static_cast(&brokenCapFactory) = &factory; +#else +#error "Platform not supported" +#endif +} + +} // namespace _ (private) + +const uint ClientHook::NULL_CAPABILITY_BRAND = 0; +// Defined here rather than capability.c++ so that we can safely call isNull() in this file. + +namespace _ { // private + +#endif // !CAPNP_LITE + +#if CAPNP_DEBUG_TYPES +#define G(n) bounded() +#else +#define G(n) n +#endif + +// ======================================================================================= + +struct WirePointer { + // A pointer, in exactly the format in which it appears on the wire. + + // Copying and moving is not allowed because the offset would become wrong. + WirePointer(const WirePointer& other) = delete; + WirePointer(WirePointer&& other) = delete; + WirePointer& operator=(const WirePointer& other) = delete; + WirePointer& operator=(WirePointer&& other) = delete; + + // ----------------------------------------------------------------- + // Common part of all pointers: kind + offset + // + // Actually this is not terribly common. The "offset" could actually be different things + // depending on the context: + // - For a regular (e.g. struct/list) pointer, a signed word offset from the word immediately + // following the pointer pointer. (The off-by-one means the offset is more often zero, saving + // bytes on the wire when packed.) + // - For an inline composite list tag (not really a pointer, but structured similarly), an + // element count. + // - For a FAR pointer, an unsigned offset into the target segment. + // - For a FAR landing pad, zero indicates that the target value immediately follows the pad while + // 1 indicates that the pad is followed by another FAR pointer that actually points at the + // value. + + enum Kind { + STRUCT = 0, + // Reference points at / describes a struct. + + LIST = 1, + // Reference points at / describes a list. + + FAR = 2, + // Reference is a "far pointer", which points at data located in a different segment. The + // eventual target is one of the other kinds. + + OTHER = 3 + // Reference has type "other". If the next 30 bits are all zero (i.e. the lower 32 bits contain + // only the kind OTHER) then the pointer is a capability. All other values are reserved. + }; + + WireValue offsetAndKind; + + KJ_ALWAYS_INLINE(Kind kind() const) { + return static_cast(offsetAndKind.get() & 3); + } + KJ_ALWAYS_INLINE(bool isPositional() const) { + return (offsetAndKind.get() & 2) == 0; // match STRUCT and LIST but not FAR or OTHER + } + KJ_ALWAYS_INLINE(bool isCapability() const) { + return offsetAndKind.get() == OTHER; + } + + KJ_ALWAYS_INLINE(word* target()) { + return reinterpret_cast(this) + 1 + (static_cast(offsetAndKind.get()) >> 2); + } + KJ_ALWAYS_INLINE(const word* target(SegmentReader* segment) const) { + if (segment == nullptr) { + return reinterpret_cast(this + 1) + + (static_cast(offsetAndKind.get()) >> 2); + } else { + return segment->checkOffset(reinterpret_cast(this + 1), + static_cast(offsetAndKind.get()) >> 2); + } + } + KJ_ALWAYS_INLINE(void setKindAndTarget(Kind kind, word* target, SegmentBuilder* segment)) { + // Check that the target is really in the same segment, otherwise subtracting pointers is + // undefined behavior. As it turns out, it's undefined behavior that actually produces + // unexpected results in a real-world situation that actually happened: At one time, + // OrphanBuilder's "tag" (a WirePointer) was allowed to be initialized as if it lived in + // a particular segment when in fact it does not. On 32-bit systems, where words might + // only be 32-bit aligned, it's possible that the difference between `this` and `target` is + // not a whole number of words. But clang optimizes: + // (target - (word*)this - 1) << 2 + // to: + // (((ptrdiff_t)target - (ptrdiff_t)this - 8) >> 1) + // So now when the pointers are not aligned the same, we can end up corrupting the bottom + // two bits, where `kind` is stored. For example, this turns a struct into a far pointer. + // Ouch! + KJ_DREQUIRE(reinterpret_cast(this) >= + reinterpret_cast(segment->getStartPtr())); + KJ_DREQUIRE(reinterpret_cast(this) < + reinterpret_cast(segment->getStartPtr() + segment->getSize())); + KJ_DREQUIRE(reinterpret_cast(target) >= + reinterpret_cast(segment->getStartPtr())); + KJ_DREQUIRE(reinterpret_cast(target) <= + reinterpret_cast(segment->getStartPtr() + segment->getSize())); + offsetAndKind.set(((target - reinterpret_cast(this) - 1) << 2) | kind); + } + KJ_ALWAYS_INLINE(void setKindWithZeroOffset(Kind kind)) { + offsetAndKind.set(kind); + } + KJ_ALWAYS_INLINE(void setKindAndTargetForEmptyStruct()) { + // This pointer points at an empty struct. Assuming the WirePointer itself is in-bounds, we + // can set the target to point either at the WirePointer itself or immediately after it. The + // latter would cause the WirePointer to be "null" (since for an empty struct the upper 32 + // bits are going to be zero). So we set an offset of -1, as if the struct were allocated + // immediately before this pointer, to distinguish it from null. + offsetAndKind.set(0xfffffffc); + } + KJ_ALWAYS_INLINE(void setKindForOrphan(Kind kind)) { + // OrphanBuilder contains a WirePointer, but since it isn't located in a segment, it should + // not have a valid offset (unless it is a FAR or OTHER pointer). We set its offset to -1 + // because setting it to zero would mean a pointer to an empty struct would appear to be a null + // pointer. + KJ_DREQUIRE(isPositional()); + offsetAndKind.set(kind | 0xfffffffc); + } + + KJ_ALWAYS_INLINE(ListElementCount inlineCompositeListElementCount() const) { + return ((bounded(offsetAndKind.get()) >> G(2)) + & G(kj::maxValueForBits())) * ELEMENTS; + } + KJ_ALWAYS_INLINE(void setKindAndInlineCompositeListElementCount( + Kind kind, ListElementCount elementCount)) { + offsetAndKind.set(unboundAs((elementCount / ELEMENTS) << G(2)) | kind); + } + + KJ_ALWAYS_INLINE(const word* farTarget(SegmentReader* segment) const) { + KJ_DREQUIRE(kind() == FAR, + "farTarget() should only be called on FAR pointers."); + return segment->checkOffset(segment->getStartPtr(), offsetAndKind.get() >> 3); + } + KJ_ALWAYS_INLINE(word* farTarget(SegmentBuilder* segment) const) { + KJ_DREQUIRE(kind() == FAR, + "farTarget() should only be called on FAR pointers."); + return segment->getPtrUnchecked((bounded(offsetAndKind.get()) >> G(3)) * WORDS); + } + KJ_ALWAYS_INLINE(bool isDoubleFar() const) { + KJ_DREQUIRE(kind() == FAR, + "isDoubleFar() should only be called on FAR pointers."); + return (offsetAndKind.get() >> 2) & 1; + } + KJ_ALWAYS_INLINE(void setFar(bool isDoubleFar, WordCountN<29> pos)) { + offsetAndKind.set(unboundAs((pos / WORDS) << G(3)) | + (static_cast(isDoubleFar) << 2) | + static_cast(Kind::FAR)); + } + KJ_ALWAYS_INLINE(void setCap(uint index)) { + offsetAndKind.set(static_cast(Kind::OTHER)); + capRef.index.set(index); + } + + // ----------------------------------------------------------------- + // Part of pointer that depends on the kind. + + // Note: Originally StructRef, ListRef, and FarRef were unnamed types, but this somehow + // tickled a bug in GCC: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58192 + struct StructRef { + WireValue dataSize; + WireValue ptrCount; + + inline WordCountN<17> wordSize() const { + return upgradeBound(dataSize.get()) + ptrCount.get() * WORDS_PER_POINTER; + } + + KJ_ALWAYS_INLINE(void set(WordCount16 ds, WirePointerCount16 rc)) { + dataSize.set(ds); + ptrCount.set(rc); + } + KJ_ALWAYS_INLINE(void set(StructSize size)) { + dataSize.set(size.data); + ptrCount.set(size.pointers); + } + }; + + struct ListRef { + WireValue elementSizeAndCount; + + KJ_ALWAYS_INLINE(ElementSize elementSize() const) { + return static_cast(elementSizeAndCount.get() & 7); + } + KJ_ALWAYS_INLINE(ElementCountN<29> elementCount() const) { + return (bounded(elementSizeAndCount.get()) >> G(3)) * ELEMENTS; + } + KJ_ALWAYS_INLINE(WordCountN<29> inlineCompositeWordCount() const) { + return elementCount() * (ONE * WORDS / ELEMENTS); + } + + KJ_ALWAYS_INLINE(void set(ElementSize es, ElementCountN<29> ec)) { + elementSizeAndCount.set(unboundAs((ec / ELEMENTS) << G(3)) | + static_cast(es)); + } + + KJ_ALWAYS_INLINE(void setInlineComposite(WordCountN<29> wc)) { + elementSizeAndCount.set(unboundAs((wc / WORDS) << G(3)) | + static_cast(ElementSize::INLINE_COMPOSITE)); + } + }; + + struct FarRef { + WireValue segmentId; + + KJ_ALWAYS_INLINE(void set(SegmentId si)) { + segmentId.set(si); + } + }; + + struct CapRef { + WireValue index; + // Index into the message's capability table. + }; + + union { + uint32_t upper32Bits; + + StructRef structRef; + + ListRef listRef; + + FarRef farRef; + + CapRef capRef; + }; + + KJ_ALWAYS_INLINE(bool isNull() const) { + // If the upper 32 bits are zero, this is a pointer to an empty struct. We consider that to be + // our "null" value. + return (offsetAndKind.get() == 0) & (upper32Bits == 0); + } + +}; +static_assert(sizeof(WirePointer) == sizeof(word), + "capnp::WirePointer is not exactly one word. This will probably break everything."); +static_assert(unboundAs(POINTERS * WORDS_PER_POINTER * BYTES_PER_WORD / BYTES) == + sizeof(WirePointer), + "WORDS_PER_POINTER is wrong."); +static_assert(unboundAs(POINTERS * BYTES_PER_POINTER / BYTES) == sizeof(WirePointer), + "BYTES_PER_POINTER is wrong."); +static_assert(unboundAs(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES) == + sizeof(WirePointer), + "BITS_PER_POINTER is wrong."); + +namespace { + +static const union { + AlignedData word; + WirePointer pointer; +} zero = {{{0}}}; + +} // namespace + +// ======================================================================================= + +namespace { + +template +struct SegmentAnd { + SegmentBuilder* segment; + T value; +}; + +} // namespace + +struct WireHelpers { +#if CAPNP_DEBUG_TYPES + template + static KJ_ALWAYS_INLINE( + kj::Quantity, word> roundBytesUpToWords( + kj::Quantity, byte> bytes)) { + static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); + return (bytes + G(7) * BYTES) / BYTES_PER_WORD; + } + + template + static KJ_ALWAYS_INLINE( + kj::Quantity, byte> roundBitsUpToBytes( + kj::Quantity, BitLabel> bits)) { + return (bits + G(7) * BITS) / BITS_PER_BYTE; + } + + template + static KJ_ALWAYS_INLINE( + kj::Quantity, word> roundBitsUpToWords( + kj::Quantity, BitLabel> bits)) { + static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); + return (bits + G(63) * BITS) / BITS_PER_WORD; + } +#else + static KJ_ALWAYS_INLINE(WordCount roundBytesUpToWords(ByteCount bytes)) { + static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); + return (bytes + G(7) * BYTES) / BYTES_PER_WORD; + } + + static KJ_ALWAYS_INLINE(ByteCount roundBitsUpToBytes(BitCount bits)) { + return (bits + G(7) * BITS) / BITS_PER_BYTE; + } + + static KJ_ALWAYS_INLINE(WordCount64 roundBitsUpToWords(BitCount64 bits)) { + static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); + return (bits + G(63) * BITS) / BITS_PER_WORD; + } + + static KJ_ALWAYS_INLINE(ByteCount64 roundBitsUpToBytes(BitCount64 bits)) { + return (bits + G(7) * BITS) / BITS_PER_BYTE; + } +#endif + + static KJ_ALWAYS_INLINE(void zeroMemory(byte* ptr, ByteCount32 count)) { + memset(ptr, 0, unbound(count / BYTES)); + } + + static KJ_ALWAYS_INLINE(void zeroMemory(word* ptr, WordCountN<29> count)) { + memset(ptr, 0, unbound(count * BYTES_PER_WORD / BYTES)); + } + + static KJ_ALWAYS_INLINE(void zeroMemory(WirePointer* ptr, WirePointerCountN<29> count)) { + memset(ptr, 0, unbound(count * BYTES_PER_POINTER / BYTES)); + } + + static KJ_ALWAYS_INLINE(void zeroMemory(WirePointer* ptr)) { + memset(ptr, 0, sizeof(*ptr)); + } + + template + static inline void zeroMemory(kj::ArrayPtr array) { + memset(array.begin(), 0, array.size() * sizeof(array[0])); + } + + static KJ_ALWAYS_INLINE(void copyMemory(byte* to, const byte* from, ByteCount32 count)) { + memcpy(to, from, unbound(count / BYTES)); + } + + static KJ_ALWAYS_INLINE(void copyMemory(word* to, const word* from, WordCountN<29> count)) { + memcpy(to, from, unbound(count * BYTES_PER_WORD / BYTES)); + } + + static KJ_ALWAYS_INLINE(void copyMemory(WirePointer* to, const WirePointer* from, + WirePointerCountN<29> count)) { + memcpy(to, from, unbound(count * BYTES_PER_POINTER / BYTES)); + } + + template + static inline void copyMemory(T* to, const T* from) { + memcpy(to, from, sizeof(*from)); + } + + // TODO(cleanup): Turn these into a .copyTo() method of ArrayPtr? + template + static inline void copyMemory(T* to, kj::ArrayPtr from) { + memcpy(to, from.begin(), from.size() * sizeof(from[0])); + } + template + static inline void copyMemory(T* to, kj::ArrayPtr from) { + memcpy(to, from.begin(), from.size() * sizeof(from[0])); + } + static KJ_ALWAYS_INLINE(void copyMemory(char* to, kj::StringPtr from)) { + memcpy(to, from.begin(), from.size() * sizeof(from[0])); + } + + static KJ_ALWAYS_INLINE(bool boundsCheck( + SegmentReader* segment, const word* start, WordCountN<31> size)) { + // If segment is null, this is an unchecked message, so we don't do bounds checks. + return segment == nullptr || segment->checkObject(start, size); + } + + static KJ_ALWAYS_INLINE(bool amplifiedRead(SegmentReader* segment, WordCount virtualAmount)) { + // If segment is null, this is an unchecked message, so we don't do read limiter checks. + return segment == nullptr || segment->amplifiedRead(virtualAmount); + } + + static KJ_ALWAYS_INLINE(word* allocate( + WirePointer*& ref, SegmentBuilder*& segment, CapTableBuilder* capTable, + SegmentWordCount amount, WirePointer::Kind kind, BuilderArena* orphanArena)) { + // Allocate space in the message for a new object, creating far pointers if necessary. + // + // * `ref` starts out being a reference to the pointer which shall be assigned to point at the + // new object. On return, `ref` points to a pointer which needs to be initialized with + // the object's type information. Normally this is the same pointer, but it can change if + // a far pointer was allocated -- in this case, `ref` will end up pointing to the far + // pointer's tag. Either way, `allocate()` takes care of making sure that the original + // pointer ends up leading to the new object. On return, only the upper 32 bit of `*ref` + // need to be filled in by the caller. + // * `segment` starts out pointing to the segment containing `ref`. On return, it points to + // the segment containing the allocated object, which is usually the same segment but could + // be a different one if the original segment was out of space. + // * `amount` is the number of words to allocate. + // * `kind` is the kind of object to allocate. It is used to initialize the pointer. It + // cannot be `FAR` -- far pointers are allocated automatically as needed. + // * `orphanArena` is usually null. If it is non-null, then we're allocating an orphan object. + // In this case, `segment` starts out null; the allocation takes place in an arbitrary + // segment belonging to the arena. `ref` will be initialized as a non-far pointer, but its + // target offset will be set to zero. + + if (orphanArena == nullptr) { + if (!ref->isNull()) zeroObject(segment, capTable, ref); + + if (amount == ZERO * WORDS && kind == WirePointer::STRUCT) { + // Note that the check for kind == WirePointer::STRUCT will hopefully cause this whole + // branch to be optimized away from all the call sites that are allocating non-structs. + ref->setKindAndTargetForEmptyStruct(); + return reinterpret_cast(ref); + } + + word* ptr = segment->allocate(amount); + + if (ptr == nullptr) { + + // Need to allocate in a new segment. We'll need to allocate an extra pointer worth of + // space to act as the landing pad for a far pointer. + + WordCount amountPlusRef = amount + POINTER_SIZE_IN_WORDS; + auto allocation = segment->getArena()->allocate( + assertMaxBits(amountPlusRef, []() { + KJ_FAIL_REQUIRE("requested object size exceeds maximum segment size"); + })); + segment = allocation.segment; + ptr = allocation.words; + + // Set up the original pointer to be a far pointer to the new segment. + ref->setFar(false, segment->getOffsetTo(ptr)); + ref->farRef.set(segment->getSegmentId()); + + // Initialize the landing pad to indicate that the data immediately follows the pad. + ref = reinterpret_cast(ptr); + ref->setKindAndTarget(kind, ptr + POINTER_SIZE_IN_WORDS, segment); + + // Allocated space follows new pointer. + return ptr + POINTER_SIZE_IN_WORDS; + } else { + ref->setKindAndTarget(kind, ptr, segment); + return ptr; + } + } else { + // orphanArena is non-null. Allocate an orphan. + KJ_DASSERT(ref->isNull()); + auto allocation = orphanArena->allocate(amount); + segment = allocation.segment; + ref->setKindForOrphan(kind); + return allocation.words; + } + } + + static KJ_ALWAYS_INLINE(word* followFarsNoWritableCheck( + WirePointer*& ref, word* refTarget, SegmentBuilder*& segment)) { + // If `ref` is a far pointer, follow it. On return, `ref` will have been updated to point at + // a WirePointer that contains the type information about the target object, and a pointer to + // the object contents is returned. The caller must NOT use `ref->target()` as this may or may + // not actually return a valid pointer. `segment` is also updated to point at the segment which + // actually contains the object. + // + // If `ref` is not a far pointer, this simply returns `refTarget`. Usually, `refTarget` should + // be the same as `ref->target()`, but may not be in cases where `ref` is only a tag. + + if (ref->kind() == WirePointer::FAR) { + segment = segment->getArena()->getSegment(ref->farRef.segmentId.get()); + WirePointer* pad = reinterpret_cast(ref->farTarget(segment)); + if (!ref->isDoubleFar()) { + ref = pad; + return pad->target(); + } + + // Landing pad is another far pointer. It is followed by a tag describing the pointed-to + // object. + ref = pad + 1; + + segment = segment->getArena()->getSegment(pad->farRef.segmentId.get()); + return pad->farTarget(segment); + } else { + return refTarget; + } + } + + static KJ_ALWAYS_INLINE(word* followFars( + WirePointer*& ref, word* refTarget, SegmentBuilder*& segment)) { + auto result = followFarsNoWritableCheck(ref, refTarget, segment); + segment->checkWritable(); + return result; + } + + static KJ_ALWAYS_INLINE(kj::Maybe followFars( + const WirePointer*& ref, const word* refTarget, SegmentReader*& segment)) + KJ_WARN_UNUSED_RESULT { + // Like the other followFars() but operates on readers. + + // If the segment is null, this is an unchecked message, so there are no FAR pointers. + if (segment != nullptr && ref->kind() == WirePointer::FAR) { + // Look up the segment containing the landing pad. + segment = segment->getArena()->tryGetSegment(ref->farRef.segmentId.get()); + KJ_REQUIRE(segment != nullptr, "Message contains far pointer to unknown segment.") { + return nullptr; + } + + // Find the landing pad and check that it is within bounds. + const word* ptr = ref->farTarget(segment); + auto padWords = (ONE + bounded(ref->isDoubleFar())) * POINTER_SIZE_IN_WORDS; + KJ_REQUIRE(boundsCheck(segment, ptr, padWords), + "Message contains out-of-bounds far pointer.") { + return nullptr; + } + + const WirePointer* pad = reinterpret_cast(ptr); + + // If this is not a double-far then the landing pad is our final pointer. + if (!ref->isDoubleFar()) { + ref = pad; + return pad->target(segment); + } + + // Landing pad is another far pointer. It is followed by a tag describing the pointed-to + // object. + ref = pad + 1; + + SegmentReader* newSegment = segment->getArena()->tryGetSegment(pad->farRef.segmentId.get()); + KJ_REQUIRE(newSegment != nullptr, + "Message contains double-far pointer to unknown segment.") { + return nullptr; + } + KJ_REQUIRE(pad->kind() == WirePointer::FAR, + "Second word of double-far pad must be far pointer.") { + return nullptr; + } + + segment = newSegment; + return pad->farTarget(segment); + } else { + KJ_DASSERT(refTarget != nullptr); + return refTarget; + } + } + + // ----------------------------------------------------------------- + + static void zeroObject(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* ref) { + // Zero out the pointed-to object. Use when the pointer is about to be overwritten making the + // target object no longer reachable. + + // We shouldn't zero out external data linked into the message. + if (!segment->isWritable()) return; + + switch (ref->kind()) { + case WirePointer::STRUCT: + case WirePointer::LIST: + zeroObject(segment, capTable, ref, ref->target()); + break; + case WirePointer::FAR: { + segment = segment->getArena()->getSegment(ref->farRef.segmentId.get()); + if (segment->isWritable()) { // Don't zero external data. + WirePointer* pad = reinterpret_cast(ref->farTarget(segment)); + + if (ref->isDoubleFar()) { + segment = segment->getArena()->getSegment(pad->farRef.segmentId.get()); + if (segment->isWritable()) { + zeroObject(segment, capTable, pad + 1, pad->farTarget(segment)); + } + zeroMemory(pad, G(2) * POINTERS); + } else { + zeroObject(segment, capTable, pad); + zeroMemory(pad); + } + } + break; + } + case WirePointer::OTHER: + if (ref->isCapability()) { +#if CAPNP_LITE + KJ_FAIL_ASSERT("Capability encountered in builder in lite mode?") { break; } +#else // CAPNP_LINE + capTable->dropCap(ref->capRef.index.get()); +#endif // CAPNP_LITE, else + } else { + KJ_FAIL_REQUIRE("Unknown pointer type.") { break; } + } + break; + } + } + + static void zeroObject(SegmentBuilder* segment, CapTableBuilder* capTable, + WirePointer* tag, word* ptr) { + // We shouldn't zero out external data linked into the message. + if (!segment->isWritable()) return; + + switch (tag->kind()) { + case WirePointer::STRUCT: { + WirePointer* pointerSection = + reinterpret_cast(ptr + tag->structRef.dataSize.get()); + for (auto i: kj::zeroTo(tag->structRef.ptrCount.get())) { + zeroObject(segment, capTable, pointerSection + i); + } + zeroMemory(ptr, tag->structRef.wordSize()); + break; + } + case WirePointer::LIST: { + switch (tag->listRef.elementSize()) { + case ElementSize::VOID: + // Nothing. + break; + case ElementSize::BIT: + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: { + zeroMemory(ptr, roundBitsUpToWords( + upgradeBound(tag->listRef.elementCount()) * + dataBitsPerElement(tag->listRef.elementSize()))); + break; + } + case ElementSize::POINTER: { + WirePointer* typedPtr = reinterpret_cast(ptr); + auto count = tag->listRef.elementCount() * (ONE * POINTERS / ELEMENTS); + for (auto i: kj::zeroTo(count)) { + zeroObject(segment, capTable, typedPtr + i); + } + zeroMemory(typedPtr, count); + break; + } + case ElementSize::INLINE_COMPOSITE: { + WirePointer* elementTag = reinterpret_cast(ptr); + + KJ_ASSERT(elementTag->kind() == WirePointer::STRUCT, + "Don't know how to handle non-STRUCT inline composite."); + WordCount dataSize = elementTag->structRef.dataSize.get(); + WirePointerCount pointerCount = elementTag->structRef.ptrCount.get(); + + auto count = elementTag->inlineCompositeListElementCount(); + if (pointerCount > ZERO * POINTERS) { + word* pos = ptr + POINTER_SIZE_IN_WORDS; + for (auto i KJ_UNUSED: kj::zeroTo(count)) { + pos += dataSize; + + for (auto j KJ_UNUSED: kj::zeroTo(pointerCount)) { + zeroObject(segment, capTable, reinterpret_cast(pos)); + pos += POINTER_SIZE_IN_WORDS; + } + } + } + + auto wordsPerElement = elementTag->structRef.wordSize() / ELEMENTS; + zeroMemory(ptr, assertMaxBits(POINTER_SIZE_IN_WORDS + + upgradeBound(count) * wordsPerElement, []() { + KJ_FAIL_ASSERT("encountered list pointer in builder which is too large to " + "possibly fit in a segment. Bug in builder code?"); + })); + break; + } + } + break; + } + case WirePointer::FAR: + KJ_FAIL_ASSERT("Unexpected FAR pointer.") { + break; + } + break; + case WirePointer::OTHER: + KJ_FAIL_ASSERT("Unexpected OTHER pointer.") { + break; + } + break; + } + } + + static KJ_ALWAYS_INLINE( + void zeroPointerAndFars(SegmentBuilder* segment, WirePointer* ref)) { + // Zero out the pointer itself and, if it is a far pointer, zero the landing pad as well, but + // do not zero the object body. Used when upgrading. + + if (ref->kind() == WirePointer::FAR) { + SegmentBuilder* padSegment = segment->getArena()->getSegment(ref->farRef.segmentId.get()); + if (padSegment->isWritable()) { // Don't zero external data. + WirePointer* pad = reinterpret_cast(ref->farTarget(padSegment)); + if (ref->isDoubleFar()) { + zeroMemory(pad, G(2) * POINTERS); + } else { + zeroMemory(pad); + } + } + } + + zeroMemory(ref); + } + + + // ----------------------------------------------------------------- + + static MessageSizeCounts totalSize( + SegmentReader* segment, const WirePointer* ref, int nestingLimit) { + // Compute the total size of the object pointed to, not counting far pointer overhead. + + MessageSizeCounts result = { ZERO * WORDS, 0 }; + + if (ref->isNull()) { + return result; + } + + KJ_REQUIRE(nestingLimit > 0, "Message is too deeply-nested.") { + return result; + } + --nestingLimit; + + const word* ptr; + KJ_IF_MAYBE(p, followFars(ref, ref->target(segment), segment)) { + ptr = p; + } else { + return result; + } + + switch (ref->kind()) { + case WirePointer::STRUCT: { + KJ_REQUIRE(boundsCheck(segment, ptr, ref->structRef.wordSize()), + "Message contained out-of-bounds struct pointer.") { + return result; + } + result.addWords(ref->structRef.wordSize()); + + const WirePointer* pointerSection = + reinterpret_cast(ptr + ref->structRef.dataSize.get()); + for (auto i: kj::zeroTo(ref->structRef.ptrCount.get())) { + result += totalSize(segment, pointerSection + i, nestingLimit); + } + break; + } + case WirePointer::LIST: { + switch (ref->listRef.elementSize()) { + case ElementSize::VOID: + // Nothing. + break; + case ElementSize::BIT: + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: { + auto totalWords = roundBitsUpToWords( + upgradeBound(ref->listRef.elementCount()) * + dataBitsPerElement(ref->listRef.elementSize())); + KJ_REQUIRE(boundsCheck(segment, ptr, totalWords), + "Message contained out-of-bounds list pointer.") { + return result; + } + result.addWords(totalWords); + break; + } + case ElementSize::POINTER: { + auto count = ref->listRef.elementCount() * (POINTERS / ELEMENTS); + + KJ_REQUIRE(boundsCheck(segment, ptr, count * WORDS_PER_POINTER), + "Message contained out-of-bounds list pointer.") { + return result; + } + + result.addWords(count * WORDS_PER_POINTER); + + for (auto i: kj::zeroTo(count)) { + result += totalSize(segment, reinterpret_cast(ptr) + i, + nestingLimit); + } + break; + } + case ElementSize::INLINE_COMPOSITE: { + auto wordCount = ref->listRef.inlineCompositeWordCount(); + KJ_REQUIRE(boundsCheck(segment, ptr, wordCount + POINTER_SIZE_IN_WORDS), + "Message contained out-of-bounds list pointer.") { + return result; + } + + const WirePointer* elementTag = reinterpret_cast(ptr); + auto count = elementTag->inlineCompositeListElementCount(); + + KJ_REQUIRE(elementTag->kind() == WirePointer::STRUCT, + "Don't know how to handle non-STRUCT inline composite.") { + return result; + } + + auto actualSize = elementTag->structRef.wordSize() / ELEMENTS * + upgradeBound(count); + KJ_REQUIRE(actualSize <= wordCount, + "Struct list pointer's elements overran size.") { + return result; + } + + // We count the actual size rather than the claimed word count because that's what + // we'll end up with if we make a copy. + result.addWords(wordCount + POINTER_SIZE_IN_WORDS); + + WordCount dataSize = elementTag->structRef.dataSize.get(); + WirePointerCount pointerCount = elementTag->structRef.ptrCount.get(); + + if (pointerCount > ZERO * POINTERS) { + const word* pos = ptr + POINTER_SIZE_IN_WORDS; + for (auto i KJ_UNUSED: kj::zeroTo(count)) { + pos += dataSize; + + for (auto j KJ_UNUSED: kj::zeroTo(pointerCount)) { + result += totalSize(segment, reinterpret_cast(pos), + nestingLimit); + pos += POINTER_SIZE_IN_WORDS; + } + } + } + break; + } + } + break; + } + case WirePointer::FAR: + KJ_FAIL_REQUIRE("Unexpected FAR pointer.") { + break; + } + break; + case WirePointer::OTHER: + if (ref->isCapability()) { + result.capCount++; + } else { + KJ_FAIL_REQUIRE("Unknown pointer type.") { break; } + } + break; + } + + return result; + } + + // ----------------------------------------------------------------- + // Copy from an unchecked message. + + static KJ_ALWAYS_INLINE( + void copyStruct(SegmentBuilder* segment, CapTableBuilder* capTable, + word* dst, const word* src, + StructDataWordCount dataSize, StructPointerCount pointerCount)) { + copyMemory(dst, src, dataSize); + + const WirePointer* srcRefs = reinterpret_cast(src + dataSize); + WirePointer* dstRefs = reinterpret_cast(dst + dataSize); + + for (auto i: kj::zeroTo(pointerCount)) { + SegmentBuilder* subSegment = segment; + WirePointer* dstRef = dstRefs + i; + copyMessage(subSegment, capTable, dstRef, srcRefs + i); + } + } + + static word* copyMessage( + SegmentBuilder*& segment, CapTableBuilder* capTable, + WirePointer*& dst, const WirePointer* src) { + // Not always-inline because it's recursive. + + switch (src->kind()) { + case WirePointer::STRUCT: { + if (src->isNull()) { + zeroMemory(dst); + return nullptr; + } else { + const word* srcPtr = src->target(nullptr); + word* dstPtr = allocate( + dst, segment, capTable, src->structRef.wordSize(), WirePointer::STRUCT, nullptr); + + copyStruct(segment, capTable, dstPtr, srcPtr, src->structRef.dataSize.get(), + src->structRef.ptrCount.get()); + + dst->structRef.set(src->structRef.dataSize.get(), src->structRef.ptrCount.get()); + return dstPtr; + } + } + case WirePointer::LIST: { + switch (src->listRef.elementSize()) { + case ElementSize::VOID: + case ElementSize::BIT: + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: { + auto wordCount = roundBitsUpToWords( + upgradeBound(src->listRef.elementCount()) * + dataBitsPerElement(src->listRef.elementSize())); + const word* srcPtr = src->target(nullptr); + word* dstPtr = allocate(dst, segment, capTable, wordCount, WirePointer::LIST, nullptr); + copyMemory(dstPtr, srcPtr, wordCount); + + dst->listRef.set(src->listRef.elementSize(), src->listRef.elementCount()); + return dstPtr; + } + + case ElementSize::POINTER: { + const WirePointer* srcRefs = reinterpret_cast(src->target(nullptr)); + WirePointer* dstRefs = reinterpret_cast( + allocate(dst, segment, capTable, src->listRef.elementCount() * + (ONE * POINTERS / ELEMENTS) * WORDS_PER_POINTER, + WirePointer::LIST, nullptr)); + + for (auto i: kj::zeroTo(src->listRef.elementCount() * (ONE * POINTERS / ELEMENTS))) { + SegmentBuilder* subSegment = segment; + WirePointer* dstRef = dstRefs + i; + copyMessage(subSegment, capTable, dstRef, srcRefs + i); + } + + dst->listRef.set(ElementSize::POINTER, src->listRef.elementCount()); + return reinterpret_cast(dstRefs); + } + + case ElementSize::INLINE_COMPOSITE: { + const word* srcPtr = src->target(nullptr); + word* dstPtr = allocate(dst, segment, capTable, + assertMaxBits( + src->listRef.inlineCompositeWordCount() + POINTER_SIZE_IN_WORDS, + []() { KJ_FAIL_ASSERT("list too big to fit in a segment"); }), + WirePointer::LIST, nullptr); + + dst->listRef.setInlineComposite(src->listRef.inlineCompositeWordCount()); + + const WirePointer* srcTag = reinterpret_cast(srcPtr); + copyMemory(reinterpret_cast(dstPtr), srcTag); + + const word* srcElement = srcPtr + POINTER_SIZE_IN_WORDS; + word* dstElement = dstPtr + POINTER_SIZE_IN_WORDS; + + KJ_ASSERT(srcTag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE of lists is not yet supported."); + + for (auto i KJ_UNUSED: kj::zeroTo(srcTag->inlineCompositeListElementCount())) { + copyStruct(segment, capTable, dstElement, srcElement, + srcTag->structRef.dataSize.get(), srcTag->structRef.ptrCount.get()); + srcElement += srcTag->structRef.wordSize(); + dstElement += srcTag->structRef.wordSize(); + } + return dstPtr; + } + } + break; + } + case WirePointer::OTHER: + KJ_FAIL_REQUIRE("Unchecked messages cannot contain OTHER pointers (e.g. capabilities)."); + break; + case WirePointer::FAR: + KJ_FAIL_REQUIRE("Unchecked messages cannot contain far pointers."); + break; + } + + return nullptr; + } + + static void transferPointer(SegmentBuilder* dstSegment, WirePointer* dst, + SegmentBuilder* srcSegment, WirePointer* src) { + // Make *dst point to the same object as *src. Both must reside in the same message, but can + // be in different segments. Not always-inline because this is rarely used. + // + // Caller MUST zero out the source pointer after calling this, to make sure no later code + // mistakenly thinks the source location still owns the object. transferPointer() doesn't do + // this zeroing itself because many callers transfer several pointers in a loop then zero out + // the whole section. + + KJ_DASSERT(dst->isNull()); + // We expect the caller to ensure the target is already null so won't leak. + + if (src->isNull()) { + zeroMemory(dst); + } else if (src->isPositional()) { + transferPointer(dstSegment, dst, srcSegment, src, src->target()); + } else { + // Far and other pointers are position-independent, so we can just copy. + copyMemory(dst, src); + } + } + + static void transferPointer(SegmentBuilder* dstSegment, WirePointer* dst, + SegmentBuilder* srcSegment, const WirePointer* srcTag, + word* srcPtr) { + // Like the other overload, but splits src into a tag and a target. Particularly useful for + // OrphanBuilder. + + if (dstSegment == srcSegment) { + // Same segment, so create a direct pointer. + + if (srcTag->kind() == WirePointer::STRUCT && srcTag->structRef.wordSize() == ZERO * WORDS) { + dst->setKindAndTargetForEmptyStruct(); + } else { + dst->setKindAndTarget(srcTag->kind(), srcPtr, dstSegment); + } + + // We can just copy the upper 32 bits. (Use memcpy() to comply with aliasing rules.) + copyMemory(&dst->upper32Bits, &srcTag->upper32Bits); + } else { + // Need to create a far pointer. Try to allocate it in the same segment as the source, so + // that it doesn't need to be a double-far. + + WirePointer* landingPad = + reinterpret_cast(srcSegment->allocate(G(1) * WORDS)); + if (landingPad == nullptr) { + // Darn, need a double-far. + auto allocation = srcSegment->getArena()->allocate(G(2) * WORDS); + SegmentBuilder* farSegment = allocation.segment; + landingPad = reinterpret_cast(allocation.words); + + landingPad[0].setFar(false, srcSegment->getOffsetTo(srcPtr)); + landingPad[0].farRef.segmentId.set(srcSegment->getSegmentId()); + + landingPad[1].setKindWithZeroOffset(srcTag->kind()); + copyMemory(&landingPad[1].upper32Bits, &srcTag->upper32Bits); + + dst->setFar(true, farSegment->getOffsetTo(reinterpret_cast(landingPad))); + dst->farRef.set(farSegment->getSegmentId()); + } else { + // Simple landing pad is just a pointer. + landingPad->setKindAndTarget(srcTag->kind(), srcPtr, srcSegment); + copyMemory(&landingPad->upper32Bits, &srcTag->upper32Bits); + + dst->setFar(false, srcSegment->getOffsetTo(reinterpret_cast(landingPad))); + dst->farRef.set(srcSegment->getSegmentId()); + } + } + } + + // ----------------------------------------------------------------- + + static KJ_ALWAYS_INLINE(StructBuilder initStructPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, StructSize size, + BuilderArena* orphanArena = nullptr)) { + // Allocate space for the new struct. Newly-allocated space is automatically zeroed. + word* ptr = allocate(ref, segment, capTable, size.total(), WirePointer::STRUCT, orphanArena); + + // Initialize the pointer. + ref->structRef.set(size); + + // Build the StructBuilder. + return StructBuilder(segment, capTable, ptr, reinterpret_cast(ptr + size.data), + size.data * BITS_PER_WORD, size.pointers); + } + + static KJ_ALWAYS_INLINE(StructBuilder getWritableStructPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, StructSize size, + const word* defaultValue)) { + return getWritableStructPointer(ref, ref->target(), segment, capTable, size, defaultValue); + } + + static KJ_ALWAYS_INLINE(StructBuilder getWritableStructPointer( + WirePointer* ref, word* refTarget, SegmentBuilder* segment, CapTableBuilder* capTable, + StructSize size, const word* defaultValue, BuilderArena* orphanArena = nullptr)) { + if (ref->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return initStructPointer(ref, segment, capTable, size, orphanArena); + } + refTarget = copyMessage(segment, capTable, ref, + reinterpret_cast(defaultValue)); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + WirePointer* oldRef = ref; + SegmentBuilder* oldSegment = segment; + word* oldPtr = followFars(oldRef, refTarget, oldSegment); + + KJ_REQUIRE(oldRef->kind() == WirePointer::STRUCT, + "Message contains non-struct pointer where struct pointer was expected.") { + goto useDefault; + } + + auto oldDataSize = oldRef->structRef.dataSize.get(); + auto oldPointerCount = oldRef->structRef.ptrCount.get(); + WirePointer* oldPointerSection = + reinterpret_cast(oldPtr + oldDataSize); + + if (oldDataSize < size.data || oldPointerCount < size.pointers) { + // The space allocated for this struct is too small. Unlike with readers, we can't just + // run with it and do bounds checks at access time, because how would we handle writes? + // Instead, we have to copy the struct to a new space now. + + auto newDataSize = kj::max(oldDataSize, size.data); + auto newPointerCount = kj::max(oldPointerCount, size.pointers); + auto totalSize = newDataSize + newPointerCount * WORDS_PER_POINTER; + + // Don't let allocate() zero out the object just yet. + zeroPointerAndFars(segment, ref); + + word* ptr = allocate(ref, segment, capTable, totalSize, WirePointer::STRUCT, orphanArena); + ref->structRef.set(newDataSize, newPointerCount); + + // Copy data section. + copyMemory(ptr, oldPtr, oldDataSize); + + // Copy pointer section. + WirePointer* newPointerSection = reinterpret_cast(ptr + newDataSize); + for (auto i: kj::zeroTo(oldPointerCount)) { + transferPointer(segment, newPointerSection + i, oldSegment, oldPointerSection + i); + } + + // Zero out old location. This has two purposes: + // 1) We don't want to leak the original contents of the struct when the message is written + // out as it may contain secrets that the caller intends to remove from the new copy. + // 2) Zeros will be deflated by packing, making this dead memory almost-free if it ever + // hits the wire. + zeroMemory(oldPtr, oldDataSize + oldPointerCount * WORDS_PER_POINTER); + + return StructBuilder(segment, capTable, ptr, newPointerSection, newDataSize * BITS_PER_WORD, + newPointerCount); + } else { + return StructBuilder(oldSegment, capTable, oldPtr, oldPointerSection, + oldDataSize * BITS_PER_WORD, oldPointerCount); + } + } + + static KJ_ALWAYS_INLINE(ListBuilder initListPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, + ElementCount elementCount, ElementSize elementSize, BuilderArena* orphanArena = nullptr)) { + KJ_DREQUIRE(elementSize != ElementSize::INLINE_COMPOSITE, + "Should have called initStructListPointer() instead."); + + auto checkedElementCount = assertMaxBits(elementCount, + []() { KJ_FAIL_REQUIRE("tried to allocate list with too many elements"); }); + + auto dataSize = dataBitsPerElement(elementSize) * ELEMENTS; + auto pointerCount = pointersPerElement(elementSize) * ELEMENTS; + auto step = bitsPerElementIncludingPointers(elementSize); + KJ_DASSERT(step * ELEMENTS == (dataSize + pointerCount * BITS_PER_POINTER)); + + // Calculate size of the list. + auto wordCount = roundBitsUpToWords(upgradeBound(checkedElementCount) * step); + + // Allocate the list. + word* ptr = allocate(ref, segment, capTable, wordCount, WirePointer::LIST, orphanArena); + + // Initialize the pointer. + ref->listRef.set(elementSize, checkedElementCount); + + // Build the ListBuilder. + return ListBuilder(segment, capTable, ptr, step, checkedElementCount, + dataSize, pointerCount, elementSize); + } + + static KJ_ALWAYS_INLINE(ListBuilder initStructListPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, + ElementCount elementCount, StructSize elementSize, BuilderArena* orphanArena = nullptr)) { + auto checkedElementCount = assertMaxBits(elementCount, + []() { KJ_FAIL_REQUIRE("tried to allocate list with too many elements"); }); + + WordsPerElementN<17> wordsPerElement = elementSize.total() / ELEMENTS; + + // Allocate the list, prefixed by a single WirePointer. + auto wordCount = assertMax() - 1>( + upgradeBound(checkedElementCount) * wordsPerElement, + []() { KJ_FAIL_REQUIRE("total size of struct list is larger than max segment size"); }); + word* ptr = allocate(ref, segment, capTable, POINTER_SIZE_IN_WORDS + wordCount, + WirePointer::LIST, orphanArena); + + // Initialize the pointer. + // INLINE_COMPOSITE lists replace the element count with the word count. + ref->listRef.setInlineComposite(wordCount); + + // Initialize the list tag. + reinterpret_cast(ptr)->setKindAndInlineCompositeListElementCount( + WirePointer::STRUCT, checkedElementCount); + reinterpret_cast(ptr)->structRef.set(elementSize); + ptr += POINTER_SIZE_IN_WORDS; + + // Build the ListBuilder. + return ListBuilder(segment, capTable, ptr, wordsPerElement * BITS_PER_WORD, checkedElementCount, + elementSize.data * BITS_PER_WORD, elementSize.pointers, + ElementSize::INLINE_COMPOSITE); + } + + static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointer( + WirePointer* origRef, SegmentBuilder* origSegment, CapTableBuilder* capTable, + ElementSize elementSize, const word* defaultValue)) { + return getWritableListPointer(origRef, origRef->target(), origSegment, capTable, elementSize, + defaultValue); + } + + static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointer( + WirePointer* origRef, word* origRefTarget, + SegmentBuilder* origSegment, CapTableBuilder* capTable, ElementSize elementSize, + const word* defaultValue, BuilderArena* orphanArena = nullptr)) { + KJ_DREQUIRE(elementSize != ElementSize::INLINE_COMPOSITE, + "Use getWritableStructListPointer() for struct lists."); + + if (origRef->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return ListBuilder(elementSize); + } + origRefTarget = copyMessage( + origSegment, capTable, origRef, reinterpret_cast(defaultValue)); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + // We must verify that the pointer has the right size. Unlike in + // getWritableStructListPointer(), we never need to "upgrade" the data, because this + // method is called only for non-struct lists, and there is no allowed upgrade path *to* + // a non-struct list, only *from* them. + + WirePointer* ref = origRef; + SegmentBuilder* segment = origSegment; + word* ptr = followFars(ref, origRefTarget, segment); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Called getWritableListPointer() but existing pointer is not a list.") { + goto useDefault; + } + + ElementSize oldSize = ref->listRef.elementSize(); + + if (oldSize == ElementSize::INLINE_COMPOSITE) { + // The existing element size is INLINE_COMPOSITE, though we expected a list of primitives. + // The existing data must have been written with a newer version of the protocol. We + // therefore never need to upgrade the data in this case, but we do need to validate that it + // is a valid upgrade from what we expected. + + // Read the tag to get the actual element count. + WirePointer* tag = reinterpret_cast(ptr); + KJ_REQUIRE(tag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE list with non-STRUCT elements not supported."); + ptr += POINTER_SIZE_IN_WORDS; + + auto dataSize = tag->structRef.dataSize.get(); + auto pointerCount = tag->structRef.ptrCount.get(); + + switch (elementSize) { + case ElementSize::VOID: + // Anything is a valid upgrade from Void. + break; + + case ElementSize::BIT: + KJ_FAIL_REQUIRE( + "Found struct list where bit list was expected; upgrading boolean lists to structs " + "is no longer supported.") { + goto useDefault; + } + break; + + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: + KJ_REQUIRE(dataSize >= ONE * WORDS, + "Existing list value is incompatible with expected type.") { + goto useDefault; + } + break; + + case ElementSize::POINTER: + KJ_REQUIRE(pointerCount >= ONE * POINTERS, + "Existing list value is incompatible with expected type.") { + goto useDefault; + } + // Adjust the pointer to point at the reference segment. + ptr += dataSize; + break; + + case ElementSize::INLINE_COMPOSITE: + KJ_UNREACHABLE; + } + + // OK, looks valid. + + return ListBuilder(segment, capTable, ptr, + tag->structRef.wordSize() * BITS_PER_WORD / ELEMENTS, + tag->inlineCompositeListElementCount(), + dataSize * BITS_PER_WORD, pointerCount, ElementSize::INLINE_COMPOSITE); + } else { + auto dataSize = dataBitsPerElement(oldSize) * ELEMENTS; + auto pointerCount = pointersPerElement(oldSize) * ELEMENTS; + + if (elementSize == ElementSize::BIT) { + KJ_REQUIRE(oldSize == ElementSize::BIT, + "Found non-bit list where bit list was expected.") { + goto useDefault; + } + } else { + KJ_REQUIRE(oldSize != ElementSize::BIT, + "Found bit list where non-bit list was expected.") { + goto useDefault; + } + KJ_REQUIRE(dataSize >= dataBitsPerElement(elementSize) * ELEMENTS, + "Existing list value is incompatible with expected type.") { + goto useDefault; + } + KJ_REQUIRE(pointerCount >= pointersPerElement(elementSize) * ELEMENTS, + "Existing list value is incompatible with expected type.") { + goto useDefault; + } + } + + auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; + return ListBuilder(segment, capTable, ptr, step, ref->listRef.elementCount(), + dataSize, pointerCount, oldSize); + } + } + + static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointerAnySize( + WirePointer* origRef, SegmentBuilder* origSegment, CapTableBuilder* capTable, + const word* defaultValue)) { + return getWritableListPointerAnySize(origRef, origRef->target(), origSegment, + capTable, defaultValue); + } + + static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointerAnySize( + WirePointer* origRef, word* origRefTarget, + SegmentBuilder* origSegment, CapTableBuilder* capTable, + const word* defaultValue, BuilderArena* orphanArena = nullptr)) { + if (origRef->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return ListBuilder(ElementSize::VOID); + } + origRefTarget = copyMessage( + origSegment, capTable, origRef, reinterpret_cast(defaultValue)); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + WirePointer* ref = origRef; + SegmentBuilder* segment = origSegment; + word* ptr = followFars(ref, origRefTarget, segment); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Called getWritableListPointerAnySize() but existing pointer is not a list.") { + goto useDefault; + } + + ElementSize elementSize = ref->listRef.elementSize(); + + if (elementSize == ElementSize::INLINE_COMPOSITE) { + // Read the tag to get the actual element count. + WirePointer* tag = reinterpret_cast(ptr); + KJ_REQUIRE(tag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE list with non-STRUCT elements not supported."); + ptr += POINTER_SIZE_IN_WORDS; + + return ListBuilder(segment, capTable, ptr, + tag->structRef.wordSize() * BITS_PER_WORD / ELEMENTS, + tag->inlineCompositeListElementCount(), + tag->structRef.dataSize.get() * BITS_PER_WORD, + tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE); + } else { + auto dataSize = dataBitsPerElement(elementSize) * ELEMENTS; + auto pointerCount = pointersPerElement(elementSize) * ELEMENTS; + + auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; + return ListBuilder(segment, capTable, ptr, step, ref->listRef.elementCount(), + dataSize, pointerCount, elementSize); + } + } + + static KJ_ALWAYS_INLINE(ListBuilder getWritableStructListPointer( + WirePointer* origRef, SegmentBuilder* origSegment, CapTableBuilder* capTable, + StructSize elementSize, const word* defaultValue)) { + return getWritableStructListPointer(origRef, origRef->target(), origSegment, capTable, + elementSize, defaultValue); + } + static KJ_ALWAYS_INLINE(ListBuilder getWritableStructListPointer( + WirePointer* origRef, word* origRefTarget, + SegmentBuilder* origSegment, CapTableBuilder* capTable, + StructSize elementSize, const word* defaultValue, BuilderArena* orphanArena = nullptr)) { + if (origRef->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return ListBuilder(ElementSize::INLINE_COMPOSITE); + } + origRefTarget = copyMessage( + origSegment, capTable, origRef, reinterpret_cast(defaultValue)); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + // We must verify that the pointer has the right size and potentially upgrade it if not. + + WirePointer* oldRef = origRef; + SegmentBuilder* oldSegment = origSegment; + word* oldPtr = followFars(oldRef, origRefTarget, oldSegment); + + KJ_REQUIRE(oldRef->kind() == WirePointer::LIST, + "Called getList{Field,Element}() but existing pointer is not a list.") { + goto useDefault; + } + + ElementSize oldSize = oldRef->listRef.elementSize(); + + if (oldSize == ElementSize::INLINE_COMPOSITE) { + // Existing list is INLINE_COMPOSITE, but we need to verify that the sizes match. + + WirePointer* oldTag = reinterpret_cast(oldPtr); + oldPtr += POINTER_SIZE_IN_WORDS; + KJ_REQUIRE(oldTag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE list with non-STRUCT elements not supported.") { + goto useDefault; + } + + auto oldDataSize = oldTag->structRef.dataSize.get(); + auto oldPointerCount = oldTag->structRef.ptrCount.get(); + auto oldStep = (oldDataSize + oldPointerCount * WORDS_PER_POINTER) / ELEMENTS; + + auto elementCount = oldTag->inlineCompositeListElementCount(); + + if (oldDataSize >= elementSize.data && oldPointerCount >= elementSize.pointers) { + // Old size is at least as large as we need. Ship it. + return ListBuilder(oldSegment, capTable, oldPtr, oldStep * BITS_PER_WORD, elementCount, + oldDataSize * BITS_PER_WORD, oldPointerCount, + ElementSize::INLINE_COMPOSITE); + } + + // The structs in this list are smaller than expected, probably written using an older + // version of the protocol. We need to make a copy and expand them. + + auto newDataSize = kj::max(oldDataSize, elementSize.data); + auto newPointerCount = kj::max(oldPointerCount, elementSize.pointers); + auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS; + + auto totalSize = assertMax() - 1>( + newStep * upgradeBound(elementCount), + []() { KJ_FAIL_REQUIRE("total size of struct list is larger than max segment size"); }); + + // Don't let allocate() zero out the object just yet. + zeroPointerAndFars(origSegment, origRef); + + word* newPtr = allocate(origRef, origSegment, capTable, totalSize + POINTER_SIZE_IN_WORDS, + WirePointer::LIST, orphanArena); + origRef->listRef.setInlineComposite(totalSize); + + WirePointer* newTag = reinterpret_cast(newPtr); + newTag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, elementCount); + newTag->structRef.set(newDataSize, newPointerCount); + newPtr += POINTER_SIZE_IN_WORDS; + + word* src = oldPtr; + word* dst = newPtr; + for (auto i KJ_UNUSED: kj::zeroTo(elementCount)) { + // Copy data section. + copyMemory(dst, src, oldDataSize); + + // Copy pointer section. + WirePointer* newPointerSection = reinterpret_cast(dst + newDataSize); + WirePointer* oldPointerSection = reinterpret_cast(src + oldDataSize); + for (auto j: kj::zeroTo(oldPointerCount)) { + transferPointer(origSegment, newPointerSection + j, oldSegment, oldPointerSection + j); + } + + dst += newStep * (ONE * ELEMENTS); + src += oldStep * (ONE * ELEMENTS); + } + + auto oldSize = assertMax() - 1>( + oldStep * upgradeBound(elementCount), + []() { KJ_FAIL_ASSERT("old size overflows but new size doesn't?"); }); + + // Zero out old location. See explanation in getWritableStructPointer(). + // Make sure to include the tag word. + zeroMemory(oldPtr - POINTER_SIZE_IN_WORDS, oldSize + POINTER_SIZE_IN_WORDS); + + return ListBuilder(origSegment, capTable, newPtr, newStep * BITS_PER_WORD, elementCount, + newDataSize * BITS_PER_WORD, newPointerCount, + ElementSize::INLINE_COMPOSITE); + } else { + // We're upgrading from a non-struct list. + + auto oldDataSize = dataBitsPerElement(oldSize) * ELEMENTS; + auto oldPointerCount = pointersPerElement(oldSize) * ELEMENTS; + auto oldStep = (oldDataSize + oldPointerCount * BITS_PER_POINTER) / ELEMENTS; + auto elementCount = oldRef->listRef.elementCount(); + + if (oldSize == ElementSize::VOID) { + // Nothing to copy, just allocate a new list. + return initStructListPointer(origRef, origSegment, capTable, elementCount, elementSize); + } else { + // Upgrading to an inline composite list. + + KJ_REQUIRE(oldSize != ElementSize::BIT, + "Found bit list where struct list was expected; upgrading boolean lists to structs " + "is no longer supported.") { + goto useDefault; + } + + auto newDataSize = elementSize.data; + auto newPointerCount = elementSize.pointers; + + if (oldSize == ElementSize::POINTER) { + newPointerCount = kj::max(newPointerCount, ONE * POINTERS); + } else { + // Old list contains data elements, so we need at least 1 word of data. + newDataSize = kj::max(newDataSize, ONE * WORDS); + } + + auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS; + auto totalWords = assertMax() - 1>( + newStep * upgradeBound(elementCount), + []() {KJ_FAIL_REQUIRE("total size of struct list is larger than max segment size");}); + + // Don't let allocate() zero out the object just yet. + zeroPointerAndFars(origSegment, origRef); + + word* newPtr = allocate(origRef, origSegment, capTable, totalWords + POINTER_SIZE_IN_WORDS, + WirePointer::LIST, orphanArena); + origRef->listRef.setInlineComposite(totalWords); + + WirePointer* tag = reinterpret_cast(newPtr); + tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, elementCount); + tag->structRef.set(newDataSize, newPointerCount); + newPtr += POINTER_SIZE_IN_WORDS; + + if (oldSize == ElementSize::POINTER) { + WirePointer* dst = reinterpret_cast(newPtr + newDataSize); + WirePointer* src = reinterpret_cast(oldPtr); + for (auto i KJ_UNUSED: kj::zeroTo(elementCount)) { + transferPointer(origSegment, dst, oldSegment, src); + dst += newStep / WORDS_PER_POINTER * (ONE * ELEMENTS); + ++src; + } + } else { + byte* dst = reinterpret_cast(newPtr); + byte* src = reinterpret_cast(oldPtr); + auto newByteStep = newStep * (ONE * ELEMENTS) * BYTES_PER_WORD; + auto oldByteStep = oldDataSize / BITS_PER_BYTE; + for (auto i KJ_UNUSED: kj::zeroTo(elementCount)) { + copyMemory(dst, src, oldByteStep); + src += oldByteStep; + dst += newByteStep; + } + } + + auto oldSize = assertMax() - 1>( + roundBitsUpToWords(oldStep * upgradeBound(elementCount)), + []() { KJ_FAIL_ASSERT("old size overflows but new size doesn't?"); }); + + // Zero out old location. See explanation in getWritableStructPointer(). + zeroMemory(oldPtr, oldSize); + + return ListBuilder(origSegment, capTable, newPtr, newStep * BITS_PER_WORD, elementCount, + newDataSize * BITS_PER_WORD, newPointerCount, + ElementSize::INLINE_COMPOSITE); + } + } + } + + static KJ_ALWAYS_INLINE(SegmentAnd initTextPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, TextSize size, + BuilderArena* orphanArena = nullptr)) { + // The byte list must include a NUL terminator. + auto byteSize = size + ONE * BYTES; + + // Allocate the space. + word* ptr = allocate( + ref, segment, capTable, roundBytesUpToWords(byteSize), WirePointer::LIST, orphanArena); + + // Initialize the pointer. + ref->listRef.set(ElementSize::BYTE, byteSize * (ONE * ELEMENTS / BYTES)); + + // Build the Text::Builder. This will initialize the NUL terminator. + return { segment, Text::Builder(reinterpret_cast(ptr), unbound(size / BYTES)) }; + } + + static KJ_ALWAYS_INLINE(SegmentAnd setTextPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, Text::Reader value, + BuilderArena* orphanArena = nullptr)) { + TextSize size = assertMax(bounded(value.size()), + []() { KJ_FAIL_REQUIRE("text blob too big"); }) * BYTES; + + auto allocation = initTextPointer(ref, segment, capTable, size, orphanArena); + copyMemory(allocation.value.begin(), value); + return allocation; + } + + static KJ_ALWAYS_INLINE(Text::Builder getWritableTextPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, + const void* defaultValue, TextSize defaultSize)) { + return getWritableTextPointer(ref, ref->target(), segment,capTable, defaultValue, defaultSize); + } + + static KJ_ALWAYS_INLINE(Text::Builder getWritableTextPointer( + WirePointer* ref, word* refTarget, SegmentBuilder* segment, CapTableBuilder* capTable, + const void* defaultValue, TextSize defaultSize)) { + if (ref->isNull()) { + useDefault: + if (defaultSize == ZERO * BYTES) { + return nullptr; + } else { + Text::Builder builder = initTextPointer(ref, segment, capTable, defaultSize).value; + copyMemory(builder.asBytes().begin(), reinterpret_cast(defaultValue), + defaultSize); + return builder; + } + } else { + word* ptr = followFars(ref, refTarget, segment); + byte* bptr = reinterpret_cast(ptr); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Called getText{Field,Element}() but existing pointer is not a list.") { + goto useDefault; + } + KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE, + "Called getText{Field,Element}() but existing list pointer is not byte-sized.") { + goto useDefault; + } + + auto maybeSize = trySubtract(ref->listRef.elementCount() * (ONE * BYTES / ELEMENTS), + ONE * BYTES); + KJ_IF_MAYBE(size, maybeSize) { + KJ_REQUIRE(*(bptr + *size) == '\0', "Text blob missing NUL terminator.") { + goto useDefault; + } + + return Text::Builder(reinterpret_cast(bptr), unbound(*size / BYTES)); + } else { + KJ_FAIL_REQUIRE("zero-size blob can't be text (need NUL terminator)") { + goto useDefault; + }; + } + } + } + + static KJ_ALWAYS_INLINE(SegmentAnd initDataPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, BlobSize size, + BuilderArena* orphanArena = nullptr)) { + // Allocate the space. + word* ptr = allocate(ref, segment, capTable, roundBytesUpToWords(size), + WirePointer::LIST, orphanArena); + + // Initialize the pointer. + ref->listRef.set(ElementSize::BYTE, size * (ONE * ELEMENTS / BYTES)); + + // Build the Data::Builder. + return { segment, Data::Builder(reinterpret_cast(ptr), unbound(size / BYTES)) }; + } + + static KJ_ALWAYS_INLINE(SegmentAnd setDataPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, Data::Reader value, + BuilderArena* orphanArena = nullptr)) { + BlobSize size = assertMaxBits(bounded(value.size()), + []() { KJ_FAIL_REQUIRE("text blob too big"); }) * BYTES; + + auto allocation = initDataPointer(ref, segment, capTable, size, orphanArena); + copyMemory(allocation.value.begin(), value); + return allocation; + } + + static KJ_ALWAYS_INLINE(Data::Builder getWritableDataPointer( + WirePointer* ref, SegmentBuilder* segment, CapTableBuilder* capTable, + const void* defaultValue, BlobSize defaultSize)) { + return getWritableDataPointer(ref, ref->target(), segment, capTable, defaultValue, defaultSize); + } + + static KJ_ALWAYS_INLINE(Data::Builder getWritableDataPointer( + WirePointer* ref, word* refTarget, SegmentBuilder* segment, CapTableBuilder* capTable, + const void* defaultValue, BlobSize defaultSize)) { + if (ref->isNull()) { + useDefault: + if (defaultSize == ZERO * BYTES) { + return nullptr; + } else { + Data::Builder builder = initDataPointer(ref, segment, capTable, defaultSize).value; + copyMemory(builder.begin(), reinterpret_cast(defaultValue), defaultSize); + return builder; + } + } else { + word* ptr = followFars(ref, refTarget, segment); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Called getData{Field,Element}() but existing pointer is not a list.") { + goto useDefault; + } + KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE, + "Called getData{Field,Element}() but existing list pointer is not byte-sized.") { + goto useDefault; + } + + return Data::Builder(reinterpret_cast(ptr), + unbound(ref->listRef.elementCount() / ELEMENTS)); + } + } + + static SegmentAnd setStructPointer( + SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* ref, StructReader value, + BuilderArena* orphanArena = nullptr, bool canonical = false) { + auto dataSize = roundBitsUpToBytes(value.dataSize); + auto ptrCount = value.pointerCount; + + if (canonical) { + // StructReaders should not have bitwidths other than 1, but let's be safe + KJ_REQUIRE((value.dataSize == ONE * BITS) + || (value.dataSize % BITS_PER_BYTE == ZERO * BITS)); + + if (value.dataSize == ONE * BITS) { + // Handle the truncation case where it's a false in a 1-bit struct + if (!value.getDataField(ZERO * ELEMENTS)) { + dataSize = ZERO * BYTES; + } + } else { + // Truncate the data section + auto data = value.getDataSectionAsBlob(); + auto end = data.end(); + while (end > data.begin() && end[-1] == 0) --end; + dataSize = intervalLength(data.begin(), end, MAX_STUCT_DATA_WORDS * BYTES_PER_WORD); + } + + // Truncate pointer section + const WirePointer* ptr = value.pointers + ptrCount; + while (ptr > value.pointers && ptr[-1].isNull()) --ptr; + ptrCount = intervalLength(value.pointers, ptr, MAX_STRUCT_POINTER_COUNT); + } + + auto dataWords = roundBytesUpToWords(dataSize); + + auto totalSize = dataWords + ptrCount * WORDS_PER_POINTER; + + word* ptr = allocate(ref, segment, capTable, totalSize, WirePointer::STRUCT, orphanArena); + ref->structRef.set(dataWords, ptrCount); + + if (value.dataSize == ONE * BITS) { + // Data size could be made 0 by truncation + if (dataSize != ZERO * BYTES) { + *reinterpret_cast(ptr) = value.getDataField(ZERO * ELEMENTS); + } + } else { + copyMemory(reinterpret_cast(ptr), + reinterpret_cast(value.data), + dataSize); + } + + WirePointer* pointerSection = reinterpret_cast(ptr + dataWords); + for (auto i: kj::zeroTo(ptrCount)) { + copyPointer(segment, capTable, pointerSection + i, + value.segment, value.capTable, value.pointers + i, + value.nestingLimit, nullptr, canonical); + } + + return { segment, ptr }; + } + +#if !CAPNP_LITE + static void setCapabilityPointer( + SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* ref, + kj::Own&& cap) { + if (!ref->isNull()) { + zeroObject(segment, capTable, ref); + } + if (cap->isNull()) { + zeroMemory(ref); + } else { + ref->setCap(capTable->injectCap(kj::mv(cap))); + } + } +#endif // !CAPNP_LITE + + static SegmentAnd setListPointer( + SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* ref, ListReader value, + BuilderArena* orphanArena = nullptr, bool canonical = false) { + auto totalSize = assertMax() - 1>( + roundBitsUpToWords(upgradeBound(value.elementCount) * value.step), + []() { KJ_FAIL_ASSERT("encountered impossibly long struct list ListReader"); }); + + if (value.elementSize != ElementSize::INLINE_COMPOSITE) { + // List of non-structs. + word* ptr = allocate(ref, segment, capTable, totalSize, WirePointer::LIST, orphanArena); + + if (value.elementSize == ElementSize::POINTER) { + // List of pointers. + ref->listRef.set(ElementSize::POINTER, value.elementCount); + for (auto i: kj::zeroTo(value.elementCount * (ONE * POINTERS / ELEMENTS))) { + copyPointer(segment, capTable, reinterpret_cast(ptr) + i, + value.segment, value.capTable, + reinterpret_cast(value.ptr) + i, + value.nestingLimit, nullptr, canonical); + } + } else { + // List of data. + ref->listRef.set(value.elementSize, value.elementCount); + + auto wholeByteSize = + assertMax(MAX_SEGMENT_WORDS * BYTES_PER_WORD, + upgradeBound(value.elementCount) * value.step / BITS_PER_BYTE, + []() { KJ_FAIL_ASSERT("encountered impossibly long data ListReader"); }); + copyMemory(reinterpret_cast(ptr), value.ptr, wholeByteSize); + auto leftoverBits = + (upgradeBound(value.elementCount) * value.step) % BITS_PER_BYTE; + if (leftoverBits > ZERO * BITS) { + // We need to copy a partial byte. + uint8_t mask = (1 << unbound(leftoverBits / BITS)) - 1; + *((reinterpret_cast(ptr)) + wholeByteSize) = mask & *(value.ptr + wholeByteSize); + } + } + + return { segment, ptr }; + } else { + // List of structs. + StructDataWordCount declDataSize = value.structDataSize / BITS_PER_WORD; + StructPointerCount declPointerCount = value.structPointerCount; + + StructDataWordCount dataSize = ZERO * WORDS; + StructPointerCount ptrCount = ZERO * POINTERS; + + if (canonical) { + for (auto i: kj::zeroTo(value.elementCount)) { + auto element = value.getStructElement(i); + + // Truncate the data section + auto data = element.getDataSectionAsBlob(); + auto end = data.end(); + while (end > data.begin() && end[-1] == 0) --end; + dataSize = kj::max(dataSize, roundBytesUpToWords( + intervalLength(data.begin(), end, MAX_STUCT_DATA_WORDS * BYTES_PER_WORD))); + + // Truncate pointer section + const WirePointer* ptr = element.pointers + element.pointerCount; + while (ptr > element.pointers && ptr[-1].isNull()) --ptr; + ptrCount = kj::max(ptrCount, + intervalLength(element.pointers, ptr, MAX_STRUCT_POINTER_COUNT)); + } + auto newTotalSize = (dataSize + upgradeBound(ptrCount) * WORDS_PER_POINTER) + / ELEMENTS * value.elementCount; + KJ_ASSERT(newTotalSize <= totalSize); // we've only removed data! + totalSize = assumeMax() - 1>(newTotalSize); + } else { + dataSize = declDataSize; + ptrCount = declPointerCount; + } + + KJ_DASSERT(value.structDataSize % BITS_PER_WORD == ZERO * BITS); + word* ptr = allocate(ref, segment, capTable, totalSize + POINTER_SIZE_IN_WORDS, + WirePointer::LIST, orphanArena); + ref->listRef.setInlineComposite(totalSize); + + WirePointer* tag = reinterpret_cast(ptr); + tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, value.elementCount); + tag->structRef.set(dataSize, ptrCount); + word* dst = ptr + POINTER_SIZE_IN_WORDS; + + const word* src = reinterpret_cast(value.ptr); + for (auto i KJ_UNUSED: kj::zeroTo(value.elementCount)) { + copyMemory(dst, src, dataSize); + dst += dataSize; + src += declDataSize; + + for (auto j: kj::zeroTo(ptrCount)) { + copyPointer(segment, capTable, reinterpret_cast(dst) + j, + value.segment, value.capTable, reinterpret_cast(src) + j, + value.nestingLimit, nullptr, canonical); + } + dst += ptrCount * WORDS_PER_POINTER; + src += declPointerCount * WORDS_PER_POINTER; + } + + return { segment, ptr }; + } + } + + static KJ_ALWAYS_INLINE(SegmentAnd copyPointer( + SegmentBuilder* dstSegment, CapTableBuilder* dstCapTable, WirePointer* dst, + SegmentReader* srcSegment, CapTableReader* srcCapTable, const WirePointer* src, + int nestingLimit, BuilderArena* orphanArena = nullptr, + bool canonical = false)) { + return copyPointer(dstSegment, dstCapTable, dst, + srcSegment, srcCapTable, src, src->target(srcSegment), + nestingLimit, orphanArena, canonical); + } + + static SegmentAnd copyPointer( + SegmentBuilder* dstSegment, CapTableBuilder* dstCapTable, WirePointer* dst, + SegmentReader* srcSegment, CapTableReader* srcCapTable, const WirePointer* src, + const word* srcTarget, int nestingLimit, + BuilderArena* orphanArena = nullptr, bool canonical = false) { + // Deep-copy the object pointed to by src into dst. It turns out we can't reuse + // readStructPointer(), etc. because they do type checking whereas here we want to accept any + // valid pointer. + + if (src->isNull()) { + useDefault: + if (!dst->isNull()) { + zeroObject(dstSegment, dstCapTable, dst); + zeroMemory(dst); + } + return { dstSegment, nullptr }; + } + + const word* ptr; + KJ_IF_MAYBE(p, WireHelpers::followFars(src, srcTarget, srcSegment)) { + ptr = p; + } else { + goto useDefault; + } + + switch (src->kind()) { + case WirePointer::STRUCT: + KJ_REQUIRE(nestingLimit > 0, + "Message is too deeply-nested or contains cycles. See capnp::ReaderOptions.") { + goto useDefault; + } + + KJ_REQUIRE(boundsCheck(srcSegment, ptr, src->structRef.wordSize()), + "Message contained out-of-bounds struct pointer.") { + goto useDefault; + } + return setStructPointer(dstSegment, dstCapTable, dst, + StructReader(srcSegment, srcCapTable, ptr, + reinterpret_cast(ptr + src->structRef.dataSize.get()), + src->structRef.dataSize.get() * BITS_PER_WORD, + src->structRef.ptrCount.get(), + nestingLimit - 1), + orphanArena, canonical); + + case WirePointer::LIST: { + ElementSize elementSize = src->listRef.elementSize(); + + KJ_REQUIRE(nestingLimit > 0, + "Message is too deeply-nested or contains cycles. See capnp::ReaderOptions.") { + goto useDefault; + } + + if (elementSize == ElementSize::INLINE_COMPOSITE) { + auto wordCount = src->listRef.inlineCompositeWordCount(); + const WirePointer* tag = reinterpret_cast(ptr); + + KJ_REQUIRE(boundsCheck(srcSegment, ptr, wordCount + POINTER_SIZE_IN_WORDS), + "Message contains out-of-bounds list pointer.") { + goto useDefault; + } + + ptr += POINTER_SIZE_IN_WORDS; + + KJ_REQUIRE(tag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") { + goto useDefault; + } + + auto elementCount = tag->inlineCompositeListElementCount(); + auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS; + + KJ_REQUIRE(wordsPerElement * upgradeBound(elementCount) <= wordCount, + "INLINE_COMPOSITE list's elements overrun its word count.") { + goto useDefault; + } + + if (wordsPerElement * (ONE * ELEMENTS) == ZERO * WORDS) { + // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large + // without having sent actual data. + KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (ONE * WORDS / ELEMENTS)), + "Message contains amplified list pointer.") { + goto useDefault; + } + } + + return setListPointer(dstSegment, dstCapTable, dst, + ListReader(srcSegment, srcCapTable, ptr, + elementCount, wordsPerElement * BITS_PER_WORD, + tag->structRef.dataSize.get() * BITS_PER_WORD, + tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE, + nestingLimit - 1), + orphanArena, canonical); + } else { + auto dataSize = dataBitsPerElement(elementSize) * ELEMENTS; + auto pointerCount = pointersPerElement(elementSize) * ELEMENTS; + auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; + auto elementCount = src->listRef.elementCount(); + auto wordCount = roundBitsUpToWords(upgradeBound(elementCount) * step); + + KJ_REQUIRE(boundsCheck(srcSegment, ptr, wordCount), + "Message contains out-of-bounds list pointer.") { + goto useDefault; + } + + if (elementSize == ElementSize::VOID) { + // Watch out for lists of void, which can claim to be arbitrarily large without having + // sent actual data. + KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (ONE * WORDS / ELEMENTS)), + "Message contains amplified list pointer.") { + goto useDefault; + } + } + + return setListPointer(dstSegment, dstCapTable, dst, + ListReader(srcSegment, srcCapTable, ptr, elementCount, step, dataSize, pointerCount, + elementSize, nestingLimit - 1), + orphanArena, canonical); + } + } + + case WirePointer::FAR: + KJ_FAIL_REQUIRE("Unexpected FAR pointer.") { + goto useDefault; + } + + case WirePointer::OTHER: { + KJ_REQUIRE(src->isCapability(), "Unknown pointer type.") { + goto useDefault; + } + + if (canonical) { + KJ_FAIL_REQUIRE("Cannot create a canonical message with a capability") { + break; + } + } +#if !CAPNP_LITE + KJ_IF_MAYBE(cap, srcCapTable->extractCap(src->capRef.index.get())) { + setCapabilityPointer(dstSegment, dstCapTable, dst, kj::mv(*cap)); + // Return dummy non-null pointer so OrphanBuilder doesn't end up null. + return { dstSegment, reinterpret_cast(1) }; + } else { +#endif // !CAPNP_LITE + KJ_FAIL_REQUIRE("Message contained invalid capability pointer.") { + goto useDefault; + } +#if !CAPNP_LITE + } +#endif // !CAPNP_LITE + } + } + + KJ_UNREACHABLE; + } + + static void adopt(SegmentBuilder* segment, CapTableBuilder* capTable, + WirePointer* ref, OrphanBuilder&& value) { + KJ_REQUIRE(value.segment == nullptr || value.segment->getArena() == segment->getArena(), + "Adopted object must live in the same message."); + + if (!ref->isNull()) { + zeroObject(segment, capTable, ref); + } + + if (value == nullptr) { + // Set null. + zeroMemory(ref); + } else if (value.tagAsPtr()->isPositional()) { + WireHelpers::transferPointer(segment, ref, value.segment, value.tagAsPtr(), value.location); + } else { + // FAR and OTHER pointers are position-independent, so we can just copy. + copyMemory(ref, value.tagAsPtr()); + } + + // Take ownership away from the OrphanBuilder. + zeroMemory(value.tagAsPtr()); + value.location = nullptr; + value.segment = nullptr; + } + + static OrphanBuilder disown(SegmentBuilder* segment, CapTableBuilder* capTable, + WirePointer* ref) { + word* location; + + if (ref->isNull()) { + location = nullptr; + } else if (ref->kind() == WirePointer::OTHER) { + KJ_REQUIRE(ref->isCapability(), "Unknown pointer type.") { break; } + location = reinterpret_cast(1); // dummy so that it is non-null + } else { + WirePointer* refCopy = ref; + location = followFarsNoWritableCheck(refCopy, ref->target(), segment); + } + + OrphanBuilder result(ref, segment, capTable, location); + + if (!ref->isNull() && ref->isPositional()) { + result.tagAsPtr()->setKindForOrphan(ref->kind()); + } + + // Zero out the pointer that was disowned. + zeroMemory(ref); + + return result; + } + + // ----------------------------------------------------------------- + + static KJ_ALWAYS_INLINE(StructReader readStructPointer( + SegmentReader* segment, CapTableReader* capTable, + const WirePointer* ref, const word* defaultValue, + int nestingLimit)) { + return readStructPointer(segment, capTable, ref, ref->target(segment), + defaultValue, nestingLimit); + } + + static KJ_ALWAYS_INLINE(StructReader readStructPointer( + SegmentReader* segment, CapTableReader* capTable, + const WirePointer* ref, const word* refTarget, + const word* defaultValue, int nestingLimit)) { + if (ref->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return StructReader(); + } + segment = nullptr; + ref = reinterpret_cast(defaultValue); + refTarget = ref->target(segment); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + KJ_REQUIRE(nestingLimit > 0, + "Message is too deeply-nested or contains cycles. See capnp::ReaderOptions.") { + goto useDefault; + } + + const word* ptr; + KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) { + ptr = p; + } else { + goto useDefault; + } + + KJ_REQUIRE(ref->kind() == WirePointer::STRUCT, + "Message contains non-struct pointer where struct pointer was expected.") { + goto useDefault; + } + + KJ_REQUIRE(boundsCheck(segment, ptr, ref->structRef.wordSize()), + "Message contained out-of-bounds struct pointer.") { + goto useDefault; + } + + return StructReader( + segment, capTable, + ptr, reinterpret_cast(ptr + ref->structRef.dataSize.get()), + ref->structRef.dataSize.get() * BITS_PER_WORD, + ref->structRef.ptrCount.get(), + nestingLimit - 1); + } + +#if !CAPNP_LITE + static KJ_ALWAYS_INLINE(kj::Own readCapabilityPointer( + SegmentReader* segment, CapTableReader* capTable, + const WirePointer* ref, int nestingLimit)) { + kj::Maybe> maybeCap; + + KJ_REQUIRE(brokenCapFactory != nullptr, + "Trying to read capabilities without ever having created a capability context. " + "To read capabilities from a message, you must imbue it with CapReaderContext, or " + "use the Cap'n Proto RPC system."); + + if (ref->isNull()) { + return brokenCapFactory->newNullCap(); + } else if (!ref->isCapability()) { + KJ_FAIL_REQUIRE( + "Message contains non-capability pointer where capability pointer was expected.") { + break; + } + return brokenCapFactory->newBrokenCap( + "Calling capability extracted from a non-capability pointer."); + } else KJ_IF_MAYBE(cap, capTable->extractCap(ref->capRef.index.get())) { + return kj::mv(*cap); + } else { + KJ_FAIL_REQUIRE("Message contains invalid capability pointer.") { + break; + } + return brokenCapFactory->newBrokenCap("Calling invalid capability pointer."); + } + } +#endif // !CAPNP_LITE + + static KJ_ALWAYS_INLINE(ListReader readListPointer( + SegmentReader* segment, CapTableReader* capTable, + const WirePointer* ref, const word* defaultValue, + ElementSize expectedElementSize, int nestingLimit, bool checkElementSize = true)) { + return readListPointer(segment, capTable, ref, ref->target(segment), defaultValue, + expectedElementSize, nestingLimit, checkElementSize); + } + + static KJ_ALWAYS_INLINE(ListReader readListPointer( + SegmentReader* segment, CapTableReader* capTable, + const WirePointer* ref, const word* refTarget, + const word* defaultValue, ElementSize expectedElementSize, int nestingLimit, + bool checkElementSize = true)) { + if (ref->isNull()) { + useDefault: + if (defaultValue == nullptr || + reinterpret_cast(defaultValue)->isNull()) { + return ListReader(expectedElementSize); + } + segment = nullptr; + ref = reinterpret_cast(defaultValue); + refTarget = ref->target(segment); + defaultValue = nullptr; // If the default value is itself invalid, don't use it again. + } + + KJ_REQUIRE(nestingLimit > 0, + "Message is too deeply-nested or contains cycles. See capnp::ReaderOptions.") { + goto useDefault; + } + + const word* ptr; + KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) { + ptr = p; + } else { + goto useDefault; + } + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Message contains non-list pointer where list pointer was expected.") { + goto useDefault; + } + + ElementSize elementSize = ref->listRef.elementSize(); + if (elementSize == ElementSize::INLINE_COMPOSITE) { + auto wordCount = ref->listRef.inlineCompositeWordCount(); + + // An INLINE_COMPOSITE list points to a tag, which is formatted like a pointer. + const WirePointer* tag = reinterpret_cast(ptr); + + KJ_REQUIRE(boundsCheck(segment, ptr, wordCount + POINTER_SIZE_IN_WORDS), + "Message contains out-of-bounds list pointer.") { + goto useDefault; + } + + ptr += POINTER_SIZE_IN_WORDS; + + KJ_REQUIRE(tag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") { + goto useDefault; + } + + auto size = tag->inlineCompositeListElementCount(); + auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS; + + KJ_REQUIRE(upgradeBound(size) * wordsPerElement <= wordCount, + "INLINE_COMPOSITE list's elements overrun its word count.") { + goto useDefault; + } + + if (wordsPerElement * (ONE * ELEMENTS) == ZERO * WORDS) { + // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large + // without having sent actual data. + KJ_REQUIRE(amplifiedRead(segment, size * (ONE * WORDS / ELEMENTS)), + "Message contains amplified list pointer.") { + goto useDefault; + } + } + + if (checkElementSize) { + // If a struct list was not expected, then presumably a non-struct list was upgraded to a + // struct list. We need to manipulate the pointer to point at the first field of the + // struct. Together with the `step` field, this will allow the struct list to be accessed + // as if it were a primitive list without branching. + + // Check whether the size is compatible. + switch (expectedElementSize) { + case ElementSize::VOID: + break; + + case ElementSize::BIT: + KJ_FAIL_REQUIRE( + "Found struct list where bit list was expected; upgrading boolean lists to structs " + "is no longer supported.") { + goto useDefault; + } + break; + + case ElementSize::BYTE: + case ElementSize::TWO_BYTES: + case ElementSize::FOUR_BYTES: + case ElementSize::EIGHT_BYTES: + KJ_REQUIRE(tag->structRef.dataSize.get() > ZERO * WORDS, + "Expected a primitive list, but got a list of pointer-only structs.") { + goto useDefault; + } + break; + + case ElementSize::POINTER: + // We expected a list of pointers but got a list of structs. Assuming the first field + // in the struct is the pointer we were looking for, we want to munge the pointer to + // point at the first element's pointer section. + ptr += tag->structRef.dataSize.get(); + KJ_REQUIRE(tag->structRef.ptrCount.get() > ZERO * POINTERS, + "Expected a pointer list, but got a list of data-only structs.") { + goto useDefault; + } + break; + + case ElementSize::INLINE_COMPOSITE: + break; + } + } + + return ListReader( + segment, capTable, ptr, size, wordsPerElement * BITS_PER_WORD, + tag->structRef.dataSize.get() * BITS_PER_WORD, + tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE, + nestingLimit - 1); + + } else { + // This is a primitive or pointer list, but all such lists can also be interpreted as struct + // lists. We need to compute the data size and pointer count for such structs. + auto dataSize = dataBitsPerElement(ref->listRef.elementSize()) * ELEMENTS; + auto pointerCount = pointersPerElement(ref->listRef.elementSize()) * ELEMENTS; + auto elementCount = ref->listRef.elementCount(); + auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS; + + auto wordCount = roundBitsUpToWords(upgradeBound(elementCount) * step); + KJ_REQUIRE(boundsCheck(segment, ptr, wordCount), + "Message contains out-of-bounds list pointer.") { + goto useDefault; + } + + if (elementSize == ElementSize::VOID) { + // Watch out for lists of void, which can claim to be arbitrarily large without having sent + // actual data. + KJ_REQUIRE(amplifiedRead(segment, elementCount * (ONE * WORDS / ELEMENTS)), + "Message contains amplified list pointer.") { + goto useDefault; + } + } + + if (checkElementSize) { + if (elementSize == ElementSize::BIT && expectedElementSize != ElementSize::BIT) { + KJ_FAIL_REQUIRE( + "Found bit list where struct list was expected; upgrading boolean lists to structs " + "is no longer supported.") { + goto useDefault; + } + } + + // Verify that the elements are at least as large as the expected type. Note that if we + // expected INLINE_COMPOSITE, the expected sizes here will be zero, because bounds checking + // will be performed at field access time. So this check here is for the case where we + // expected a list of some primitive or pointer type. + + BitCount expectedDataBitsPerElement = + dataBitsPerElement(expectedElementSize) * ELEMENTS; + WirePointerCount expectedPointersPerElement = + pointersPerElement(expectedElementSize) * ELEMENTS; + + KJ_REQUIRE(expectedDataBitsPerElement <= dataSize, + "Message contained list with incompatible element type.") { + goto useDefault; + } + KJ_REQUIRE(expectedPointersPerElement <= pointerCount, + "Message contained list with incompatible element type.") { + goto useDefault; + } + } + + return ListReader(segment, capTable, ptr, elementCount, step, + dataSize, pointerCount, elementSize, nestingLimit - 1); + } + } + + static KJ_ALWAYS_INLINE(Text::Reader readTextPointer( + SegmentReader* segment, const WirePointer* ref, + const void* defaultValue, ByteCount defaultSize)) { + return readTextPointer(segment, ref, ref->target(segment), defaultValue, defaultSize); + } + + static KJ_ALWAYS_INLINE(Text::Reader readTextPointer( + SegmentReader* segment, const WirePointer* ref, const word* refTarget, + const void* defaultValue, ByteCount defaultSize)) { + if (ref->isNull()) { + useDefault: + if (defaultValue == nullptr) defaultValue = ""; + return Text::Reader(reinterpret_cast(defaultValue), + unbound(defaultSize / BYTES)); + } else { + const word* ptr; + KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) { + ptr = p; + } else { + goto useDefault; + } + + auto size = ref->listRef.elementCount() * (ONE * BYTES / ELEMENTS); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Message contains non-list pointer where text was expected.") { + goto useDefault; + } + + KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE, + "Message contains list pointer of non-bytes where text was expected.") { + goto useDefault; + } + + KJ_REQUIRE(boundsCheck(segment, ptr, roundBytesUpToWords(size)), + "Message contained out-of-bounds text pointer.") { + goto useDefault; + } + + KJ_REQUIRE(size > ZERO * BYTES, "Message contains text that is not NUL-terminated.") { + goto useDefault; + } + + const char* cptr = reinterpret_cast(ptr); + uint unboundedSize = unbound(size / BYTES) - 1; + + KJ_REQUIRE(cptr[unboundedSize] == '\0', "Message contains text that is not NUL-terminated.") { + goto useDefault; + } + + return Text::Reader(cptr, unboundedSize); + } + } + + static KJ_ALWAYS_INLINE(Data::Reader readDataPointer( + SegmentReader* segment, const WirePointer* ref, + const void* defaultValue, BlobSize defaultSize)) { + return readDataPointer(segment, ref, ref->target(segment), defaultValue, defaultSize); + } + + static KJ_ALWAYS_INLINE(Data::Reader readDataPointer( + SegmentReader* segment, const WirePointer* ref, const word* refTarget, + const void* defaultValue, BlobSize defaultSize)) { + if (ref->isNull()) { + useDefault: + return Data::Reader(reinterpret_cast(defaultValue), + unbound(defaultSize / BYTES)); + } else { + const word* ptr; + KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) { + ptr = p; + } else { + goto useDefault; + } + + if (KJ_UNLIKELY(ptr == nullptr)) { + // Already reported error. + goto useDefault; + } + + auto size = ref->listRef.elementCount() * (ONE * BYTES / ELEMENTS); + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, + "Message contains non-list pointer where data was expected.") { + goto useDefault; + } + + KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE, + "Message contains list pointer of non-bytes where data was expected.") { + goto useDefault; + } + + KJ_REQUIRE(boundsCheck(segment, ptr, roundBytesUpToWords(size)), + "Message contained out-of-bounds data pointer.") { + goto useDefault; + } + + return Data::Reader(reinterpret_cast(ptr), unbound(size / BYTES)); + } + } +}; + +// ======================================================================================= +// PointerBuilder + +StructBuilder PointerBuilder::initStruct(StructSize size) { + return WireHelpers::initStructPointer(pointer, segment, capTable, size); +} + +StructBuilder PointerBuilder::getStruct(StructSize size, const word* defaultValue) { + return WireHelpers::getWritableStructPointer(pointer, segment, capTable, size, defaultValue); +} + +ListBuilder PointerBuilder::initList(ElementSize elementSize, ElementCount elementCount) { + return WireHelpers::initListPointer(pointer, segment, capTable, elementCount, elementSize); +} + +ListBuilder PointerBuilder::initStructList(ElementCount elementCount, StructSize elementSize) { + return WireHelpers::initStructListPointer(pointer, segment, capTable, elementCount, elementSize); +} + +ListBuilder PointerBuilder::getList(ElementSize elementSize, const word* defaultValue) { + return WireHelpers::getWritableListPointer(pointer, segment, capTable, elementSize, defaultValue); +} + +ListBuilder PointerBuilder::getStructList(StructSize elementSize, const word* defaultValue) { + return WireHelpers::getWritableStructListPointer( + pointer, segment, capTable, elementSize, defaultValue); +} + +ListBuilder PointerBuilder::getListAnySize(const word* defaultValue) { + return WireHelpers::getWritableListPointerAnySize(pointer, segment, capTable, defaultValue); +} + +template <> +Text::Builder PointerBuilder::initBlob(ByteCount size) { + return WireHelpers::initTextPointer(pointer, segment, capTable, + assertMax(size, ThrowOverflow())).value; +} +template <> +void PointerBuilder::setBlob(Text::Reader value) { + WireHelpers::setTextPointer(pointer, segment, capTable, value); +} +template <> +Text::Builder PointerBuilder::getBlob(const void* defaultValue, ByteCount defaultSize) { + return WireHelpers::getWritableTextPointer(pointer, segment, capTable, defaultValue, + assertMax(defaultSize, ThrowOverflow())); +} + +template <> +Data::Builder PointerBuilder::initBlob(ByteCount size) { + return WireHelpers::initDataPointer(pointer, segment, capTable, + assertMaxBits(size, ThrowOverflow())).value; +} +template <> +void PointerBuilder::setBlob(Data::Reader value) { + WireHelpers::setDataPointer(pointer, segment, capTable, value); +} +template <> +Data::Builder PointerBuilder::getBlob(const void* defaultValue, ByteCount defaultSize) { + return WireHelpers::getWritableDataPointer(pointer, segment, capTable, defaultValue, + assertMaxBits(defaultSize, ThrowOverflow())); +} + +void PointerBuilder::setStruct(const StructReader& value, bool canonical) { + WireHelpers::setStructPointer(segment, capTable, pointer, value, nullptr, canonical); +} + +void PointerBuilder::setList(const ListReader& value, bool canonical) { + WireHelpers::setListPointer(segment, capTable, pointer, value, nullptr, canonical); +} + +#if !CAPNP_LITE +kj::Own PointerBuilder::getCapability() { + return WireHelpers::readCapabilityPointer( + segment, capTable, pointer, kj::maxValue); +} + +void PointerBuilder::setCapability(kj::Own&& cap) { + WireHelpers::setCapabilityPointer(segment, capTable, pointer, kj::mv(cap)); +} +#endif // !CAPNP_LITE + +void PointerBuilder::adopt(OrphanBuilder&& value) { + WireHelpers::adopt(segment, capTable, pointer, kj::mv(value)); +} + +OrphanBuilder PointerBuilder::disown() { + return WireHelpers::disown(segment, capTable, pointer); +} + +void PointerBuilder::clear() { + WireHelpers::zeroObject(segment, capTable, pointer); + WireHelpers::zeroMemory(pointer); +} + +PointerType PointerBuilder::getPointerType() const { + if(pointer->isNull()) { + return PointerType::NULL_; + } else { + WirePointer* ptr = pointer; + SegmentBuilder* sgmt = segment; + WireHelpers::followFars(ptr, ptr->target(), sgmt); + switch(ptr->kind()) { + case WirePointer::FAR: + KJ_FAIL_ASSERT("far pointer not followed?"); + case WirePointer::STRUCT: + return PointerType::STRUCT; + case WirePointer::LIST: + return PointerType::LIST; + case WirePointer::OTHER: + KJ_REQUIRE(ptr->isCapability(), "unknown pointer type"); + return PointerType::CAPABILITY; + } + KJ_UNREACHABLE; + } +} + +void PointerBuilder::transferFrom(PointerBuilder other) { + if (!pointer->isNull()) { + WireHelpers::zeroObject(segment, capTable, pointer); + WireHelpers::zeroMemory(pointer); + } + WireHelpers::transferPointer(segment, pointer, other.segment, other.pointer); + WireHelpers::zeroMemory(other.pointer); +} + +void PointerBuilder::copyFrom(PointerReader other, bool canonical) { + if (other.pointer == nullptr) { + if (!pointer->isNull()) { + WireHelpers::zeroObject(segment, capTable, pointer); + WireHelpers::zeroMemory(pointer); + } + } else { + WireHelpers::copyPointer(segment, capTable, pointer, + other.segment, other.capTable, other.pointer, other.nestingLimit, + nullptr, + canonical); + } +} + +PointerReader PointerBuilder::asReader() const { + return PointerReader(segment, capTable, pointer, kj::maxValue); +} + +BuilderArena* PointerBuilder::getArena() const { + return segment->getArena(); +} + +CapTableBuilder* PointerBuilder::getCapTable() { + return capTable; +} + +PointerBuilder PointerBuilder::imbue(CapTableBuilder* capTable) { + auto result = *this; + result.capTable = capTable; + return result; +} + +// ======================================================================================= +// PointerReader + +PointerReader PointerReader::getRoot(SegmentReader* segment, CapTableReader* capTable, + const word* location, int nestingLimit) { + KJ_REQUIRE(WireHelpers::boundsCheck(segment, location, POINTER_SIZE_IN_WORDS), + "Root location out-of-bounds.") { + location = nullptr; + } + + return PointerReader(segment, capTable, + reinterpret_cast(location), nestingLimit); +} + +StructReader PointerReader::getStruct(const word* defaultValue) const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readStructPointer(segment, capTable, ref, defaultValue, nestingLimit); +} + +ListReader PointerReader::getList(ElementSize expectedElementSize, const word* defaultValue) const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readListPointer( + segment, capTable, ref, defaultValue, expectedElementSize, nestingLimit); +} + +ListReader PointerReader::getListAnySize(const word* defaultValue) const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readListPointer( + segment, capTable, ref, defaultValue, ElementSize::VOID /* dummy */, nestingLimit, false); +} + +template <> +Text::Reader PointerReader::getBlob(const void* defaultValue, ByteCount defaultSize) const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readTextPointer(segment, ref, defaultValue, defaultSize); +} + +template <> +Data::Reader PointerReader::getBlob(const void* defaultValue, ByteCount defaultSize) const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readDataPointer(segment, ref, defaultValue, + assertMaxBits(defaultSize, ThrowOverflow())); +} + +#if !CAPNP_LITE +kj::Own PointerReader::getCapability() const { + const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer; + return WireHelpers::readCapabilityPointer(segment, capTable, ref, nestingLimit); +} +#endif // !CAPNP_LITE + +const word* PointerReader::getUnchecked() const { + KJ_REQUIRE(segment == nullptr, "getUncheckedPointer() only allowed on unchecked messages."); + return reinterpret_cast(pointer); +} + +MessageSizeCounts PointerReader::targetSize() const { + return pointer == nullptr ? MessageSizeCounts { ZERO * WORDS, 0 } + : WireHelpers::totalSize(segment, pointer, nestingLimit); +} + +PointerType PointerReader::getPointerType() const { + if(pointer == nullptr || pointer->isNull()) { + return PointerType::NULL_; + } else { + const WirePointer* ptr = pointer; + const word* refTarget = ptr->target(segment); + SegmentReader* sgmt = segment; + if (WireHelpers::followFars(ptr, refTarget, sgmt) == nullptr) return PointerType::NULL_; + switch(ptr->kind()) { + case WirePointer::FAR: + KJ_FAIL_ASSERT("far pointer not followed?") { return PointerType::NULL_; } + case WirePointer::STRUCT: + return PointerType::STRUCT; + case WirePointer::LIST: + return PointerType::LIST; + case WirePointer::OTHER: + KJ_REQUIRE(ptr->isCapability(), "unknown pointer type") { return PointerType::NULL_; } + return PointerType::CAPABILITY; + } + KJ_UNREACHABLE; + } +} + +kj::Maybe PointerReader::getArena() const { + return segment == nullptr ? nullptr : segment->getArena(); +} + +CapTableReader* PointerReader::getCapTable() { + return capTable; +} + +PointerReader PointerReader::imbue(CapTableReader* capTable) const { + auto result = *this; + result.capTable = capTable; + return result; +} + +bool PointerReader::isCanonical(const word **readHead) { + if (!this->pointer) { + // The pointer is null, so we are canonical and do not read + return true; + } + + if (!this->pointer->isPositional()) { + // The pointer is a FAR or OTHER pointer, and is non-canonical + return false; + } + + switch (this->getPointerType()) { + case PointerType::NULL_: + // The pointer is null, we are canonical and do not read + return true; + case PointerType::STRUCT: { + bool dataTrunc, ptrTrunc; + auto structReader = this->getStruct(nullptr); + if (structReader.getDataSectionSize() == ZERO * BITS && + structReader.getPointerSectionSize() == ZERO * POINTERS) { + return reinterpret_cast(this->pointer) == structReader.getLocation(); + } else { + return structReader.isCanonical(readHead, readHead, &dataTrunc, &ptrTrunc) && dataTrunc && ptrTrunc; + } + } + case PointerType::LIST: + return this->getListAnySize(nullptr).isCanonical(readHead, pointer); + case PointerType::CAPABILITY: + KJ_FAIL_ASSERT("Capabilities are not positional"); + } + KJ_UNREACHABLE; +} + +// ======================================================================================= +// StructBuilder + +void StructBuilder::clearAll() { + if (dataSize == ONE * BITS) { + setDataField(ONE * ELEMENTS, false); + } else { + WireHelpers::zeroMemory(reinterpret_cast(data), dataSize / BITS_PER_BYTE); + } + + for (auto i: kj::zeroTo(pointerCount)) { + WireHelpers::zeroObject(segment, capTable, pointers + i); + } + WireHelpers::zeroMemory(pointers, pointerCount); +} + +void StructBuilder::transferContentFrom(StructBuilder other) { + // Determine the amount of data the builders have in common. + auto sharedDataSize = kj::min(dataSize, other.dataSize); + + if (dataSize > sharedDataSize) { + // Since the target is larger than the source, make sure to zero out the extra bits that the + // source doesn't have. + if (dataSize == ONE * BITS) { + setDataField(ZERO * ELEMENTS, false); + } else { + byte* unshared = reinterpret_cast(data) + sharedDataSize / BITS_PER_BYTE; + // Note: this subtraction can't fail due to the if() above + WireHelpers::zeroMemory(unshared, + subtractChecked(dataSize, sharedDataSize, []() {}) / BITS_PER_BYTE); + } + } + + // Copy over the shared part. + if (sharedDataSize == ONE * BITS) { + setDataField(ZERO * ELEMENTS, other.getDataField(ZERO * ELEMENTS)); + } else { + WireHelpers::copyMemory(reinterpret_cast(data), + reinterpret_cast(other.data), + sharedDataSize / BITS_PER_BYTE); + } + + // Zero out all pointers in the target. + for (auto i: kj::zeroTo(pointerCount)) { + WireHelpers::zeroObject(segment, capTable, pointers + i); + } + WireHelpers::zeroMemory(pointers, pointerCount); + + // Transfer the pointers. + auto sharedPointerCount = kj::min(pointerCount, other.pointerCount); + for (auto i: kj::zeroTo(sharedPointerCount)) { + WireHelpers::transferPointer(segment, pointers + i, other.segment, other.pointers + i); + } + + // Zero out the pointers that were transferred in the source because it no longer has ownership. + // If the source had any extra pointers that the destination didn't have space for, we + // intentionally leave them be, so that they'll be cleaned up later. + WireHelpers::zeroMemory(other.pointers, sharedPointerCount); +} + +void StructBuilder::copyContentFrom(StructReader other) { + // Determine the amount of data the builders have in common. + auto sharedDataSize = kj::min(dataSize, other.dataSize); + + if (dataSize > sharedDataSize) { + // Since the target is larger than the source, make sure to zero out the extra bits that the + // source doesn't have. + if (dataSize == ONE * BITS) { + setDataField(ZERO * ELEMENTS, false); + } else { + byte* unshared = reinterpret_cast(data) + sharedDataSize / BITS_PER_BYTE; + WireHelpers::zeroMemory(unshared, + subtractChecked(dataSize, sharedDataSize, []() {}) / BITS_PER_BYTE); + } + } + + // Copy over the shared part. + if (sharedDataSize == ONE * BITS) { + setDataField(ZERO * ELEMENTS, other.getDataField(ZERO * ELEMENTS)); + } else { + WireHelpers::copyMemory(reinterpret_cast(data), + reinterpret_cast(other.data), + sharedDataSize / BITS_PER_BYTE); + } + + // Zero out all pointers in the target. + for (auto i: kj::zeroTo(pointerCount)) { + WireHelpers::zeroObject(segment, capTable, pointers + i); + } + WireHelpers::zeroMemory(pointers, pointerCount); + + // Copy the pointers. + auto sharedPointerCount = kj::min(pointerCount, other.pointerCount); + for (auto i: kj::zeroTo(sharedPointerCount)) { + WireHelpers::copyPointer(segment, capTable, pointers + i, + other.segment, other.capTable, other.pointers + i, other.nestingLimit); + } +} + +StructReader StructBuilder::asReader() const { + return StructReader(segment, capTable, data, pointers, + dataSize, pointerCount, kj::maxValue); +} + +BuilderArena* StructBuilder::getArena() { + return segment->getArena(); +} + +CapTableBuilder* StructBuilder::getCapTable() { + return capTable; +} + +StructBuilder StructBuilder::imbue(CapTableBuilder* capTable) { + auto result = *this; + result.capTable = capTable; + return result; +} + +// ======================================================================================= +// StructReader + +MessageSizeCounts StructReader::totalSize() const { + MessageSizeCounts result = { + WireHelpers::roundBitsUpToWords(dataSize) + pointerCount * WORDS_PER_POINTER, 0 }; + + for (auto i: kj::zeroTo(pointerCount)) { + result += WireHelpers::totalSize(segment, pointers + i, nestingLimit); + } + + if (segment != nullptr) { + // This traversal should not count against the read limit, because it's highly likely that + // the caller is going to traverse the object again, e.g. to copy it. + segment->unread(result.wordCount); + } + + return result; +} + +kj::Array StructReader::canonicalize() { + auto size = totalSize().wordCount + POINTER_SIZE_IN_WORDS; + kj::Array backing = kj::heapArray(unbound(size / WORDS)); + WireHelpers::zeroMemory(backing.asPtr()); + FlatMessageBuilder builder(backing); + _::PointerHelpers::getInternalBuilder(builder.initRoot()).setStruct(*this, true); + KJ_ASSERT(builder.isCanonical()); + auto output = builder.getSegmentsForOutput()[0]; + kj::Array trunc = kj::heapArray(output.size()); + WireHelpers::copyMemory(trunc.begin(), output); + return trunc; +} + +CapTableReader* StructReader::getCapTable() { + return capTable; +} + +StructReader StructReader::imbue(CapTableReader* capTable) const { + auto result = *this; + result.capTable = capTable; + return result; +} + +bool StructReader::isCanonical(const word **readHead, + const word **ptrHead, + bool *dataTrunc, + bool *ptrTrunc) { + if (this->getLocation() != *readHead) { + // Our target area is not at the readHead, preorder fails + return false; + } + + if (this->getDataSectionSize() % BITS_PER_WORD != ZERO * BITS) { + // Using legacy non-word-size structs, reject + return false; + } + auto dataSize = this->getDataSectionSize() / BITS_PER_WORD; + + // Mark whether the struct is properly truncated + KJ_IF_MAYBE(diff, trySubtract(dataSize, ONE * WORDS)) { + *dataTrunc = this->getDataField(*diff / WORDS * ELEMENTS) != 0; + } else { + // Data segment empty. + *dataTrunc = true; + } + + KJ_IF_MAYBE(diff, trySubtract(this->pointerCount, ONE * POINTERS)) { + *ptrTrunc = !this->getPointerField(*diff).isNull(); + } else { + *ptrTrunc = true; + } + + // Advance the read head + *readHead += (dataSize + (this->pointerCount * WORDS_PER_POINTER)); + + // Check each pointer field for canonicity + for (auto ptrIndex: kj::zeroTo(this->pointerCount)) { + if (!this->getPointerField(ptrIndex).isCanonical(ptrHead)) { + return false; + } + } + + return true; +} + +// ======================================================================================= +// ListBuilder + +Text::Builder ListBuilder::asText() { + KJ_REQUIRE(structDataSize == G(8) * BITS && structPointerCount == ZERO * POINTERS, + "Expected Text, got list of non-bytes.") { + return Text::Builder(); + } + + size_t size = unbound(elementCount / ELEMENTS); + + KJ_REQUIRE(size > 0, "Message contains text that is not NUL-terminated.") { + return Text::Builder(); + } + + char* cptr = reinterpret_cast(ptr); + --size; // NUL terminator + + KJ_REQUIRE(cptr[size] == '\0', "Message contains text that is not NUL-terminated.") { + return Text::Builder(); + } + + return Text::Builder(cptr, size); +} + +Data::Builder ListBuilder::asData() { + KJ_REQUIRE(structDataSize == G(8) * BITS && structPointerCount == ZERO * POINTERS, + "Expected Text, got list of non-bytes.") { + return Data::Builder(); + } + + return Data::Builder(reinterpret_cast(ptr), unbound(elementCount / ELEMENTS)); +} + +StructBuilder ListBuilder::getStructElement(ElementCount index) { + auto indexBit = upgradeBound(index) * step; + byte* structData = ptr + indexBit / BITS_PER_BYTE; + KJ_DASSERT(indexBit % BITS_PER_BYTE == ZERO * BITS); + return StructBuilder(segment, capTable, structData, + reinterpret_cast(structData + structDataSize / BITS_PER_BYTE), + structDataSize, structPointerCount); +} + +ListReader ListBuilder::asReader() const { + return ListReader(segment, capTable, ptr, elementCount, step, structDataSize, structPointerCount, + elementSize, kj::maxValue); +} + +BuilderArena* ListBuilder::getArena() { + return segment->getArena(); +} + +CapTableBuilder* ListBuilder::getCapTable() { + return capTable; +} + +ListBuilder ListBuilder::imbue(CapTableBuilder* capTable) { + auto result = *this; + result.capTable = capTable; + return result; +} + +// ======================================================================================= +// ListReader + +Text::Reader ListReader::asText() { + KJ_REQUIRE(structDataSize == G(8) * BITS && structPointerCount == ZERO * POINTERS, + "Expected Text, got list of non-bytes.") { + return Text::Reader(); + } + + size_t size = unbound(elementCount / ELEMENTS); + + KJ_REQUIRE(size > 0, "Message contains text that is not NUL-terminated.") { + return Text::Reader(); + } + + const char* cptr = reinterpret_cast(ptr); + --size; // NUL terminator + + KJ_REQUIRE(cptr[size] == '\0', "Message contains text that is not NUL-terminated.") { + return Text::Reader(); + } + + return Text::Reader(cptr, size); +} + +Data::Reader ListReader::asData() { + KJ_REQUIRE(structDataSize == G(8) * BITS && structPointerCount == ZERO * POINTERS, + "Expected Text, got list of non-bytes.") { + return Data::Reader(); + } + + return Data::Reader(reinterpret_cast(ptr), unbound(elementCount / ELEMENTS)); +} + +kj::ArrayPtr ListReader::asRawBytes() { + KJ_REQUIRE(structPointerCount == ZERO * POINTERS, + "Expected data only, got pointers.") { + return kj::ArrayPtr(); + } + + return arrayPtr(reinterpret_cast(ptr), + WireHelpers::roundBitsUpToBytes( + upgradeBound(elementCount) * (structDataSize / ELEMENTS))); +} + +StructReader ListReader::getStructElement(ElementCount index) const { + KJ_REQUIRE(nestingLimit > 0, + "Message is too deeply-nested or contains cycles. See capnp::ReaderOptions.") { + return StructReader(); + } + + auto indexBit = upgradeBound(index) * step; + const byte* structData = ptr + indexBit / BITS_PER_BYTE; + const WirePointer* structPointers = + reinterpret_cast(structData + structDataSize / BITS_PER_BYTE); + + // This check should pass if there are no bugs in the list pointer validation code. + KJ_DASSERT(structPointerCount == ZERO * POINTERS || + (uintptr_t)structPointers % sizeof(void*) == 0, + "Pointer section of struct list element not aligned."); + + KJ_DASSERT(indexBit % BITS_PER_BYTE == ZERO * BITS); + return StructReader( + segment, capTable, structData, structPointers, + structDataSize, structPointerCount, + nestingLimit - 1); +} + +CapTableReader* ListReader::getCapTable() { + return capTable; +} + +ListReader ListReader::imbue(CapTableReader* capTable) const { + auto result = *this; + result.capTable = capTable; + return result; +} + +bool ListReader::isCanonical(const word **readHead, const WirePointer *ref) { + switch (this->getElementSize()) { + case ElementSize::INLINE_COMPOSITE: { + *readHead += 1; + if (reinterpret_cast(this->ptr) != *readHead) { + // The next word to read is the tag word, but the pointer is in + // front of it, so our check is slightly different + return false; + } + if (this->structDataSize % BITS_PER_WORD != ZERO * BITS) { + return false; + } + auto elementSize = StructSize(this->structDataSize / BITS_PER_WORD, + this->structPointerCount).total() / ELEMENTS; + auto totalSize = upgradeBound(this->elementCount) * elementSize; + if (totalSize != ref->listRef.inlineCompositeWordCount()) { + return false; + } + if (elementSize == ZERO * WORDS / ELEMENTS) { + return true; + } + auto listEnd = *readHead + totalSize; + auto pointerHead = listEnd; + bool listDataTrunc = false; + bool listPtrTrunc = false; + for (auto ec: kj::zeroTo(this->elementCount)) { + bool dataTrunc, ptrTrunc; + if (!this->getStructElement(ec).isCanonical(readHead, + &pointerHead, + &dataTrunc, + &ptrTrunc)) { + return false; + } + listDataTrunc |= dataTrunc; + listPtrTrunc |= ptrTrunc; + } + KJ_REQUIRE(*readHead == listEnd, *readHead, listEnd); + *readHead = pointerHead; + return listDataTrunc && listPtrTrunc; + } + case ElementSize::POINTER: { + if (reinterpret_cast(this->ptr) != *readHead) { + return false; + } + *readHead += this->elementCount * (POINTERS / ELEMENTS) * WORDS_PER_POINTER; + for (auto ec: kj::zeroTo(this->elementCount)) { + if (!this->getPointerElement(ec).isCanonical(readHead)) { + return false; + } + } + return true; + } + default: { + if (reinterpret_cast(this->ptr) != *readHead) { + return false; + } + + auto bitSize = upgradeBound(this->elementCount) * + dataBitsPerElement(this->elementSize); + auto truncatedByteSize = bitSize / BITS_PER_BYTE; + auto byteReadHead = reinterpret_cast(*readHead) + truncatedByteSize; + auto readHeadEnd = *readHead + WireHelpers::roundBitsUpToWords(bitSize); + + auto leftoverBits = bitSize % BITS_PER_BYTE; + if (leftoverBits > ZERO * BITS) { + auto mask = ~((1 << unbound(leftoverBits / BITS)) - 1); + + if (mask & *byteReadHead) { + return false; + } + byteReadHead += 1; + } + + while (byteReadHead != reinterpret_cast(readHeadEnd)) { + if (*byteReadHead != 0) { + return false; + } + byteReadHead += 1; + } + + *readHead = readHeadEnd; + return true; + } + } + KJ_UNREACHABLE; +} + +// ======================================================================================= +// OrphanBuilder + +OrphanBuilder OrphanBuilder::initStruct( + BuilderArena* arena, CapTableBuilder* capTable, StructSize size) { + OrphanBuilder result; + StructBuilder builder = WireHelpers::initStructPointer( + result.tagAsPtr(), nullptr, capTable, size, arena); + result.segment = builder.segment; + result.capTable = capTable; + result.location = builder.getLocation(); + return result; +} + +OrphanBuilder OrphanBuilder::initList( + BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, ElementSize elementSize) { + OrphanBuilder result; + ListBuilder builder = WireHelpers::initListPointer( + result.tagAsPtr(), nullptr, capTable, elementCount, elementSize, arena); + result.segment = builder.segment; + result.capTable = capTable; + result.location = builder.getLocation(); + return result; +} + +OrphanBuilder OrphanBuilder::initStructList( + BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, StructSize elementSize) { + OrphanBuilder result; + ListBuilder builder = WireHelpers::initStructListPointer( + result.tagAsPtr(), nullptr, capTable, elementCount, elementSize, arena); + result.segment = builder.segment; + result.capTable = capTable; + result.location = builder.getLocation(); + return result; +} + +OrphanBuilder OrphanBuilder::initText( + BuilderArena* arena, CapTableBuilder* capTable, ByteCount size) { + OrphanBuilder result; + auto allocation = WireHelpers::initTextPointer(result.tagAsPtr(), nullptr, capTable, + assertMax(size, ThrowOverflow()), arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value.begin()); + return result; +} + +OrphanBuilder OrphanBuilder::initData( + BuilderArena* arena, CapTableBuilder* capTable, ByteCount size) { + OrphanBuilder result; + auto allocation = WireHelpers::initDataPointer(result.tagAsPtr(), nullptr, capTable, + assertMaxBits(size), arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value.begin()); + return result; +} + +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom) { + OrphanBuilder result; + auto allocation = WireHelpers::setStructPointer( + nullptr, capTable, result.tagAsPtr(), copyFrom, arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value); + return result; +} + +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom) { + OrphanBuilder result; + auto allocation = WireHelpers::setListPointer( + nullptr, capTable, result.tagAsPtr(), copyFrom, arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value); + return result; +} + +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom) { + OrphanBuilder result; + auto allocation = WireHelpers::copyPointer( + nullptr, capTable, result.tagAsPtr(), + copyFrom.segment, copyFrom.capTable, copyFrom.pointer, copyFrom.nestingLimit, arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value); + return result; +} + +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom) { + OrphanBuilder result; + auto allocation = WireHelpers::setTextPointer( + result.tagAsPtr(), nullptr, capTable, copyFrom, arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value.begin()); + return result; +} + +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom) { + OrphanBuilder result; + auto allocation = WireHelpers::setDataPointer( + result.tagAsPtr(), nullptr, capTable, copyFrom, arena); + result.segment = allocation.segment; + result.capTable = capTable; + result.location = reinterpret_cast(allocation.value.begin()); + return result; +} + +#if !CAPNP_LITE +OrphanBuilder OrphanBuilder::copy( + BuilderArena* arena, CapTableBuilder* capTable, kj::Own copyFrom) { + OrphanBuilder result; + WireHelpers::setCapabilityPointer(nullptr, capTable, result.tagAsPtr(), kj::mv(copyFrom)); + result.segment = arena->getSegment(SegmentId(0)); + result.capTable = capTable; + result.location = &result.tag; // dummy to make location non-null + return result; +} +#endif // !CAPNP_LITE + +OrphanBuilder OrphanBuilder::concat( + BuilderArena* arena, CapTableBuilder* capTable, + ElementSize elementSize, StructSize structSize, + kj::ArrayPtr lists) { + KJ_REQUIRE(lists.size() > 0, "Can't concat empty list "); + + // Find the overall element count and size. + ListElementCount elementCount = ZERO * ELEMENTS; + for (auto& list: lists) { + elementCount = assertMaxBits(elementCount + list.elementCount, + []() { KJ_FAIL_REQUIRE("concatenated list exceeds list size limit"); }); + if (list.elementSize != elementSize) { + // If element sizes don't all match, upgrade to struct list. + KJ_REQUIRE(list.elementSize != ElementSize::BIT && elementSize != ElementSize::BIT, + "can't upgrade bit lists to struct lists"); + elementSize = ElementSize::INLINE_COMPOSITE; + } + structSize.data = kj::max(structSize.data, + WireHelpers::roundBitsUpToWords(list.structDataSize)); + structSize.pointers = kj::max(structSize.pointers, list.structPointerCount); + } + + // Allocate the list. + OrphanBuilder result; + ListBuilder builder = (elementSize == ElementSize::INLINE_COMPOSITE) + ? WireHelpers::initStructListPointer( + result.tagAsPtr(), nullptr, capTable, elementCount, structSize, arena) + : WireHelpers::initListPointer( + result.tagAsPtr(), nullptr, capTable, elementCount, elementSize, arena); + + // Copy elements. + switch (elementSize) { + case ElementSize::INLINE_COMPOSITE: { + ListElementCount pos = ZERO * ELEMENTS; + for (auto& list: lists) { + for (auto i: kj::zeroTo(list.size())) { + builder.getStructElement(pos).copyContentFrom(list.getStructElement(i)); + // assumeBits() safe because we checked total size earlier. + pos = assumeBits(pos + ONE * ELEMENTS); + } + } + break; + } + case ElementSize::POINTER: { + ListElementCount pos = ZERO * ELEMENTS; + for (auto& list: lists) { + for (auto i: kj::zeroTo(list.size())) { + builder.getPointerElement(pos).copyFrom(list.getPointerElement(i)); + // assumeBits() safe because we checked total size earlier. + pos = assumeBits(pos + ONE * ELEMENTS); + } + } + break; + } + case ElementSize::BIT: { + // It's difficult to memcpy() bits since a list could start or end mid-byte. For now we + // do a slow, naive loop. Probably no one will ever care. + ListElementCount pos = ZERO * ELEMENTS; + for (auto& list: lists) { + for (auto i: kj::zeroTo(list.size())) { + builder.setDataElement(pos, list.getDataElement(i)); + // assumeBits() safe because we checked total size earlier. + pos = assumeBits(pos + ONE * ELEMENTS); + } + } + break; + } + default: { + // We know all the inputs are primitives with identical size because otherwise we would have + // chosen INLINE_COMPOSITE. Therefore, we can safely use memcpy() here instead of copying + // each element manually. + byte* target = builder.ptr; + auto step = builder.step / BITS_PER_BYTE; + for (auto& list: lists) { + auto count = step * upgradeBound(list.size()); + WireHelpers::copyMemory(target, list.ptr, assumeBits(count)); + target += count; + } + break; + } + } + + // Return orphan. + result.segment = builder.segment; + result.capTable = capTable; + result.location = builder.getLocation(); + return result; +} + +OrphanBuilder OrphanBuilder::referenceExternalData(BuilderArena* arena, Data::Reader data) { + KJ_REQUIRE(reinterpret_cast(data.begin()) % sizeof(void*) == 0, + "Cannot referenceExternalData() that is not aligned."); + + auto checkedSize = assertMaxBits(bounded(data.size())); + auto wordCount = WireHelpers::roundBytesUpToWords(checkedSize * BYTES); + kj::ArrayPtr words(reinterpret_cast(data.begin()), + unbound(wordCount / WORDS)); + + OrphanBuilder result; + result.tagAsPtr()->setKindForOrphan(WirePointer::LIST); + result.tagAsPtr()->listRef.set(ElementSize::BYTE, checkedSize * ELEMENTS); + result.segment = arena->addExternalSegment(words); + + // External data cannot possibly contain capabilities. + result.capTable = nullptr; + + // const_cast OK here because we will check whether the segment is writable when we try to get + // a builder. + result.location = const_cast(words.begin()); + + return result; +} + +StructBuilder OrphanBuilder::asStruct(StructSize size) { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + StructBuilder result = WireHelpers::getWritableStructPointer( + tagAsPtr(), location, segment, capTable, size, nullptr, segment->getArena()); + + // Watch out, the pointer could have been updated if the object had to be relocated. + location = reinterpret_cast(result.data); + + return result; +} + +ListBuilder OrphanBuilder::asList(ElementSize elementSize) { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + ListBuilder result = WireHelpers::getWritableListPointer( + tagAsPtr(), location, segment, capTable, elementSize, nullptr, segment->getArena()); + + // Watch out, the pointer could have been updated if the object had to be relocated. + // (Actually, currently this is not true for primitive lists, but let's not turn into a bug if + // it changes!) + location = result.getLocation(); + + return result; +} + +ListBuilder OrphanBuilder::asStructList(StructSize elementSize) { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + ListBuilder result = WireHelpers::getWritableStructListPointer( + tagAsPtr(), location, segment, capTable, elementSize, nullptr, segment->getArena()); + + // Watch out, the pointer could have been updated if the object had to be relocated. + location = result.getLocation(); + + return result; +} + +ListBuilder OrphanBuilder::asListAnySize() { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + ListBuilder result = WireHelpers::getWritableListPointerAnySize( + tagAsPtr(), location, segment, capTable, nullptr, segment->getArena()); + + // Watch out, the pointer could have been updated if the object had to be relocated. + location = result.getLocation(); + + return result; +} + +Text::Builder OrphanBuilder::asText() { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + // Never relocates. + return WireHelpers::getWritableTextPointer( + tagAsPtr(), location, segment, capTable, nullptr, ZERO * BYTES); +} + +Data::Builder OrphanBuilder::asData() { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + + // Never relocates. + return WireHelpers::getWritableDataPointer( + tagAsPtr(), location, segment, capTable, nullptr, ZERO * BYTES); +} + +StructReader OrphanBuilder::asStructReader(StructSize size) const { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + return WireHelpers::readStructPointer( + segment, capTable, tagAsPtr(), location, nullptr, kj::maxValue); +} + +ListReader OrphanBuilder::asListReader(ElementSize elementSize) const { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + return WireHelpers::readListPointer( + segment, capTable, tagAsPtr(), location, nullptr, elementSize, kj::maxValue); +} + +ListReader OrphanBuilder::asListReaderAnySize() const { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + return WireHelpers::readListPointer( + segment, capTable, tagAsPtr(), location, nullptr, ElementSize::VOID /* dummy */, + kj::maxValue); +} + +#if !CAPNP_LITE +kj::Own OrphanBuilder::asCapability() const { + return WireHelpers::readCapabilityPointer(segment, capTable, tagAsPtr(), kj::maxValue); +} +#endif // !CAPNP_LITE + +Text::Reader OrphanBuilder::asTextReader() const { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + return WireHelpers::readTextPointer(segment, tagAsPtr(), location, nullptr, ZERO * BYTES); +} + +Data::Reader OrphanBuilder::asDataReader() const { + KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr)); + return WireHelpers::readDataPointer(segment, tagAsPtr(), location, nullptr, ZERO * BYTES); +} + +bool OrphanBuilder::truncate(ElementCount uncheckedSize, bool isText) { + ListElementCount size = assertMaxBits(uncheckedSize, + []() { KJ_FAIL_REQUIRE("requested list size is too large"); }); + + WirePointer* ref = tagAsPtr(); + SegmentBuilder* segment = this->segment; + + word* target = WireHelpers::followFars(ref, location, segment); + + if (ref->isNull()) { + // We don't know the right element size, so we can't resize this list. + return size == ZERO * ELEMENTS; + } + + KJ_REQUIRE(ref->kind() == WirePointer::LIST, "Can't truncate non-list.") { + return false; + } + + if (isText) { + // Add space for the NUL terminator. + size = assertMaxBits(size + ONE * ELEMENTS, + []() { KJ_FAIL_REQUIRE("requested list size is too large"); }); + } + + auto elementSize = ref->listRef.elementSize(); + + if (elementSize == ElementSize::INLINE_COMPOSITE) { + auto oldWordCount = ref->listRef.inlineCompositeWordCount(); + + WirePointer* tag = reinterpret_cast(target); + ++target; + KJ_REQUIRE(tag->kind() == WirePointer::STRUCT, + "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") { + return false; + } + StructSize structSize(tag->structRef.dataSize.get(), tag->structRef.ptrCount.get()); + auto elementStep = structSize.total() / ELEMENTS; + + auto oldSize = tag->inlineCompositeListElementCount(); + + SegmentWordCount sizeWords = assertMaxBits( + upgradeBound(size) * elementStep, + []() { KJ_FAIL_ASSERT("requested list size too large to fit in message segment"); }); + SegmentWordCount oldSizeWords = assertMaxBits( + upgradeBound(oldSize) * elementStep, + []() { KJ_FAIL_ASSERT("prior to truncate, list is larger than max segment size?"); }); + + word* newEndWord = target + sizeWords; + word* oldEndWord = target + oldWordCount; + + if (size <= oldSize) { + // Zero the trailing elements. + for (auto i: kj::range(size, oldSize)) { + // assumeBits() safe because we checked that both sizeWords and oldSizeWords are in-range + // above. + WireHelpers::zeroObject(segment, capTable, tag, target + + assumeBits(upgradeBound(i) * elementStep)); + } + ref->listRef.setInlineComposite(sizeWords); + tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size); + segment->tryTruncate(oldEndWord, newEndWord); + } else if (newEndWord <= oldEndWord) { + // Apparently the old list was over-allocated? The word count is more than needed to store + // the elements. This is "valid" but shouldn't happen in practice unless someone is toying + // with us. + word* expectedEnd = target + oldSizeWords; + KJ_ASSERT(newEndWord >= expectedEnd); + WireHelpers::zeroMemory(expectedEnd, + intervalLength(expectedEnd, newEndWord, MAX_SEGMENT_WORDS)); + tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size); + } else { + if (segment->tryExtend(oldEndWord, newEndWord)) { + // Done in-place. Nothing else to do now; the new memory is already zero'd. + ref->listRef.setInlineComposite(sizeWords); + tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, size); + } else { + // Need to re-allocate and transfer. + OrphanBuilder replacement = initStructList(segment->getArena(), capTable, size, structSize); + + ListBuilder newList = replacement.asStructList(structSize); + for (auto i: kj::zeroTo(oldSize)) { + // assumeBits() safe because we checked that both sizeWords and oldSizeWords are in-range + // above. + word* element = target + + assumeBits(upgradeBound(i) * elementStep); + newList.getStructElement(i).transferContentFrom( + StructBuilder(segment, capTable, element, + reinterpret_cast(element + structSize.data), + structSize.data * BITS_PER_WORD, structSize.pointers)); + } + + *this = kj::mv(replacement); + } + } + } else if (elementSize == ElementSize::POINTER) { + // TODO(cleanup): GCC won't let me declare this constexpr, claiming POINTERS is not constexpr, + // but it is? + const auto POINTERS_PER_ELEMENT = ONE * POINTERS / ELEMENTS; + + auto oldSize = ref->listRef.elementCount(); + word* newEndWord = target + size * POINTERS_PER_ELEMENT * WORDS_PER_POINTER; + word* oldEndWord = target + oldSize * POINTERS_PER_ELEMENT * WORDS_PER_POINTER; + + if (size <= oldSize) { + // Zero the trailing elements. + for (WirePointer* element = reinterpret_cast(newEndWord); + element < reinterpret_cast(oldEndWord); ++element) { + WireHelpers::zeroPointerAndFars(segment, element); + } + ref->listRef.set(ElementSize::POINTER, size); + segment->tryTruncate(oldEndWord, newEndWord); + } else { + if (segment->tryExtend(oldEndWord, newEndWord)) { + // Done in-place. Nothing else to do now; the new memory is already zero'd. + ref->listRef.set(ElementSize::POINTER, size); + } else { + // Need to re-allocate and transfer. + OrphanBuilder replacement = initList( + segment->getArena(), capTable, size, ElementSize::POINTER); + ListBuilder newList = replacement.asList(ElementSize::POINTER); + WirePointer* oldPointers = reinterpret_cast(target); + for (auto i: kj::zeroTo(oldSize)) { + newList.getPointerElement(i).transferFrom( + PointerBuilder(segment, capTable, oldPointers + i * POINTERS_PER_ELEMENT)); + } + *this = kj::mv(replacement); + } + } + } else { + auto oldSize = ref->listRef.elementCount(); + auto step = dataBitsPerElement(elementSize); + const auto MAX_STEP_BYTES = ONE * WORDS / ELEMENTS * BYTES_PER_WORD; + word* newEndWord = target + WireHelpers::roundBitsUpToWords( + upgradeBound(size) * step); + word* oldEndWord = target + WireHelpers::roundBitsUpToWords( + upgradeBound(oldSize) * step); + + if (size <= oldSize) { + // When truncating text, we want to set the null terminator as well, so we'll do our zeroing + // at the byte level. + byte* begin = reinterpret_cast(target); + byte* newEndByte = begin + WireHelpers::roundBitsUpToBytes( + upgradeBound(size) * step) - isText; + byte* oldEndByte = reinterpret_cast(oldEndWord); + + WireHelpers::zeroMemory(newEndByte, + intervalLength(newEndByte, oldEndByte, MAX_LIST_ELEMENTS * MAX_STEP_BYTES)); + ref->listRef.set(elementSize, size); + segment->tryTruncate(oldEndWord, newEndWord); + } else { + // We're trying to extend, not truncate. + if (segment->tryExtend(oldEndWord, newEndWord)) { + // Done in-place. Nothing else to do now; the memory is already zero'd. + ref->listRef.set(elementSize, size); + } else { + // Need to re-allocate and transfer. + OrphanBuilder replacement = initList(segment->getArena(), capTable, size, elementSize); + ListBuilder newList = replacement.asList(elementSize); + auto words = WireHelpers::roundBitsUpToWords( + dataBitsPerElement(elementSize) * upgradeBound(oldSize)); + WireHelpers::copyMemory(reinterpret_cast(newList.ptr), target, words); + *this = kj::mv(replacement); + } + } + } + + return true; +} + +void OrphanBuilder::truncate(ElementCount size, ElementSize elementSize) { + if (!truncate(size, false)) { + // assumeBits() safe since it's checked inside truncate() + *this = initList(segment->getArena(), capTable, + assumeBits(size), elementSize); + } +} + +void OrphanBuilder::truncate(ElementCount size, StructSize elementSize) { + if (!truncate(size, false)) { + // assumeBits() safe since it's checked inside truncate() + *this = initStructList(segment->getArena(), capTable, + assumeBits(size), elementSize); + } +} + +void OrphanBuilder::truncateText(ElementCount size) { + if (!truncate(size, true)) { + // assumeBits() safe since it's checked inside truncate() + *this = initText(segment->getArena(), capTable, + assumeBits(size) * (ONE * BYTES / ELEMENTS)); + } +} + +void OrphanBuilder::euthanize() { + // Carefully catch any exceptions and rethrow them as recoverable exceptions since we may be in + // a destructor. + auto exception = kj::runCatchingExceptions([&]() { + if (tagAsPtr()->isPositional()) { + WireHelpers::zeroObject(segment, capTable, tagAsPtr(), location); + } else { + WireHelpers::zeroObject(segment, capTable, tagAsPtr()); + } + + WireHelpers::zeroMemory(&tag, ONE * WORDS); + segment = nullptr; + location = nullptr; + }); + + KJ_IF_MAYBE(e, exception) { + kj::getExceptionCallback().onRecoverableException(kj::mv(*e)); + } +} + +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/layout.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/layout.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1274 @@ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file is NOT intended for use by clients, except in generated code. +// +// This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout +// (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes, +// as does other parts of the Cap'n proto library which provide a higher-level interface for +// dynamic introspection. + +#ifndef CAPNP_LAYOUT_H_ +#define CAPNP_LAYOUT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include "common.h" +#include "blob.h" +#include "endian.h" + +#if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN) +#define CAPNP_CANONICALIZE_NAN 1 +// Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by +// __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN +// signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in +// particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world. +// Canonicalizing them makes output consistent (which is important!), but hurts performance +// slightly. +// +// Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work. +// Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs. +// everyone else. It would be great if we could just flip that bit, but we can't, because if the +// significand is all-zero, then the value is infinity rather than NaN. This means that on most +// machines, where the bit indicates quietness, there is one more quiet NaN value than signalling +// NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic +// mapping that properly preserves quietness. Instead of doing something hacky, we just give up +// and blow away NaN payloads, because no one uses them anyway. +#endif + +namespace capnp { + +#if !CAPNP_LITE +class ClientHook; +#endif // !CAPNP_LITE + +namespace _ { // private + +class PointerBuilder; +class PointerReader; +class StructBuilder; +class StructReader; +class ListBuilder; +class ListReader; +class OrphanBuilder; +struct WirePointer; +struct WireHelpers; +class SegmentReader; +class SegmentBuilder; +class Arena; +class BuilderArena; + +// ============================================================================= + +#if CAPNP_DEBUG_TYPES +typedef kj::UnitRatio, BitLabel, ElementLabel> BitsPerElementTableType; +#else +typedef uint BitsPerElementTableType; +#endif + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType dataBitsPerElement(ElementSize size) { + return _::BITS_PER_ELEMENT_TABLE[static_cast(size)]; +} + +inline constexpr PointersPerElementN<1> pointersPerElement(ElementSize size) { + return size == ElementSize::POINTER + ? PointersPerElementN<1>(ONE * POINTERS / ELEMENTS) + : PointersPerElementN<1>(ZERO * POINTERS / ELEMENTS); +} + +static constexpr BitsPerElementTableType BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[8] = { + bounded< 0>() * BITS / ELEMENTS, + bounded< 1>() * BITS / ELEMENTS, + bounded< 8>() * BITS / ELEMENTS, + bounded<16>() * BITS / ELEMENTS, + bounded<32>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded<64>() * BITS / ELEMENTS, + bounded< 0>() * BITS / ELEMENTS +}; + +inline KJ_CONSTEXPR() BitsPerElementTableType bitsPerElementIncludingPointers(ElementSize size) { + return _::BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[static_cast(size)]; +} + +template struct ElementSizeForByteSize; +template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; }; +template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; }; +template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; }; +template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; }; + +template struct ElementSizeForType { + static constexpr ElementSize value = + // Primitive types that aren't special-cased below can be determined from sizeof(). + CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize::value : + CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES : + CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE : + + // Everything else is a pointer. + ElementSize::POINTER; +}; + +// Void and bool are special. +template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::VOID; }; +template <> struct ElementSizeForType { static constexpr ElementSize value = ElementSize::BIT; }; + +// Lists and blobs are pointers, not structs. +template struct ElementSizeForType> { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType { + static constexpr ElementSize value = ElementSize::POINTER; +}; +template <> struct ElementSizeForType { + static constexpr ElementSize value = ElementSize::POINTER; +}; + +template +inline constexpr ElementSize elementSizeForType() { + return ElementSizeForType::value; +} + +struct MessageSizeCounts { + WordCountN<61, uint64_t> wordCount; // 2^64 bytes + uint capCount; + + MessageSizeCounts& operator+=(const MessageSizeCounts& other) { + // OK to truncate unchecked because this class is used to count actual stuff in memory, and + // we couldn't possibly have anywhere near 2^61 words. + wordCount = assumeBits<61>(wordCount + other.wordCount); + capCount += other.capCount; + return *this; + } + + void addWords(WordCountN<61, uint64_t> other) { + wordCount = assumeBits<61>(wordCount + other); + } + + MessageSize asPublic() { + return MessageSize { unbound(wordCount / WORDS), capCount }; + } +}; + +// ============================================================================= + +template +union AlignedData { + // Useful for declaring static constant data blobs as an array of bytes, but forcing those + // bytes to be word-aligned. + + uint8_t bytes[wordCount * sizeof(word)]; + word words[wordCount]; +}; + +struct StructSize { + StructDataWordCount data; + StructPointerCount pointers; + + inline constexpr WordCountN<17> total() const { return data + pointers * WORDS_PER_POINTER; } + + StructSize() = default; + inline constexpr StructSize(StructDataWordCount data, StructPointerCount pointers) + : data(data), pointers(pointers) {} +}; + +template +inline constexpr StructSize structSize() { + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template > +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS, + bounded(CapnpPrivate::pointerCount) * POINTERS); +} + +template > +inline constexpr StructSize minStructSizeForElement() { + // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough + // to hold a T. + + return StructSize( + dataBitsPerElement(elementSizeForType()) * ELEMENTS > ZERO * BITS + ? StructDataWordCount(ONE * WORDS) : StructDataWordCount(ZERO * WORDS), + pointersPerElement(elementSizeForType()) * ELEMENTS); +} + +// ------------------------------------------------------------------- +// Masking of default values + +template struct Mask_; +template struct Mask_ { typedef T Type; }; +template struct Mask_ { typedef uint16_t Type; }; +template <> struct Mask_ { typedef uint32_t Type; }; +template <> struct Mask_ { typedef uint64_t Type; }; + +template struct Mask_ { + // Union discriminants end up here. + static_assert(sizeof(T) == 2, "Don't know how to mask this type."); + typedef uint16_t Type; +}; + +template +using Mask = typename Mask_::Type; + +template +KJ_ALWAYS_INLINE(Mask mask(T value, Mask mask)); +template +KJ_ALWAYS_INLINE(T unmask(Mask value, Mask mask)); + +template +inline Mask mask(T value, Mask mask) { + return static_cast >(value) ^ mask; +} + +template <> +inline uint32_t mask(float value, uint32_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7fc00000u ^ mask; + } +#endif + + uint32_t i; + static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template <> +inline uint64_t mask(double value, uint64_t mask) { +#if CAPNP_CANONICALIZE_NAN + if (value != value) { + return 0x7ff8000000000000ull ^ mask; + } +#endif + + uint64_t i; + static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?"); + memcpy(&i, &value, sizeof(value)); + return i ^ mask; +} + +template +inline T unmask(Mask value, Mask mask) { + return static_cast(value ^ mask); +} + +template <> +inline float unmask(uint32_t value, uint32_t mask) { + value ^= mask; + float result; + static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +template <> +inline double unmask(uint64_t value, uint64_t mask) { + value ^= mask; + double result; + static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?"); + memcpy(&result, &value, sizeof(value)); + return result; +} + +// ------------------------------------------------------------------- + +class CapTableReader { +public: +#if !CAPNP_LITE + virtual kj::Maybe> extractCap(uint index) = 0; + // Extract the capability at the given index. If the index is invalid, returns null. +#endif // !CAPNP_LITE +}; + +class CapTableBuilder: public CapTableReader { +public: +#if !CAPNP_LITE + virtual uint injectCap(kj::Own&& cap) = 0; + // Add the capability to the message and return its index. If the same ClientHook is injected + // twice, this may return the same index both times, but in this case dropCap() needs to be + // called an equal number of times to actually remove the cap. + + virtual void dropCap(uint index) = 0; + // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out. +#endif // !CAPNP_LITE +}; + +// ------------------------------------------------------------------- + +class PointerBuilder: public kj::DisallowConstCopy { + // Represents a single pointer, usually embedded in a struct or a list. + +public: + inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {} + + static inline PointerBuilder getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location); + // Get a PointerBuilder representing a message root located in the given segment at the given + // location. + + inline bool isNull() { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructBuilder getStruct(StructSize size, const word* defaultValue); + ListBuilder getList(ElementSize elementSize, const word* defaultValue); + ListBuilder getStructList(StructSize elementSize, const word* defaultValue); + ListBuilder getListAnySize(const word* defaultValue); + template typename T::Builder getBlob( + const void* defaultValue, ByteCount defaultSize); +#if !CAPNP_LITE + kj::Own getCapability(); +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, initialize it to a copy of the default value. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + StructBuilder initStruct(StructSize size); + ListBuilder initList(ElementSize elementSize, ElementCount elementCount); + ListBuilder initStructList(ElementCount elementCount, StructSize size); + template typename T::Builder initBlob(ByteCount size); + // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing + // object. + + void setStruct(const StructReader& value, bool canonical = false); + void setList(const ListReader& value, bool canonical = false); + template void setBlob(typename T::Reader value); +#if !CAPNP_LITE + void setCapability(kj::Own&& cap); +#endif // !CAPNP_LITE + // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding + // the existing object. + + void adopt(OrphanBuilder&& orphan); + // Set the pointer to point at the given orphaned value. + + OrphanBuilder disown(); + // Set the pointer to null and return its previous value as an orphan. + + void clear(); + // Clear the pointer to null, discarding its previous value. + + void transferFrom(PointerBuilder other); + // Equivalent to `adopt(other.disown())`. + + void copyFrom(PointerReader other, bool canonical = false); + // Equivalent to `set(other.get())`. + // If you set the canonical flag, it will attempt to lay the target out + // canonically, provided enough space is available. + + PointerReader asReader() const; + + BuilderArena* getArena() const; + // Get the arena containing this pointer. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the pointer resides. + CapTableBuilder* capTable; // Table of capability indexes. + WirePointer* pointer; // Pointer to the pointer. + + inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer) + : segment(segment), capTable(capTable), pointer(pointer) {} + + friend class StructBuilder; + friend class ListBuilder; + friend class OrphanBuilder; +}; + +class PointerReader { +public: + inline PointerReader() + : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {} + + static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable, + const word* location, int nestingLimit); + // Get a PointerReader representing a message root located in the given segment at the given + // location. + + static inline PointerReader getRootUnchecked(const word* location); + // Get a PointerReader for an unchecked message. + + MessageSizeCounts targetSize() const; + // Return the total size of the target object and everything to which it points. Does not count + // far pointer overhead. This is useful for deciding how much space is needed to copy the object + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + inline bool isNull() const { return getPointerType() == PointerType::NULL_; } + PointerType getPointerType() const; + + StructReader getStruct(const word* defaultValue) const; + ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const; + ListReader getListAnySize(const word* defaultValue) const; + template + typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; +#if !CAPNP_LITE + kj::Own getCapability() const; +#endif // !CAPNP_LITE + // Get methods: Get the value. If it is null, return the default value instead. + // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a + // simple byte array for blobs. + + const word* getUnchecked() const; + // If this is an unchecked message, get a word* pointing at the location of the pointer. This + // word* can actually be passed to readUnchecked() to read the designated sub-object later. If + // this isn't an unchecked message, throws an exception. + + kj::Maybe getArena() const; + // Get the arena containing this pointer. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + PointerReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the pointer resides. + CapTableReader* capTable; // Table of capability indexes. + const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline PointerReader(SegmentReader* segment, CapTableReader* capTable, + const WirePointer* pointer, int nestingLimit) + : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListReader; + friend class PointerBuilder; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class StructBuilder: public kj::DisallowConstCopy { +public: + inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {} + + inline word* getLocation() { return reinterpret_cast(data); } + // Get the object's location. Only valid for independently-allocated objects (i.e. not list + // elements). + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr getDataSectionAsBlob(); + inline _::ListBuilder getPointerSectionAsList(); + + template + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset)); + // Return true if the field is set to something other than its default value. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset)); + // Gets the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask mask)); + // Like getDataField() but applies the given XOR mask to the data on load. Used for reading + // fields with non-zero default values. + + template + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, kj::NoInfer value)); + // Sets the data field value at the given offset. + + template + KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, + kj::NoInfer value, Mask mask)); + // Like setDataField() but applies the given XOR mask before storing. Used for writing fields + // with non-zero default values. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerField(StructPointerOffset ptrIndex)); + // Get a builder for a pointer field given the index within the pointer section. + + void clearAll(); + // Clear all pointers and data. + + void transferContentFrom(StructBuilder other); + // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger + // than this, the extra data is not transferred, meaning there is a risk of data loss when + // transferring from messages built with future versions of the protocol. + + void copyContentFrom(StructReader other); + // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not + // copied, meaning there is a risk of data loss when copying from messages built with future + // versions of the protocol. + + StructReader asReader() const; + // Gets a StructReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + StructBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the struct resides. + CapTableBuilder* capTable; // Table of capability indexes. + void* data; // Pointer to the encoded data. + WirePointer* pointers; // Pointer to the encoded pointers. + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, + void* data, WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount) {} + + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class StructReader { +public: + inline StructReader() + : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr), + dataSize(ZERO * BITS), pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + inline StructReader(kj::ArrayPtr data) + : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr), + dataSize(assumeBits(data.size()) * WORDS * BITS_PER_WORD), + pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {} + + const void* getLocation() const { return data; } + + inline StructDataBitCount getDataSectionSize() const { return dataSize; } + inline StructPointerCount getPointerSectionSize() const { return pointerCount; } + inline kj::ArrayPtr getDataSectionAsBlob(); + inline _::ListReader getPointerSectionAsList(); + + kj::Array canonicalize(); + + template + KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset) const); + // Return true if the field is set to something other than its default value. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset) const); + // Get the data field value of the given type at the given offset. The offset is measured in + // multiples of the field size, determined by the type. Returns zero if the offset is past the + // end of the struct's data section. + + template + KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask mask) const); + // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading + // fields with non-zero default values. + + KJ_ALWAYS_INLINE(PointerReader getPointerField(StructPointerOffset ptrIndex) const); + // Get a reader for a pointer field given the index within the pointer section. If the index + // is out-of-bounds, returns a null pointer. + + MessageSizeCounts totalSize() const; + // Return the total size of the struct and everything to which it points. Does not count far + // pointer overhead. This is useful for deciding how much space is needed to copy the struct + // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead, + // use the result as a hint for allocating the first segment, do the copy, and then throw an + // exception if it overruns. + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + StructReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const word **ptrHead, + bool *dataTrunc, bool *ptrTrunc); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + // + // If this function returns false, the struct is non-canonical. If it + // returns true, then: + // * If it is a composite in a list, it is canonical if at least one struct + // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1 + // * If it is derived from a struct pointer, it is canonical if + // dataTrunc = 1 AND ptrTrunc = 1 + +private: + SegmentReader* segment; // Memory segment in which the struct resides. + CapTableReader* capTable; // Table of capability indexes. + + const void* data; + const WirePointer* pointers; + + StructDataBitCount dataSize; + // Size of data section. We use a bit count rather than a word count to more easily handle the + // case of struct lists encoded with less than a word per element. + + StructPointerCount pointerCount; // Size of the pointer section. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + // TODO(perf): Limit to 16 bits for better packing? + + inline StructReader(SegmentReader* segment, CapTableReader* capTable, + const void* data, const WirePointer* pointers, + StructDataBitCount dataSize, StructPointerCount pointerCount, + int nestingLimit) + : segment(segment), capTable(capTable), data(data), pointers(pointers), + dataSize(dataSize), pointerCount(pointerCount), + nestingLimit(nestingLimit) {} + + friend class ListReader; + friend class StructBuilder; + friend struct WireHelpers; +}; + +// ------------------------------------------------------------------- + +class ListBuilder: public kj::DisallowConstCopy { +public: + inline explicit ListBuilder(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize) {} + + inline word* getLocation() { + // Get the object's location. + + if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) { + return reinterpret_cast(ptr) - POINTER_SIZE_IN_WORDS; + } else { + return reinterpret_cast(ptr); + } + } + + inline ElementSize getElementSize() const { return elementSize; } + + inline ListElementCount size() const; + // The number of elements in the list. + + Text::Builder asText(); + Data::Builder asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + template + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index)); + // Get the element of the given type at the given index. + + template + KJ_ALWAYS_INLINE(void setDataElement(ElementCount index, kj::NoInfer value)); + // Set the element at the given index. + + KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index)); + + StructBuilder getStructElement(ElementCount index); + + ListReader asReader() const; + // Get a ListReader pointing at the same memory. + + BuilderArena* getArena(); + // Gets the arena in which this object is allocated. + + CapTableBuilder* getCapTable(); + // Gets the capability context in which this object is operating. + + ListBuilder imbue(CapTableBuilder* capTable); + // Return a copy of this builder except using the given capability context. + +private: + SegmentBuilder* segment; // Memory segment in which the list resides. + CapTableBuilder* capTable; // Table of capability indexes. + + byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 128 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr, + BitsPerElementN<23> step, ListElementCount size, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize) + : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), + elementCount(size), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize) {} + + friend class StructBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +class ListReader { +public: + inline explicit ListReader(ElementSize elementSize) + : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS), + step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS), + structPointerCount(ZERO * POINTERS), elementSize(elementSize), nestingLimit(0x7fffffff) {} + + inline ListElementCount size() const; + // The number of elements in the list. + + inline ElementSize getElementSize() const { return elementSize; } + + Text::Reader asText(); + Data::Reader asData(); + // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized. + + kj::ArrayPtr asRawBytes(); + + template + KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const); + // Get the element of the given type at the given index. + + KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const); + + StructReader getStructElement(ElementCount index) const; + + CapTableReader* getCapTable(); + // Gets the capability context in which this object is operating. + + ListReader imbue(CapTableReader* capTable) const; + // Return a copy of this reader except using the given capability context. + + bool isCanonical(const word **readHead, const WirePointer* ref); + // Validate this pointer's canonicity, subject to the conditions: + // * All data to the left of readHead has been read thus far (for pointer + // ordering) + // * All pointers in preorder have already been checked + // * This pointer is in the first and only segment of the message + +private: + SegmentReader* segment; // Memory segment in which the list resides. + CapTableReader* capTable; // Table of capability indexes. + + const byte* ptr; // Pointer to list content. + + ListElementCount elementCount; // Number of elements in the list. + + BitsPerElementN<23> step; + // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data + // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 2 bits. + + StructDataBitCount structDataSize; + StructPointerCount structPointerCount; + // The struct properties to use when interpreting the elements as structs. All lists can be + // interpreted as struct lists, so these are always filled in. + + ElementSize elementSize; + // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE + // from other types when the overall size is exactly zero or one words. + + int nestingLimit; + // Limits the depth of message structures to guard against stack-overflow-based DoS attacks. + // Once this reaches zero, further pointers will be pruned. + + inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr, + ListElementCount elementCount, BitsPerElementN<23> step, + StructDataBitCount structDataSize, StructPointerCount structPointerCount, + ElementSize elementSize, int nestingLimit) + : segment(segment), capTable(capTable), ptr(reinterpret_cast(ptr)), + elementCount(elementCount), step(step), structDataSize(structDataSize), + structPointerCount(structPointerCount), elementSize(elementSize), + nestingLimit(nestingLimit) {} + + friend class StructReader; + friend class ListBuilder; + friend struct WireHelpers; + friend class OrphanBuilder; +}; + +// ------------------------------------------------------------------- + +class OrphanBuilder { +public: + inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) { + memset(&tag, 0, sizeof(tag)); + } + OrphanBuilder(const OrphanBuilder& other) = delete; + inline OrphanBuilder(OrphanBuilder&& other) noexcept; + inline ~OrphanBuilder() noexcept(false); + + static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size); + static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, ElementSize elementSize); + static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable, + ElementCount elementCount, StructSize elementSize); + static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size); + + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom); + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom); +#if !CAPNP_LITE + static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, + kj::Own copyFrom); +#endif // !CAPNP_LITE + + static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable, + ElementSize expectedElementSize, StructSize expectedStructSize, + kj::ArrayPtr lists); + + static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data); + + OrphanBuilder& operator=(const OrphanBuilder& other) = delete; + inline OrphanBuilder& operator=(OrphanBuilder&& other); + + inline bool operator==(decltype(nullptr)) const { return location == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return location != nullptr; } + + StructBuilder asStruct(StructSize size); + // Interpret as a struct, or throw an exception if not a struct. + + ListBuilder asList(ElementSize elementSize); + // Interpret as a list, or throw an exception if not a list. elementSize cannot be + // INLINE_COMPOSITE -- use asStructList() instead. + + ListBuilder asStructList(StructSize elementSize); + // Interpret as a struct list, or throw an exception if not a list. + + ListBuilder asListAnySize(); + // For AnyList. + + Text::Builder asText(); + Data::Builder asData(); + // Interpret as a blob, or throw an exception if not a blob. + + StructReader asStructReader(StructSize size) const; + ListReader asListReader(ElementSize elementSize) const; + ListReader asListReaderAnySize() const; +#if !CAPNP_LITE + kj::Own asCapability() const; +#endif // !CAPNP_LITE + Text::Reader asTextReader() const; + Data::Reader asDataReader() const; + + bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT; + // Resize the orphan list to the given size. Returns false if the list is currently empty but + // the requested size is non-zero, in which case the caller will need to allocate a new list. + + void truncate(ElementCount size, ElementSize elementSize); + void truncate(ElementCount size, StructSize elementSize); + void truncateText(ElementCount size); + // Versions of truncate() that know how to allocate a new list if needed. + +private: + static_assert(ONE * POINTERS * WORDS_PER_POINTER == ONE * WORDS, + "This struct assumes a pointer is one word."); + word tag; + // Contains an encoded WirePointer representing this object. WirePointer is defined in + // layout.c++, but fits in a word. + // + // This may be a FAR pointer. Even in that case, `location` points to the eventual destination + // of that far pointer. The reason we keep the far pointer around rather than just making `tag` + // represent the final destination is because if the eventual adopter of the pointer is not in + // the target's segment then it may be useful to reuse the far pointer landing pad. + // + // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual + // target. + + SegmentBuilder* segment; + // Segment in which the object resides. + + CapTableBuilder* capTable; + // Table of capability indexes. + + word* location; + // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this + // 0x1 just so that it is non-null for operator==, but it is never used. + + inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment, + CapTableBuilder* capTable, word* location) + : segment(segment), capTable(capTable), location(location) { + memcpy(&tag, tagPtr, sizeof(tag)); + } + + inline WirePointer* tagAsPtr() { return reinterpret_cast(&tag); } + inline const WirePointer* tagAsPtr() const { return reinterpret_cast(&tag); } + + void euthanize(); + // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when + // the OrphanBuilder is being destroyed or overwritten and it is non-null. + + friend struct WireHelpers; +}; + +// ======================================================================================= +// Internal implementation details... + +// These are defined in the source file. +template <> typename Text::Builder PointerBuilder::initBlob(ByteCount size); +template <> void PointerBuilder::setBlob(typename Text::Reader value); +template <> typename Text::Builder PointerBuilder::getBlob( + const void* defaultValue, ByteCount defaultSize); +template <> typename Text::Reader PointerReader::getBlob( + const void* defaultValue, ByteCount defaultSize) const; + +template <> typename Data::Builder PointerBuilder::initBlob(ByteCount size); +template <> void PointerBuilder::setBlob(typename Data::Reader value); +template <> typename Data::Builder PointerBuilder::getBlob( + const void* defaultValue, ByteCount defaultSize); +template <> typename Data::Reader PointerReader::getBlob( + const void* defaultValue, ByteCount defaultSize) const; + +inline PointerBuilder PointerBuilder::getRoot( + SegmentBuilder* segment, CapTableBuilder* capTable, word* location) { + return PointerBuilder(segment, capTable, reinterpret_cast(location)); +} + +inline PointerReader PointerReader::getRootUnchecked(const word* location) { + return PointerReader(nullptr, nullptr, + reinterpret_cast(location), 0x7fffffff); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr StructBuilder::getDataSectionAsBlob() { + return kj::ArrayPtr(reinterpret_cast(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListBuilder StructBuilder::getPointerSectionAsList() { + return _::ListBuilder(segment, capTable, pointers, ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, + pointerCount * (ONE * ELEMENTS / POINTERS), + ZERO * BITS, ONE * POINTERS, ElementSize::POINTER); +} + +template +inline bool StructBuilder::hasDataField(StructDataOffset offset) { + return getDataField>(offset) != 0; +} + +template <> +inline bool StructBuilder::hasDataField(StructDataOffset offset) { + return false; +} + +template +inline T StructBuilder::getDataField(StructDataOffset offset) { + return reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].get(); +} + +template <> +inline bool StructBuilder::getDataField(StructDataOffset offset) { + BitCount32 boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void StructBuilder::getDataField(StructDataOffset offset) { + return VOID; +} + +template +inline T StructBuilder::getDataField(StructDataOffset offset, Mask mask) { + return unmask(getDataField >(offset), mask); +} + +template +inline void StructBuilder::setDataField(StructDataOffset offset, kj::NoInfer value) { + reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, float value) { + setDataField(offset, mask(value, 0)); +} +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, double value) { + setDataField(offset, mask(value, 0)); +} +#endif + +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, bool value) { + auto boffset = offset * (ONE * BITS / ELEMENTS); + byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + uint bitnum = unboundMaxBits<3>(boffset % BITS_PER_BYTE / BITS); + *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << bitnum)) + | (static_cast(value) << bitnum); +} + +template <> +inline void StructBuilder::setDataField(StructDataOffset offset, Void value) {} + +template +inline void StructBuilder::setDataField(StructDataOffset offset, + kj::NoInfer value, Mask m) { + setDataField >(offset, mask(value, m)); +} + +inline PointerBuilder StructBuilder::getPointerField(StructPointerOffset ptrIndex) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerBuilder(segment, capTable, reinterpret_cast( + reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER)); +} + +// ------------------------------------------------------------------- + +inline kj::ArrayPtr StructReader::getDataSectionAsBlob() { + return kj::ArrayPtr(reinterpret_cast(data), + unbound(dataSize / BITS_PER_BYTE / BYTES)); +} + +inline _::ListReader StructReader::getPointerSectionAsList() { + return _::ListReader(segment, capTable, pointers, pointerCount * (ONE * ELEMENTS / POINTERS), + ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, ZERO * BITS, ONE * POINTERS, + ElementSize::POINTER, nestingLimit); +} + +template +inline bool StructReader::hasDataField(StructDataOffset offset) const { + return getDataField>(offset) != 0; +} + +template <> +inline bool StructReader::hasDataField(StructDataOffset offset) const { + return false; +} + +template +inline T StructReader::getDataField(StructDataOffset offset) const { + if ((offset + ONE * ELEMENTS) * capnp::bitsPerElement() <= dataSize) { + return reinterpret_cast*>(data)[unbound(offset / ELEMENTS)].get(); + } else { + return static_cast(0); + } +} + +template <> +inline bool StructReader::getDataField(StructDataOffset offset) const { + auto boffset = offset * (ONE * BITS / ELEMENTS); + if (boffset < dataSize) { + const byte* b = reinterpret_cast(data) + boffset / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0; + } else { + return false; + } +} + +template <> +inline Void StructReader::getDataField(StructDataOffset offset) const { + return VOID; +} + +template +T StructReader::getDataField(StructDataOffset offset, Mask mask) const { + return unmask(getDataField >(offset), mask); +} + +inline PointerReader StructReader::getPointerField(StructPointerOffset ptrIndex) const { + if (ptrIndex < pointerCount) { + // Hacky because WirePointer is defined in the .c++ file (so is incomplete here). + return PointerReader(segment, capTable, reinterpret_cast( + reinterpret_cast(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit); + } else{ + return PointerReader(); + } +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListBuilder::size() const { return elementCount; } + +template +inline T ListBuilder::getDataElement(ElementCount index) { + return reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->get(); + + // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of + // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and + // the various non-inline methods that look up pointers. + // Also if using this, consider changing ptr back to void* instead of byte*. +// return reinterpret_cast*>(ptr)[ +// index / ELEMENTS * (step / capnp::bitsPerElement())].get(); +} + +template <> +inline bool ListBuilder::getDataElement(ElementCount index) { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListBuilder::getDataElement(ElementCount index) { + return VOID; +} + +template +inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer value) { + reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->set(value); +} + +#if CAPNP_CANONICALIZE_NAN +// Use mask() on floats and doubles to make sure we canonicalize NaNs. +template <> +inline void ListBuilder::setDataElement(ElementCount index, float value) { + setDataElement(index, mask(value, 0)); +} +template <> +inline void ListBuilder::setDataElement(ElementCount index, double value) { + setDataElement(index, mask(value, 0)); +} +#endif + +template <> +inline void ListBuilder::setDataElement(ElementCount index, bool value) { + // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + byte* b = ptr + bindex / BITS_PER_BYTE; + auto bitnum = bindex % BITS_PER_BYTE / BITS; + *reinterpret_cast(b) = (*reinterpret_cast(b) & ~(1 << unbound(bitnum))) + | (static_cast(value) << unbound(bitnum)); +} + +template <> +inline void ListBuilder::setDataElement(ElementCount index, Void value) {} + +inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) { + return PointerBuilder(segment, capTable, reinterpret_cast(ptr + + upgradeBound(index) * step / BITS_PER_BYTE)); +} + +// ------------------------------------------------------------------- + +inline ListElementCount ListReader::size() const { return elementCount; } + +template +inline T ListReader::getDataElement(ElementCount index) const { + return reinterpret_cast*>( + ptr + upgradeBound(index) * step / BITS_PER_BYTE)->get(); +} + +template <> +inline bool ListReader::getDataElement(ElementCount index) const { + // Ignore step for bit lists because bit lists cannot be upgraded to struct lists. + auto bindex = index * (ONE * BITS / ELEMENTS); + const byte* b = ptr + bindex / BITS_PER_BYTE; + return (*reinterpret_cast(b) & + unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0; +} + +template <> +inline Void ListReader::getDataElement(ElementCount index) const { + return VOID; +} + +inline PointerReader ListReader::getPointerElement(ElementCount index) const { + return PointerReader(segment, capTable, reinterpret_cast( + ptr + upgradeBound(index) * step / BITS_PER_BYTE), nestingLimit); +} + +// ------------------------------------------------------------------- + +inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept + : segment(other.segment), capTable(other.capTable), location(other.location) { + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; +} + +inline OrphanBuilder::~OrphanBuilder() noexcept(false) { + if (segment != nullptr) euthanize(); +} + +inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) { + // With normal smart pointers, it's important to handle the case where the incoming pointer + // is actually transitively owned by this one. In this case, euthanize() would destroy `other` + // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only + // owns message objects, and `other` is not itself a message object, therefore cannot possibly + // be transitively owned by `this`. + + if (segment != nullptr) euthanize(); + segment = other.segment; + capTable = other.capTable; + location = other.location; + memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules. + other.segment = nullptr; + other.location = nullptr; + return *this; +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_LAYOUT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/list.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/list.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,26 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "list.h" + +namespace capnp { + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/list.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,546 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_LIST_H_ +#define CAPNP_LIST_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "orphan.h" +#include +#ifdef KJ_STD_COMPAT +#include +#endif // KJ_STD_COMPAT + +namespace capnp { +namespace _ { // private + +template +class TemporaryPointer { + // This class is a little hack which lets us define operator->() in cases where it needs to + // return a pointer to a temporary value. We instead construct a TemporaryPointer and return that + // (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is + // able to return a real pointer to its member. + +public: + TemporaryPointer(T&& value): value(kj::mv(value)) {} + TemporaryPointer(const T& value): value(value) {} + + inline T* operator->() { return &value; } +private: + T value; +}; + +template +class IndexingIterator { +public: + IndexingIterator() = default; + + inline Element operator*() const { return (*container)[index]; } + inline TemporaryPointer operator->() const { + return TemporaryPointer((*container)[index]); + } + inline Element operator[]( int off) const { return (*container)[index]; } + inline Element operator[](uint off) const { return (*container)[index]; } + + inline IndexingIterator& operator++() { ++index; return *this; } + inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; } + inline IndexingIterator& operator--() { --index; return *this; } + inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; } + + inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); } + inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); } + inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); } + inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); } + + inline int operator-(const IndexingIterator& other) const { return index - other.index; } + + inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; } + inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; } + inline IndexingIterator& operator+=( int amount) { index += amount; return *this; } + inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; } + + // STL says comparing iterators of different containers is not allowed, so we only compare + // indices here. + inline bool operator==(const IndexingIterator& other) const { return index == other.index; } + inline bool operator!=(const IndexingIterator& other) const { return index != other.index; } + inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; } + inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; } + inline bool operator< (const IndexingIterator& other) const { return index < other.index; } + inline bool operator> (const IndexingIterator& other) const { return index > other.index; } + +private: + Container* container; + uint index; + + friend Container; + inline IndexingIterator(Container* container, uint index) + : container(container), index(index) {} +}; + +} // namespace _ (private) + +template +struct List { + // List of primitives. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(_::elementSizeForType()) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline T operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return reader.template getDataElement(bounded(index) * ELEMENTS); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(_::elementSizeForType()) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline T operator[](uint index) { + KJ_IREQUIRE(index < size()); + return builder.template getDataElement(bounded(index) * ELEMENTS); + } + inline void set(uint index, T value) { + // Alas, it is not possible to make operator[] return a reference to which you can assign, + // since the encoded representation does not necessarily match the compiler's representation + // of the type. We can't even return a clever class that implements operator T() and + // operator=() because it will lead to surprising behavior when using type inference (e.g. + // calling a template function with inferred argument types, or using "auto" or "decltype"). + + builder.template setDataElement(bounded(index) * ELEMENTS, value); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(_::elementSizeForType(), bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(_::elementSizeForType(), defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(_::elementSizeForType(), defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List: public List {}; + +template +struct List { + // List of structs. + + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename T::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename T::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); + } + + inline void adoptWithCaveats(uint index, Orphan&& orphan) { + // Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from + // the fact that structs in a struct list are allocated inline rather than by pointer: + // * This actually performs a shallow copy, effectively adopting each of the orphan's + // children rather than adopting the orphan itself. The orphan ends up being discarded, + // possibly wasting space in the message object. + // * If the orphan is larger than the target struct -- say, because the orphan was built + // using a newer version of the schema that has additional fields -- it will be truncated, + // losing data. + + KJ_IREQUIRE(index < size()); + + // We pass a zero-valued StructSize to asStruct() because we do not want the struct to be + // expanded under any circumstances. We're just going to throw it away anyway, and + // transferContentFrom() already carefully compares the struct sizes before transferring. + builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom( + orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); + } + inline void setWithCaveats(uint index, const typename T::Reader& reader) { + // Mostly behaves like you'd expect `set` to behave, but with a caveat originating from + // the fact that structs in a struct list are allocated inline rather than by pointer: + // If the source struct is larger than the target struct -- say, because the source was built + // using a newer version of the schema that has additional fields -- it will be truncated, + // losing data. + // + // Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to + // do it without losing any data in case the source lists come from a newer version of the + // protocol. (Plus, it's easier to use anyhow.) + + KJ_IREQUIRE(index < size()); + builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(reader._reader); + } + + // There are no init(), set(), adopt(), or disown() methods for lists of structs because the + // elements of the list are inlined and are initialized when the list is initialized. This + // means that init() would be redundant, and set() would risk data loss if the input struct + // were from a newer version of the protocol. + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initStructList(bounded(size) * ELEMENTS, _::structSize()); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getStructList(_::structSize(), defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List, Kind::LIST> { + // List of lists. + + List() = delete; + + class Reader { + public: + typedef List> Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename List::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return typename List::Reader(_::PointerHelpers>::get( + reader.getPointerElement(bounded(index) * ELEMENTS))); + } + + typedef _::IndexingIterator::Reader> Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List> Builds; + + inline Builder(): builder(ElementSize::POINTER) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename List::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return typename List::Builder(_::PointerHelpers>::get( + builder.getPointerElement(bounded(index) * ELEMENTS))); + } + inline typename List::Builder init(uint index, uint size) { + KJ_IREQUIRE(index < this->size()); + return typename List::Builder(_::PointerHelpers>::init( + builder.getPointerElement(bounded(index) * ELEMENTS), size)); + } + inline void set(uint index, typename List::Reader value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).setList(value.reader); + } + void set(uint index, std::initializer_list> value) { + KJ_IREQUIRE(index < size()); + auto l = init(index, value.size()); + uint i = 0; + for (auto& element: value) { + l.set(i++, element); + } + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator::Builder> Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +template +struct List { + List() = delete; + + class Reader { + public: + typedef List Reads; + + inline Reader(): reader(ElementSize::POINTER) {} + inline explicit Reader(_::ListReader reader): reader(reader) {} + + inline uint size() const { return unbound(reader.size() / ELEMENTS); } + inline typename T::Reader operator[](uint index) const { + KJ_IREQUIRE(index < size()); + return reader.getPointerElement(bounded(index) * ELEMENTS) + .template getBlob(nullptr, ZERO * BYTES); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + + private: + _::ListReader reader; + template + friend struct _::PointerHelpers; + template + friend struct List; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Builder { + public: + typedef List Builds; + + inline Builder(): builder(ElementSize::POINTER) {} + inline Builder(decltype(nullptr)): Builder() {} + inline explicit Builder(_::ListBuilder builder): builder(builder) {} + + inline operator Reader() const { return Reader(builder.asReader()); } + inline Reader asReader() const { return Reader(builder.asReader()); } + + inline uint size() const { return unbound(builder.size() / ELEMENTS); } + inline typename T::Builder operator[](uint index) { + KJ_IREQUIRE(index < size()); + return builder.getPointerElement(bounded(index) * ELEMENTS) + .template getBlob(nullptr, ZERO * BYTES); + } + inline void set(uint index, typename T::Reader value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).template setBlob(value); + } + inline typename T::Builder init(uint index, uint size) { + KJ_IREQUIRE(index < this->size()); + return builder.getPointerElement(bounded(index) * ELEMENTS) + .template initBlob(bounded(size) * BYTES); + } + inline void adopt(uint index, Orphan&& value) { + KJ_IREQUIRE(index < size()); + builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder)); + } + inline Orphan disown(uint index) { + KJ_IREQUIRE(index < size()); + return Orphan(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + private: + _::ListBuilder builder; + template + friend struct _::PointerHelpers; + friend class Orphanage; + template + friend struct ToDynamic_; + }; + + class Pipeline {}; + +private: + inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { + return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); + } + inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { + return builder.getList(ElementSize::POINTER, defaultValue); + } + inline static _::ListReader getFromPointer( + const _::PointerReader& reader, const word* defaultValue) { + return reader.getList(ElementSize::POINTER, defaultValue); + } + + template + friend struct List; + template + friend struct _::PointerHelpers; +}; + +} // namespace capnp + +#ifdef KJ_STD_COMPAT +namespace std { + +template +struct iterator_traits> + : public std::iterator {}; + +} // namespace std +#endif // KJ_STD_COMPAT + +#endif // CAPNP_LIST_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/membrane-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/membrane-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,335 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "membrane.h" +#include +#include "test-util.h" +#include +#include +#include "rpc-twoparty.h" + +namespace capnp { +namespace _ { +namespace { + +using Thing = test::TestMembrane::Thing; + +class ThingImpl final: public Thing::Server { +public: + ThingImpl(kj::StringPtr text): text(text) {} + +protected: + kj::Promise passThrough(PassThroughContext context) override { + context.getResults().setText(text); + return kj::READY_NOW; + } + + kj::Promise intercept(InterceptContext context) override { + context.getResults().setText(text); + return kj::READY_NOW; + } + +private: + kj::StringPtr text; +}; + +class TestMembraneImpl final: public test::TestMembrane::Server { +protected: + kj::Promise makeThing(MakeThingContext context) override { + context.getResults().setThing(kj::heap("inside")); + return kj::READY_NOW; + } + + kj::Promise callPassThrough(CallPassThroughContext context) override { + auto params = context.getParams(); + auto req = params.getThing().passThroughRequest(); + if (params.getTailCall()) { + return context.tailCall(kj::mv(req)); + } else { + return req.send().then( + [KJ_CPCAP(context)](Response&& result) mutable { + context.setResults(result); + }); + } + } + + kj::Promise callIntercept(CallInterceptContext context) override { + auto params = context.getParams(); + auto req = params.getThing().interceptRequest(); + if (params.getTailCall()) { + return context.tailCall(kj::mv(req)); + } else { + return req.send().then( + [KJ_CPCAP(context)](Response&& result) mutable { + context.setResults(result); + }); + } + } + + kj::Promise loopback(LoopbackContext context) override { + context.getResults().setThing(context.getParams().getThing()); + return kj::READY_NOW; + } +}; + +class MembranePolicyImpl: public MembranePolicy, public kj::Refcounted { +public: + kj::Maybe inboundCall(uint64_t interfaceId, uint16_t methodId, + Capability::Client target) override { + if (interfaceId == capnp::typeId() && methodId == 1) { + return Capability::Client(kj::heap("inbound")); + } else { + return nullptr; + } + } + + kj::Maybe outboundCall(uint64_t interfaceId, uint16_t methodId, + Capability::Client target) override { + if (interfaceId == capnp::typeId() && methodId == 1) { + return Capability::Client(kj::heap("outbound")); + } else { + return nullptr; + } + } + + kj::Own addRef() override { + return kj::addRef(*this); + } +}; + +void testThingImpl(kj::WaitScope& waitScope, test::TestMembrane::Client membraned, + kj::Function makeThing, + kj::StringPtr localPassThrough, kj::StringPtr localIntercept, + kj::StringPtr remotePassThrough, kj::StringPtr remoteIntercept) { + KJ_EXPECT(makeThing().passThroughRequest().send().wait(waitScope).getText() == localPassThrough); + KJ_EXPECT(makeThing().interceptRequest().send().wait(waitScope).getText() == localIntercept); + + { + auto req = membraned.callPassThroughRequest(); + req.setThing(makeThing()); + req.setTailCall(false); + KJ_EXPECT(req.send().wait(waitScope).getText() == remotePassThrough); + } + { + auto req = membraned.callInterceptRequest(); + req.setThing(makeThing()); + req.setTailCall(false); + KJ_EXPECT(req.send().wait(waitScope).getText() == remoteIntercept); + } + { + auto req = membraned.callPassThroughRequest(); + req.setThing(makeThing()); + req.setTailCall(true); + KJ_EXPECT(req.send().wait(waitScope).getText() == remotePassThrough); + } + { + auto req = membraned.callInterceptRequest(); + req.setThing(makeThing()); + req.setTailCall(true); + KJ_EXPECT(req.send().wait(waitScope).getText() == remoteIntercept); + } +} + +struct TestEnv { + kj::EventLoop loop; + kj::WaitScope waitScope; + kj::Own policy; + test::TestMembrane::Client membraned; + + TestEnv() + : waitScope(loop), + policy(kj::refcounted()), + membraned(membrane(kj::heap(), policy->addRef())) {} + + void testThing(kj::Function makeThing, + kj::StringPtr localPassThrough, kj::StringPtr localIntercept, + kj::StringPtr remotePassThrough, kj::StringPtr remoteIntercept) { + testThingImpl(waitScope, membraned, kj::mv(makeThing), + localPassThrough, localIntercept, remotePassThrough, remoteIntercept); + } +}; + +KJ_TEST("call local object inside membrane") { + TestEnv env; + env.testThing([&]() { + return env.membraned.makeThingRequest().send().wait(env.waitScope).getThing(); + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call local promise inside membrane") { + TestEnv env; + env.testThing([&]() { + return env.membraned.makeThingRequest().send().getThing(); + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call local resolved promise inside membrane") { + TestEnv env; + env.testThing([&]() { + auto thing = env.membraned.makeThingRequest().send().getThing(); + thing.whenResolved().wait(env.waitScope); + return thing; + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call local object outside membrane") { + TestEnv env; + env.testThing([&]() { + return kj::heap("outside"); + }, "outside", "outside", "outside", "outbound"); +} + +KJ_TEST("call local capability that has passed into and back out of membrane") { + TestEnv env; + env.testThing([&]() { + auto req = env.membraned.loopbackRequest(); + req.setThing(kj::heap("outside")); + return req.send().wait(env.waitScope).getThing(); + }, "outside", "outside", "outside", "outbound"); +} + +KJ_TEST("call local promise pointing into membrane that eventually resolves to outside") { + TestEnv env; + env.testThing([&]() { + auto req = env.membraned.loopbackRequest(); + req.setThing(kj::heap("outside")); + return req.send().getThing(); + }, "outside", "outside", "outside", "outbound"); +} + +KJ_TEST("apply membrane using copyOutOfMembrane() on struct") { + TestEnv env; + + env.testThing([&]() { + MallocMessageBuilder outsideBuilder; + auto root = outsideBuilder.initRoot(); + root.setCap(kj::heap("inside")); + MallocMessageBuilder insideBuilder; + insideBuilder.adoptRoot(copyOutOfMembrane( + root.asReader(), insideBuilder.getOrphanage(), env.policy->addRef())); + return insideBuilder.getRoot().getCap(); + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("apply membrane using copyOutOfMembrane() on list") { + TestEnv env; + + env.testThing([&]() { + MallocMessageBuilder outsideBuilder; + auto list = outsideBuilder.initRoot().initList(1); + list.set(0, kj::heap("inside")); + MallocMessageBuilder insideBuilder; + insideBuilder.initRoot().adoptList(copyOutOfMembrane( + list.asReader(), insideBuilder.getOrphanage(), env.policy->addRef())); + return insideBuilder.getRoot().getList()[0]; + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("apply membrane using copyOutOfMembrane() on AnyPointer") { + TestEnv env; + + env.testThing([&]() { + MallocMessageBuilder outsideBuilder; + auto ptr = outsideBuilder.initRoot().getAnyPointerField(); + ptr.setAs(kj::heap("inside")); + MallocMessageBuilder insideBuilder; + insideBuilder.initRoot().getAnyPointerField().adopt(copyOutOfMembrane( + ptr.asReader(), insideBuilder.getOrphanage(), env.policy->addRef())); + return insideBuilder.getRoot().getAnyPointerField() + .getAs(); + }, "inside", "inbound", "inside", "inside"); +} + +struct TestRpcEnv { + kj::AsyncIoContext io; + kj::TwoWayPipe pipe; + TwoPartyClient client; + TwoPartyClient server; + test::TestMembrane::Client membraned; + + TestRpcEnv() + : io(kj::setupAsyncIo()), + pipe(io.provider->newTwoWayPipe()), + client(*pipe.ends[0]), + server(*pipe.ends[1], + membrane(kj::heap(), kj::refcounted()), + rpc::twoparty::Side::SERVER), + membraned(client.bootstrap().castAs()) {} + + void testThing(kj::Function makeThing, + kj::StringPtr localPassThrough, kj::StringPtr localIntercept, + kj::StringPtr remotePassThrough, kj::StringPtr remoteIntercept) { + testThingImpl(io.waitScope, membraned, kj::mv(makeThing), + localPassThrough, localIntercept, remotePassThrough, remoteIntercept); + } +}; + +KJ_TEST("call remote object inside membrane") { + TestRpcEnv env; + env.testThing([&]() { + return env.membraned.makeThingRequest().send().wait(env.io.waitScope).getThing(); + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call remote promise inside membrane") { + TestRpcEnv env; + env.testThing([&]() { + return env.membraned.makeThingRequest().send().getThing(); + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call remote resolved promise inside membrane") { + TestEnv env; + env.testThing([&]() { + auto thing = env.membraned.makeThingRequest().send().getThing(); + thing.whenResolved().wait(env.waitScope); + return thing; + }, "inside", "inbound", "inside", "inside"); +} + +KJ_TEST("call remote object outside membrane") { + TestRpcEnv env; + env.testThing([&]() { + return kj::heap("outside"); + }, "outside", "outside", "outside", "outbound"); +} + +KJ_TEST("call remote capability that has passed into and back out of membrane") { + TestRpcEnv env; + env.testThing([&]() { + auto req = env.membraned.loopbackRequest(); + req.setThing(kj::heap("outside")); + return req.send().wait(env.io.waitScope).getThing(); + }, "outside", "outside", "outside", "outbound"); +} + +KJ_TEST("call remote promise pointing into membrane that eventually resolves to outside") { + TestRpcEnv env; + env.testThing([&]() { + auto req = env.membraned.loopbackRequest(); + req.setThing(kj::heap("outside")); + return req.send().getThing(); + }, "outside", "outside", "outside", "outbound"); +} + +} // namespace +} // namespace _ +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/membrane.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/membrane.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,487 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "membrane.h" +#include + +namespace capnp { + +namespace { + +static const char DUMMY = 0; +static constexpr const void* MEMBRANE_BRAND = &DUMMY; + +kj::Own membrane(kj::Own inner, MembranePolicy& policy, bool reverse); + +class MembraneCapTableReader final: public _::CapTableReader { +public: + MembraneCapTableReader(MembranePolicy& policy, bool reverse) + : policy(policy), reverse(reverse) {} + + AnyPointer::Reader imbue(AnyPointer::Reader reader) { + return AnyPointer::Reader(imbue( + _::PointerHelpers::getInternalReader(kj::mv(reader)))); + } + + _::PointerReader imbue(_::PointerReader reader) { + KJ_REQUIRE(inner == nullptr, "can only call this once"); + inner = reader.getCapTable(); + return reader.imbue(this); + } + + _::StructReader imbue(_::StructReader reader) { + KJ_REQUIRE(inner == nullptr, "can only call this once"); + inner = reader.getCapTable(); + return reader.imbue(this); + } + + _::ListReader imbue(_::ListReader reader) { + KJ_REQUIRE(inner == nullptr, "can only call this once"); + inner = reader.getCapTable(); + return reader.imbue(this); + } + + kj::Maybe> extractCap(uint index) override { + // The underlying message is inside the membrane, and we're pulling a cap out of it. Therefore, + // we want to wrap the extracted capability in the membrane. + return inner->extractCap(index).map([this](kj::Own&& cap) { + return membrane(kj::mv(cap), policy, reverse); + }); + } + +private: + _::CapTableReader* inner = nullptr; + MembranePolicy& policy; + bool reverse; +}; + +class MembraneCapTableBuilder final: public _::CapTableBuilder { +public: + MembraneCapTableBuilder(MembranePolicy& policy, bool reverse) + : policy(policy), reverse(reverse) {} + + AnyPointer::Builder imbue(AnyPointer::Builder builder) { + KJ_REQUIRE(inner == nullptr, "can only call this once"); + auto pointerBuilder = _::PointerHelpers::getInternalBuilder(kj::mv(builder)); + inner = pointerBuilder.getCapTable(); + return AnyPointer::Builder(pointerBuilder.imbue(this)); + } + + AnyPointer::Builder unimbue(AnyPointer::Builder builder) { + auto pointerBuilder = _::PointerHelpers::getInternalBuilder(kj::mv(builder)); + KJ_REQUIRE(pointerBuilder.getCapTable() == this); + return AnyPointer::Builder(pointerBuilder.imbue(inner)); + } + + kj::Maybe> extractCap(uint index) override { + // The underlying message is inside the membrane, and we're pulling a cap out of it. Therefore, + // we want to wrap the extracted capability in the membrane. + return inner->extractCap(index).map([this](kj::Own&& cap) { + return membrane(kj::mv(cap), policy, reverse); + }); + } + + uint injectCap(kj::Own&& cap) override { + // The underlying message is inside the membrane, and we're inserting a cap from outside into + // it. Therefore we want to add a reverse membrane. + return inner->injectCap(membrane(kj::mv(cap), policy, !reverse)); + } + + void dropCap(uint index) override { + inner->dropCap(index); + } + +private: + _::CapTableBuilder* inner = nullptr; + MembranePolicy& policy; + bool reverse; +}; + +class MembranePipelineHook final: public PipelineHook, public kj::Refcounted { +public: + MembranePipelineHook( + kj::Own&& inner, kj::Own&& policy, bool reverse) + : inner(kj::mv(inner)), policy(kj::mv(policy)), reverse(reverse) {} + + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) override { + return membrane(inner->getPipelinedCap(ops), *policy, reverse); + } + + kj::Own getPipelinedCap(kj::Array&& ops) override { + return membrane(inner->getPipelinedCap(kj::mv(ops)), *policy, reverse); + } + +private: + kj::Own inner; + kj::Own policy; + bool reverse; +}; + +class MembraneResponseHook final: public ResponseHook { +public: + MembraneResponseHook( + kj::Own&& inner, kj::Own&& policy, bool reverse) + : inner(kj::mv(inner)), policy(kj::mv(policy)), capTable(*this->policy, reverse) {} + + AnyPointer::Reader imbue(AnyPointer::Reader reader) { return capTable.imbue(reader); } + +private: + kj::Own inner; + kj::Own policy; + MembraneCapTableReader capTable; +}; + +class MembraneRequestHook final: public RequestHook { +public: + MembraneRequestHook(kj::Own&& inner, kj::Own&& policy, bool reverse) + : inner(kj::mv(inner)), policy(kj::mv(policy)), + reverse(reverse), capTable(*this->policy, reverse) {} + + static Request wrap( + Request&& inner, MembranePolicy& policy, bool reverse) { + AnyPointer::Builder builder = inner; + auto innerHook = RequestHook::from(kj::mv(inner)); + if (innerHook->getBrand() == MEMBRANE_BRAND) { + auto& otherMembrane = kj::downcast(*innerHook); + if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) { + // Request that passed across the membrane one way is now passing back the other way. + // Unwrap it rather than double-wrap it. + builder = otherMembrane.capTable.unimbue(builder); + return { builder, kj::mv(otherMembrane.inner) }; + } + } + + auto newHook = kj::heap(kj::mv(innerHook), policy.addRef(), reverse); + builder = newHook->capTable.imbue(builder); + return { builder, kj::mv(newHook) }; + } + + static kj::Own wrap( + kj::Own&& inner, MembranePolicy& policy, bool reverse) { + if (inner->getBrand() == MEMBRANE_BRAND) { + auto& otherMembrane = kj::downcast(*inner); + if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) { + // Request that passed across the membrane one way is now passing back the other way. + // Unwrap it rather than double-wrap it. + return kj::mv(otherMembrane.inner); + } + } + + return kj::heap(kj::mv(inner), policy.addRef(), reverse); + } + + RemotePromise send() override { + auto promise = inner->send(); + + auto newPipeline = AnyPointer::Pipeline(kj::refcounted( + PipelineHook::from(kj::mv(promise)), policy->addRef(), reverse)); + + bool reverse = this->reverse; // for capture + auto newPromise = promise.then(kj::mvCapture(policy, + [reverse](kj::Own&& policy, Response&& response) { + AnyPointer::Reader reader = response; + auto newRespHook = kj::heap( + ResponseHook::from(kj::mv(response)), policy->addRef(), reverse); + reader = newRespHook->imbue(reader); + return Response(reader, kj::mv(newRespHook)); + })); + + return RemotePromise(kj::mv(newPromise), kj::mv(newPipeline)); + } + + const void* getBrand() override { + return MEMBRANE_BRAND; + } + +private: + kj::Own inner; + kj::Own policy; + bool reverse; + MembraneCapTableBuilder capTable; +}; + +class MembraneCallContextHook final: public CallContextHook, public kj::Refcounted { +public: + MembraneCallContextHook(kj::Own&& inner, + kj::Own&& policy, bool reverse) + : inner(kj::mv(inner)), policy(kj::mv(policy)), reverse(reverse), + paramsCapTable(*this->policy, reverse), + resultsCapTable(*this->policy, reverse) {} + + AnyPointer::Reader getParams() override { + KJ_REQUIRE(!releasedParams); + KJ_IF_MAYBE(p, params) { + return *p; + } else { + auto result = paramsCapTable.imbue(inner->getParams()); + params = result; + return result; + } + } + + void releaseParams() override { + KJ_REQUIRE(!releasedParams); + releasedParams = true; + inner->releaseParams(); + } + + AnyPointer::Builder getResults(kj::Maybe sizeHint) override { + KJ_IF_MAYBE(r, results) { + return *r; + } else { + auto result = resultsCapTable.imbue(inner->getResults(sizeHint)); + results = result; + return result; + } + } + + kj::Promise tailCall(kj::Own&& request) override { + return inner->tailCall(MembraneRequestHook::wrap(kj::mv(request), *policy, !reverse)); + } + + void allowCancellation() override { + inner->allowCancellation(); + } + + kj::Promise onTailCall() override { + return inner->onTailCall().then([this](AnyPointer::Pipeline&& innerPipeline) { + return AnyPointer::Pipeline(kj::refcounted( + PipelineHook::from(kj::mv(innerPipeline)), policy->addRef(), reverse)); + }); + } + + ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) override { + auto pair = inner->directTailCall( + MembraneRequestHook::wrap(kj::mv(request), *policy, !reverse)); + + return { + kj::mv(pair.promise), + kj::refcounted(kj::mv(pair.pipeline), policy->addRef(), reverse) + }; + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + +private: + kj::Own inner; + kj::Own policy; + bool reverse; + + MembraneCapTableReader paramsCapTable; + kj::Maybe params; + bool releasedParams = false; + + MembraneCapTableBuilder resultsCapTable; + kj::Maybe results; +}; + +class MembraneHook final: public ClientHook, public kj::Refcounted { +public: + MembraneHook(kj::Own&& inner, kj::Own&& policy, bool reverse) + : inner(kj::mv(inner)), policy(kj::mv(policy)), reverse(reverse) {} + + static kj::Own wrap(ClientHook& cap, MembranePolicy& policy, bool reverse) { + if (cap.getBrand() == MEMBRANE_BRAND) { + auto& otherMembrane = kj::downcast(cap); + if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) { + // Capability that passed across the membrane one way is now passing back the other way. + // Unwrap it rather than double-wrap it. + return otherMembrane.inner->addRef(); + } + } + + return kj::refcounted(cap.addRef(), policy.addRef(), reverse); + } + + static kj::Own wrap(kj::Own cap, MembranePolicy& policy, bool reverse) { + if (cap->getBrand() == MEMBRANE_BRAND) { + auto& otherMembrane = kj::downcast(*cap); + if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) { + // Capability that passed across the membrane one way is now passing back the other way. + // Unwrap it rather than double-wrap it. + return otherMembrane.inner->addRef(); + } + } + + return kj::refcounted(kj::mv(cap), policy.addRef(), reverse); + } + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + KJ_IF_MAYBE(r, resolved) { + return r->get()->newCall(interfaceId, methodId, sizeHint); + } + + auto redirect = reverse + ? policy->outboundCall(interfaceId, methodId, Capability::Client(inner->addRef())) + : policy->inboundCall(interfaceId, methodId, Capability::Client(inner->addRef())); + KJ_IF_MAYBE(r, redirect) { + // The policy says that *if* this capability points into the membrane, then we want to + // redirect the call. However, if this capability is a promise, then it could resolve to + // something outside the membrane later. We have to wait before we actually redirect, + // otherwise behavior will differ depending on whether the promise is resolved. + KJ_IF_MAYBE(p, whenMoreResolved()) { + return newLocalPromiseClient(kj::mv(*p))->newCall(interfaceId, methodId, sizeHint); + } + + return ClientHook::from(kj::mv(*r))->newCall(interfaceId, methodId, sizeHint); + } else { + // For pass-through calls, we don't worry about promises, because if the capability resolves + // to something outside the membrane, then the call will pass back out of the membrane too. + return MembraneRequestHook::wrap( + inner->newCall(interfaceId, methodId, sizeHint), *policy, reverse); + } + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + KJ_IF_MAYBE(r, resolved) { + return r->get()->call(interfaceId, methodId, kj::mv(context)); + } + + auto redirect = reverse + ? policy->outboundCall(interfaceId, methodId, Capability::Client(inner->addRef())) + : policy->inboundCall(interfaceId, methodId, Capability::Client(inner->addRef())); + KJ_IF_MAYBE(r, redirect) { + // The policy says that *if* this capability points into the membrane, then we want to + // redirect the call. However, if this capability is a promise, then it could resolve to + // something outside the membrane later. We have to wait before we actually redirect, + // otherwise behavior will differ depending on whether the promise is resolved. + KJ_IF_MAYBE(p, whenMoreResolved()) { + return newLocalPromiseClient(kj::mv(*p))->call(interfaceId, methodId, kj::mv(context)); + } + + return ClientHook::from(kj::mv(*r))->call(interfaceId, methodId, kj::mv(context)); + } else { + // !reverse because calls to the CallContext go in the opposite direction. + auto result = inner->call(interfaceId, methodId, + kj::refcounted(kj::mv(context), policy->addRef(), !reverse)); + + return { + kj::mv(result.promise), + kj::refcounted(kj::mv(result.pipeline), policy->addRef(), reverse) + }; + } + } + + kj::Maybe getResolved() override { + KJ_IF_MAYBE(r, resolved) { + return **r; + } + + KJ_IF_MAYBE(newInner, inner->getResolved()) { + kj::Own newResolved = wrap(*newInner, *policy, reverse); + ClientHook& result = *newResolved; + resolved = kj::mv(newResolved); + return result; + } else { + return nullptr; + } + } + + kj::Maybe>> whenMoreResolved() override { + KJ_IF_MAYBE(r, resolved) { + return kj::Promise>(r->get()->addRef()); + } + + KJ_IF_MAYBE(promise, inner->whenMoreResolved()) { + return promise->then([this](kj::Own&& newInner) { + kj::Own newResolved = wrap(*newInner, *policy, reverse); + if (resolved == nullptr) { + resolved = newResolved->addRef(); + } + return newResolved; + }); + } else { + return nullptr; + } + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + const void* getBrand() override { + return MEMBRANE_BRAND; + } + +private: + kj::Own inner; + kj::Own policy; + bool reverse; + kj::Maybe> resolved; +}; + +kj::Own membrane(kj::Own inner, MembranePolicy& policy, bool reverse) { + return MembraneHook::wrap(kj::mv(inner), policy, reverse); +} + +} // namespace + +Capability::Client membrane(Capability::Client inner, kj::Own policy) { + return Capability::Client(membrane( + ClientHook::from(kj::mv(inner)), *policy, false)); +} + +Capability::Client reverseMembrane(Capability::Client inner, kj::Own policy) { + return Capability::Client(membrane( + ClientHook::from(kj::mv(inner)), *policy, true)); +} + +namespace _ { // private + +_::OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to, + kj::Own policy, bool reverse) { + MembraneCapTableReader capTable(*policy, reverse); + return _::OrphanBuilder::copy( + OrphanageInternal::getArena(to), + OrphanageInternal::getCapTable(to), + capTable.imbue(from)); +} + +_::OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to, + kj::Own policy, bool reverse) { + MembraneCapTableReader capTable(*policy, reverse); + return _::OrphanBuilder::copy( + OrphanageInternal::getArena(to), + OrphanageInternal::getCapTable(to), + capTable.imbue(from)); +} + +_::OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to, + kj::Own policy, bool reverse) { + MembraneCapTableReader capTable(*policy, reverse); + return _::OrphanBuilder::copy( + OrphanageInternal::getArena(to), + OrphanageInternal::getCapTable(to), + capTable.imbue(from)); +} + +} // namespace _ (private) + +} // namespace capnp + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/membrane.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/membrane.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,202 @@ +// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_MEMBRANE_H_ +#define CAPNP_MEMBRANE_H_ +// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards +// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a +// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely +// introducing new objects. +// +// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability +// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this +// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice +// indicates it should be revoked, after which all calls through the wrapper will throw exceptions. +// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new +// capability in that call, or if Carol returns a capability to Bob in the response to a call, then +// the two are now able to communicate using this new capability, which Alice cannot revoke. In +// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which +// recursively wraps all objects that pass through it in either direction. Thus, all connections +// formed between Bob and Carol (originating from Alice's original introduction) can be revoked +// together by revoking the membrane. +// +// Note that when a capability is passed into a membrane and then passed back out, the result is +// the original capability, not a double-membraned capability. This means that in our revocation +// example, if Bob uses his capability to Carol to obtain another capability from her, then send +// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to +// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use +// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then +// passed back can be recognized as the original capability. +// +// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html + +#include "capability.h" + +namespace capnp { + +class MembranePolicy { + // Applications may implement this interface to define a membrane policy, which allows some + // calls crossing the membrane to be blocked or redirected. + +public: + virtual kj::Maybe inboundCall( + uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; + // Given an inbound call (a call originating "outside" the membrane destined for an object + // "inside" the membrane), decides what to do with it. The policy may: + // + // - Return null to indicate that the call should proceed to the destination. All capabilities + // in the parameters or result will be properly wrapped in the same membrane. + // - Return a capability to have the call redirected to that capability. Note that the redirect + // capability will be treated as outside the membrane, so the params and results will not be + // auto-wrapped; however, the callee can easily wrap the returned capability in the membrane + // itself before returning to achieve this effect. + // - Throw an exception to cause the call to fail with that exception. + // + // `target` is the underlying capability (*inside* the membrane) for which the call is destined. + // Generally, the only way you should use `target` is to wrap it in some capability which you + // return as a redirect. The redirect capability may modify the call in some way and send it to + // `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when + // copying parameters or results across the membrane. + // + // Note that since `target` is inside the capability, if you were to directly return it (rather + // than return null), the effect would be that the membrane would be broken: the call would + // proceed directly and any new capabilities introduced through it would not be membraned. You + // generally should not do that. + + virtual kj::Maybe outboundCall( + uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; + // Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating + // outside. + // + // Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases + // that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would + // redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run + // into inconsistent behavion when a promise is returned across a membrane, and that promise + // later resolves to a capability on the other side of the membrane: calls on the promise + // will enter and then exit the membrane, but calls on the eventual resolution will not cross + // the membrane at all, so it is important that these two cases behave the same. + + virtual kj::Own addRef() = 0; + // Return a new owned pointer to the same policy. + // + // Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement + // `addRef()` as `return kj::addRef(*this);`. + // + // Note that the membraning system considers two membranes created with the same MembranePolicy + // object actually to be the *same* membrane. This is relevant when an object passes into the + // membrane and then back out (or out and then back in): instead of double-wrapping the object, + // the wrapping will be removed. +}; + +Capability::Client membrane(Capability::Client inner, kj::Own policy); +// Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane, +// while the returned capability should only be called from outside the membrane. + +Capability::Client reverseMembrane(Capability::Client outer, kj::Own policy); +// Like `membrane` but treat the input capability as "outside" the membrane, and return a +// capability appropriate for use inside. +// +// Applications typically won't use this directly; the membraning code automatically sets up +// reverse membranes where needed. + +template +ClientType membrane(ClientType inner, kj::Own policy); +template +ClientType reverseMembrane(ClientType inner, kj::Own policy); +// Convenience templates which return the same interface type as the input. + +template +typename ServerType::Serves::Client membrane( + kj::Own inner, kj::Own policy); +template +typename ServerType::Serves::Client reverseMembrane( + kj::Own inner, kj::Own policy); +// Convenience templates which input a capability server type and return the appropriate client +// type. + +template +Orphan::Reads> copyIntoMembrane( + Reader&& from, Orphanage to, kj::Own policy); +// Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities +// found within it. `from` is interpreted as "outside" the membrane while `to` is "inside". + +template +Orphan::Reads> copyOutOfMembrane( + Reader&& from, Orphanage to, kj::Own policy); +// Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside". + +// ======================================================================================= +// inline implementation details + +template +ClientType membrane(ClientType inner, kj::Own policy) { + return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} +template +ClientType reverseMembrane(ClientType inner, kj::Own policy) { + return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} + +template +typename ServerType::Serves::Client membrane( + kj::Own inner, kj::Own policy) { + return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} +template +typename ServerType::Serves::Client reverseMembrane( + kj::Own inner, kj::Own policy) { + return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) + .castAs(); +} + +namespace _ { // private + +OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to, + kj::Own policy, bool reverse); +OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to, + kj::Own policy, bool reverse); +OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to, + kj::Own policy, bool reverse); + +} // namespace _ (private) + +template +Orphan::Reads> copyIntoMembrane( + Reader&& from, Orphanage to, kj::Own policy) { + return _::copyOutOfMembrane( + _::PointerHelpers::Reads>::getInternalReader(from), + to, kj::mv(policy), true); +} + +template +Orphan::Reads> copyOutOfMembrane( + Reader&& from, Orphanage to, kj::Own policy) { + return _::copyOutOfMembrane( + _::PointerHelpers::Reads>::getInternalReader(from), + to, kj::mv(policy), false); +} + +} // namespace capnp + +#endif // CAPNP_MEMBRANE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/message-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/message-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,175 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "message.h" +#include "test-util.h" +#include +#include +#include +#include + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Message, MallocBuilderWithFirstSegment) { + word scratch[16]; + memset(scratch, 0, sizeof(scratch)); + MallocMessageBuilder builder(kj::arrayPtr(scratch, 16), AllocationStrategy::FIXED_SIZE); + + kj::ArrayPtr segment = builder.allocateSegment(1); + EXPECT_EQ(scratch, segment.begin()); + EXPECT_EQ(16u, segment.size()); + + segment = builder.allocateSegment(1); + EXPECT_NE(scratch, segment.begin()); + EXPECT_EQ(16u, segment.size()); + + segment = builder.allocateSegment(1); + EXPECT_NE(scratch, segment.begin()); + EXPECT_EQ(16u, segment.size()); +} + +class TestInitMessageBuilder: public MessageBuilder { +public: + TestInitMessageBuilder(kj::ArrayPtr segments): MessageBuilder(segments) {} + + kj::ArrayPtr allocateSegment(uint minimumSize) override { + auto array = kj::heapArray(minimumSize); + memset(array.begin(), 0, array.asBytes().size()); + allocations.add(kj::mv(array)); + return allocations.back(); + } + + kj::Vector> allocations; +}; + +TEST(Message, MessageBuilderInit) { + MallocMessageBuilder builder(2048); + initTestMessage(builder.getRoot()); + + // Pull the segments out and make a segment init table out of them. + // + // We const_cast for simplicity of implementing the test, but you shouldn't do that at home. :) + auto segs = builder.getSegmentsForOutput(); + ASSERT_EQ(1, segs.size()); + + auto segInits = KJ_MAP(seg, segs) -> MessageBuilder::SegmentInit { + return { kj::arrayPtr(const_cast(seg.begin()), seg.size()), seg.size() }; + }; + + // Init a new builder from the old segments. + TestInitMessageBuilder builder2(segInits); + checkTestMessage(builder2.getRoot()); + + // Verify that they're really using the same underlying memory. + builder2.getRoot().setInt64Field(123321); + EXPECT_EQ(123321, builder.getRoot().getInt64Field()); + + // Force builder2 to allocate new space. + EXPECT_EQ(0, builder2.allocations.size()); + builder2.getRoot().setTextField("foobarbaz"); + EXPECT_EQ(1, builder2.allocations.size()); +} + +TEST(Message, MessageBuilderInitMultiSegment) { + // Same as previous test, but with a message containing many segments. + + MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE); + initTestMessage(builder.getRoot()); + + // Pull the segments out and make a segment init table out of them. + // + // We const_cast for simplicity of implementing the test, but you shouldn't do that at home. :) + auto segs = builder.getSegmentsForOutput(); + ASSERT_NE(1, segs.size()); + + auto segInits = KJ_MAP(seg, segs) -> MessageBuilder::SegmentInit { + return { kj::arrayPtr(const_cast(seg.begin()), seg.size()), seg.size() }; + }; + + // Init a new builder from the old segments. + TestInitMessageBuilder builder2(segInits); + checkTestMessage(builder2.getRoot()); + + // Verify that they're really using the same underlying memory. + builder2.getRoot().setInt64Field(123321); + EXPECT_EQ(123321, builder.getRoot().getInt64Field()); + + // Force builder2 to allocate new space. + EXPECT_EQ(0, builder2.allocations.size()); + builder2.getRoot().setTextField("foobarbaz"); + EXPECT_EQ(1, builder2.allocations.size()); +} + +TEST(Message, MessageBuilderInitSpaceAvailable) { + word buffer[2048]; + memset(buffer, 0, sizeof(buffer)); + MallocMessageBuilder builder(buffer); + initTestMessage(builder.getRoot()); + + // Find out how much space in `buffer` was used in order to use in initializing the new message. + auto segs = builder.getSegmentsForOutput(); + ASSERT_EQ(1, segs.size()); + KJ_ASSERT(segs[0].begin() == buffer); + + MessageBuilder::SegmentInit init = { kj::ArrayPtr(buffer), segs[0].size() }; + + // Init a new builder from the old segments. + TestInitMessageBuilder builder2(kj::arrayPtr(&init, 1)); + checkTestMessage(builder2.getRoot()); + + // Verify that they're really using the same underlying memory. + builder2.getRoot().setInt64Field(123321); + EXPECT_EQ(123321, builder.getRoot().getInt64Field()); + + // Ask builder2 to allocate new space. It should go into the free space at the end of the + // segment. + EXPECT_EQ(0, builder2.allocations.size()); + builder2.getRoot().setTextField("foobarbaz"); + EXPECT_EQ(0, builder2.allocations.size()); + + EXPECT_EQ(kj::implicitCast(buffer + segs[0].size()), + kj::implicitCast(builder2.getRoot().getTextField().begin())); +} + +TEST(Message, ReadWriteDataStruct) { + MallocMessageBuilder builder; + auto root = builder.getRoot(); + + root.setUInt32Field(123); + root.setFloat64Field(1.5); + root.setTextField("foo"); + + auto copy = readDataStruct(writeDataStruct(root)); + EXPECT_EQ(123, copy.getUInt32Field()); + EXPECT_EQ(1.5, copy.getFloat64Field()); + EXPECT_FALSE(copy.hasTextField()); + + checkTestMessageAllZero(readDataStruct(nullptr)); + checkTestMessageAllZero(defaultValue()); +} + +// TODO(test): More tests. + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/message.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/message.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,312 @@ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE +#include "message.h" +#include +#include "arena.h" +#include "orphan.h" +#include +#include +#include +#include +#include + +namespace capnp { + +namespace { + +class DummyCapTableReader: public _::CapTableReader { +public: +#if !CAPNP_LITE + kj::Maybe> extractCap(uint index) override { + return nullptr; + } +#endif +}; +static KJ_CONSTEXPR(const) DummyCapTableReader dummyCapTableReader = DummyCapTableReader(); + +} // namespace + +MessageReader::MessageReader(ReaderOptions options): options(options), allocatedArena(false) {} +MessageReader::~MessageReader() noexcept(false) { + if (allocatedArena) { + arena()->~ReaderArena(); + } +} + +bool MessageReader::isCanonical() { + if (!allocatedArena) { + static_assert(sizeof(_::ReaderArena) <= sizeof(arenaSpace), + "arenaSpace is too small to hold a ReaderArena. Please increase it. This will break " + "ABI compatibility."); + new(arena()) _::ReaderArena(this); + allocatedArena = true; + } + + _::SegmentReader *segment = arena()->tryGetSegment(_::SegmentId(0)); + + if (segment == NULL) { + // The message has no segments + return false; + } + + if (arena()->tryGetSegment(_::SegmentId(1))) { + // The message has more than one segment + return false; + } + + const word* readHead = segment->getStartPtr() + 1; + bool rootIsCanonical = _::PointerReader::getRoot(segment, nullptr, + segment->getStartPtr(), + this->getOptions().nestingLimit) + .isCanonical(&readHead); + bool allWordsConsumed = segment->getOffsetTo(readHead) == segment->getSize(); + return rootIsCanonical && allWordsConsumed; +} + + +AnyPointer::Reader MessageReader::getRootInternal() { + if (!allocatedArena) { + static_assert(sizeof(_::ReaderArena) <= sizeof(arenaSpace), + "arenaSpace is too small to hold a ReaderArena. Please increase it. This will break " + "ABI compatibility."); + new(arena()) _::ReaderArena(this); + allocatedArena = true; + } + + _::SegmentReader* segment = arena()->tryGetSegment(_::SegmentId(0)); + KJ_REQUIRE(segment != nullptr && + segment->checkObject(segment->getStartPtr(), ONE * WORDS), + "Message did not contain a root pointer.") { + return AnyPointer::Reader(); + } + + // const_cast here is safe because dummyCapTableReader has no state. + return AnyPointer::Reader(_::PointerReader::getRoot( + segment, const_cast(&dummyCapTableReader), + segment->getStartPtr(), options.nestingLimit)); +} + +// ------------------------------------------------------------------- + +MessageBuilder::MessageBuilder(): allocatedArena(false) {} + +MessageBuilder::~MessageBuilder() noexcept(false) { + if (allocatedArena) { + kj::dtor(*arena()); + } +} + +MessageBuilder::MessageBuilder(kj::ArrayPtr segments) + : allocatedArena(false) { + kj::ctor(*arena(), this, segments); + allocatedArena = true; +} + +_::SegmentBuilder* MessageBuilder::getRootSegment() { + if (allocatedArena) { + return arena()->getSegment(_::SegmentId(0)); + } else { + static_assert(sizeof(_::BuilderArena) <= sizeof(arenaSpace), + "arenaSpace is too small to hold a BuilderArena. Please increase it."); + kj::ctor(*arena(), this); + allocatedArena = true; + + auto allocation = arena()->allocate(POINTER_SIZE_IN_WORDS); + + KJ_ASSERT(allocation.segment->getSegmentId() == _::SegmentId(0), + "First allocated word of new arena was not in segment ID 0."); + KJ_ASSERT(allocation.words == allocation.segment->getPtrUnchecked(ZERO * WORDS), + "First allocated word of new arena was not the first word in its segment."); + return allocation.segment; + } +} + +AnyPointer::Builder MessageBuilder::getRootInternal() { + _::SegmentBuilder* rootSegment = getRootSegment(); + return AnyPointer::Builder(_::PointerBuilder::getRoot( + rootSegment, arena()->getLocalCapTable(), rootSegment->getPtrUnchecked(ZERO * WORDS))); +} + +kj::ArrayPtr> MessageBuilder::getSegmentsForOutput() { + if (allocatedArena) { + return arena()->getSegmentsForOutput(); + } else { + return nullptr; + } +} + +Orphanage MessageBuilder::getOrphanage() { + // We must ensure that the arena and root pointer have been allocated before the Orphanage + // can be used. + if (!allocatedArena) getRootSegment(); + + return Orphanage(arena(), arena()->getLocalCapTable()); +} + +bool MessageBuilder::isCanonical() { + _::SegmentReader *segment = getRootSegment(); + + if (segment == NULL) { + // The message has no segments + return false; + } + + if (arena()->tryGetSegment(_::SegmentId(1))) { + // The message has more than one segment + return false; + } + + const word* readHead = segment->getStartPtr() + 1; + return _::PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), kj::maxValue) + .isCanonical(&readHead); +} + +// ======================================================================================= + +SegmentArrayMessageReader::SegmentArrayMessageReader( + kj::ArrayPtr> segments, ReaderOptions options) + : MessageReader(options), segments(segments) {} + +SegmentArrayMessageReader::~SegmentArrayMessageReader() noexcept(false) {} + +kj::ArrayPtr SegmentArrayMessageReader::getSegment(uint id) { + if (id < segments.size()) { + return segments[id]; + } else { + return nullptr; + } +} + +// ------------------------------------------------------------------- + +struct MallocMessageBuilder::MoreSegments { + std::vector segments; +}; + +MallocMessageBuilder::MallocMessageBuilder( + uint firstSegmentWords, AllocationStrategy allocationStrategy) + : nextSize(firstSegmentWords), allocationStrategy(allocationStrategy), + ownFirstSegment(true), returnedFirstSegment(false), firstSegment(nullptr) {} + +MallocMessageBuilder::MallocMessageBuilder( + kj::ArrayPtr firstSegment, AllocationStrategy allocationStrategy) + : nextSize(firstSegment.size()), allocationStrategy(allocationStrategy), + ownFirstSegment(false), returnedFirstSegment(false), firstSegment(firstSegment.begin()) { + KJ_REQUIRE(firstSegment.size() > 0, "First segment size must be non-zero."); + + // Checking just the first word should catch most cases of failing to zero the segment. + KJ_REQUIRE(*reinterpret_cast(firstSegment.begin()) == 0, + "First segment must be zeroed."); +} + +MallocMessageBuilder::~MallocMessageBuilder() noexcept(false) { + if (returnedFirstSegment) { + if (ownFirstSegment) { + free(firstSegment); + } else { + // Must zero first segment. + kj::ArrayPtr> segments = getSegmentsForOutput(); + if (segments.size() > 0) { + KJ_ASSERT(segments[0].begin() == firstSegment, + "First segment in getSegmentsForOutput() is not the first segment allocated?"); + memset(firstSegment, 0, segments[0].size() * sizeof(word)); + } + } + + KJ_IF_MAYBE(s, moreSegments) { + for (void* ptr: s->get()->segments) { + free(ptr); + } + } + } +} + +kj::ArrayPtr MallocMessageBuilder::allocateSegment(uint minimumSize) { + KJ_REQUIRE(bounded(minimumSize) * WORDS <= MAX_SEGMENT_WORDS, + "MallocMessageBuilder asked to allocate segment above maximum serializable size."); + KJ_ASSERT(bounded(nextSize) * WORDS <= MAX_SEGMENT_WORDS, + "MallocMessageBuilder nextSize out of bounds."); + + if (!returnedFirstSegment && !ownFirstSegment) { + kj::ArrayPtr result = kj::arrayPtr(reinterpret_cast(firstSegment), nextSize); + if (result.size() >= minimumSize) { + returnedFirstSegment = true; + return result; + } + // If the provided first segment wasn't big enough, we discard it and proceed to allocate + // our own. This never happens in practice since minimumSize is always 1 for the first + // segment. + ownFirstSegment = true; + } + + uint size = kj::max(minimumSize, nextSize); + + void* result = calloc(size, sizeof(word)); + if (result == nullptr) { + KJ_FAIL_SYSCALL("calloc(size, sizeof(word))", ENOMEM, size); + } + + if (!returnedFirstSegment) { + firstSegment = result; + returnedFirstSegment = true; + + // After the first segment, we want nextSize to equal the total size allocated so far. + if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) nextSize = size; + } else { + MoreSegments* segments; + KJ_IF_MAYBE(s, moreSegments) { + segments = *s; + } else { + auto newSegments = kj::heap(); + segments = newSegments; + moreSegments = mv(newSegments); + } + segments->segments.push_back(result); + if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) { + // set nextSize = min(nextSize+size, MAX_SEGMENT_WORDS) + // while protecting against possible overflow of (nextSize+size) + nextSize = (size <= unbound(MAX_SEGMENT_WORDS / WORDS) - nextSize) + ? nextSize + size : unbound(MAX_SEGMENT_WORDS / WORDS); + } + } + + return kj::arrayPtr(reinterpret_cast(result), size); +} + +// ------------------------------------------------------------------- + +FlatMessageBuilder::FlatMessageBuilder(kj::ArrayPtr array): array(array), allocated(false) {} +FlatMessageBuilder::~FlatMessageBuilder() noexcept(false) {} + +void FlatMessageBuilder::requireFilled() { + KJ_REQUIRE(getSegmentsForOutput()[0].end() == array.end(), + "FlatMessageBuilder's buffer was too large."); +} + +kj::ArrayPtr FlatMessageBuilder::allocateSegment(uint minimumSize) { + KJ_REQUIRE(!allocated, "FlatMessageBuilder's buffer was not large enough."); + allocated = true; + return array; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/message.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/message.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,508 @@ +// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include +#include "common.h" +#include "layout.h" +#include "any.h" + +#ifndef CAPNP_MESSAGE_H_ +#define CAPNP_MESSAGE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +namespace capnp { + +namespace _ { // private + class ReaderArena; + class BuilderArena; +} + +class StructSchema; +class Orphanage; +template +class Orphan; + +// ======================================================================================= + +struct ReaderOptions { + // Options controlling how data is read. + + uint64_t traversalLimitInWords = 8 * 1024 * 1024; + // Limits how many total words of data are allowed to be traversed. Traversal is counted when + // a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling + // the getter for the same sub-struct multiple times will cause it to be double-counted. Once + // the traversal limit is reached, an error will be reported. + // + // This limit exists for security reasons. It is possible for an attacker to construct a message + // in which multiple pointers point at the same location. This is technically invalid, but hard + // to detect. Using such a message, an attacker could cause a message which is small on the wire + // to appear much larger when actually traversed, possibly exhausting server resources leading to + // denial-of-service. + // + // It makes sense to set a traversal limit that is much larger than the underlying message. + // Together with sensible coding practices (e.g. trying to avoid calling sub-object getters + // multiple times, which is expensive anyway), this should provide adequate protection without + // inconvenience. + // + // The default limit is 64 MiB. This may or may not be a sensible number for any given use case, + // but probably at least prevents easy exploitation while also avoiding causing problems in most + // typical cases. + + int nestingLimit = 64; + // Limits how deeply-nested a message structure can be, e.g. structs containing other structs or + // lists of structs. + // + // Like the traversal limit, this limit exists for security reasons. Since it is common to use + // recursive code to traverse recursive data structures, an attacker could easily cause a stack + // overflow by sending a very-deeply-nested (or even cyclic) message, without the message even + // being very large. The default limit of 64 is probably low enough to prevent any chance of + // stack overflow, yet high enough that it is never a problem in practice. +}; + +class MessageReader { + // Abstract interface for an object used to read a Cap'n Proto message. Subclasses of + // MessageReader are responsible for reading the raw, flat message content. Callers should + // usually call `messageReader.getRoot()` to get a `MyStructType::Reader` + // representing the root of the message, then use that to traverse the message content. + // + // Some common subclasses of `MessageReader` include `SegmentArrayMessageReader`, whose + // constructor accepts pointers to the raw data, and `StreamFdMessageReader` (from + // `serialize.h`), which reads the message from a file descriptor. One might implement other + // subclasses to handle things like reading from shared memory segments, mmap()ed files, etc. + +public: + MessageReader(ReaderOptions options); + // It is suggested that subclasses take ReaderOptions as a constructor parameter, but give it a + // default value of "ReaderOptions()". The base class constructor doesn't have a default value + // in order to remind subclasses that they really need to give the user a way to provide this. + + virtual ~MessageReader() noexcept(false); + + virtual kj::ArrayPtr getSegment(uint id) = 0; + // Gets the segment with the given ID, or returns null if no such segment exists. This method + // will be called at most once for each segment ID. + + inline const ReaderOptions& getOptions(); + // Get the options passed to the constructor. + + template + typename RootType::Reader getRoot(); + // Get the root struct of the message, interpreting it as the given struct type. + + template + typename RootType::Reader getRoot(SchemaType schema); + // Dynamically interpret the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + bool isCanonical(); + // Returns whether the message encoded in the reader is in canonical form. + +private: + ReaderOptions options; + + // Space in which we can construct a ReaderArena. We don't use ReaderArena directly here + // because we don't want clients to have to #include arena.h, which itself includes a bunch of + // big STL headers. We don't use a pointer to a ReaderArena because that would require an + // extra malloc on every message which could be expensive when processing small messages. + void* arenaSpace[15 + sizeof(kj::MutexGuarded) / sizeof(void*)]; + bool allocatedArena; + + _::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); } + AnyPointer::Reader getRootInternal(); +}; + +class MessageBuilder { + // Abstract interface for an object used to allocate and build a message. Subclasses of + // MessageBuilder are responsible for allocating the space in which the message will be written. + // The most common subclass is `MallocMessageBuilder`, but other subclasses may be used to do + // tricky things like allocate messages in shared memory or mmap()ed files. + // + // Creating a new message ususually means allocating a new MessageBuilder (ideally on the stack) + // and then calling `messageBuilder.initRoot()` to get a `MyStructType::Builder`. + // That, in turn, can be used to fill in the message content. When done, you can call + // `messageBuilder.getSegmentsForOutput()` to get a list of flat data arrays containing the + // message. + +public: + MessageBuilder(); + virtual ~MessageBuilder() noexcept(false); + KJ_DISALLOW_COPY(MessageBuilder); + + struct SegmentInit { + kj::ArrayPtr space; + + size_t wordsUsed; + // Number of words in `space` which are used; the rest are free space in which additional + // objects may be allocated. + }; + + explicit MessageBuilder(kj::ArrayPtr segments); + // Create a MessageBuilder backed by existing memory. This is an advanced interface that most + // people should not use. THIS METHOD IS INSECURE; see below. + // + // This allows a MessageBuilder to be constructed to modify an in-memory message without first + // making a copy of the content. This is especially useful in conjunction with mmap(). + // + // The contents of each segment must outlive the MessageBuilder, but the SegmentInit array itself + // only need outlive the constructor. + // + // SECURITY: Do not use this in conjunction with untrusted data. This constructor assumes that + // the input message is valid. This constructor is designed to be used with data you control, + // e.g. an mmap'd file which is owned and accessed by only one program. When reading data you + // do not trust, you *must* load it into a Reader and then copy into a Builder as a means of + // validating the content. + // + // WARNING: It is NOT safe to initialize a MessageBuilder in this way from memory that is + // currently in use by another MessageBuilder or MessageReader. Other readers/builders will + // not observe changes to the segment sizes nor newly-allocated segments caused by allocating + // new objects in this message. + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) = 0; + // Allocates an array of at least the given number of words, throwing an exception or crashing if + // this is not possible. It is expected that this method will usually return more space than + // requested, and the caller should use that extra space as much as possible before allocating + // more. The returned space remains valid at least until the MessageBuilder is destroyed. + // + // Cap'n Proto will only call this once at a time, so the subclass need not worry about + // thread-safety. + + template + typename RootType::Builder initRoot(); + // Initialize the root struct of the message as the given struct type. + + template + void setRoot(Reader&& value); + // Set the root struct to a deep copy of the given struct. + + template + typename RootType::Builder getRoot(); + // Get the root struct of the message, interpreting it as the given struct type. + + template + typename RootType::Builder getRoot(SchemaType schema); + // Dynamically interpret the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + template + typename RootType::Builder initRoot(SchemaType schema); + // Dynamically init the root struct of the message using the given schema (a StructSchema). + // RootType in this case must be DynamicStruct, and you must #include to + // use this. + + template + void adoptRoot(Orphan&& orphan); + // Like setRoot() but adopts the orphan without copying. + + kj::ArrayPtr> getSegmentsForOutput(); + // Get the raw data that makes up the message. + + Orphanage getOrphanage(); + + bool isCanonical(); + // Check whether the message builder is in canonical form + +private: + void* arenaSpace[22]; + // Space in which we can construct a BuilderArena. We don't use BuilderArena directly here + // because we don't want clients to have to #include arena.h, which itself includes a bunch of + // big STL headers. We don't use a pointer to a BuilderArena because that would require an + // extra malloc on every message which could be expensive when processing small messages. + + bool allocatedArena = false; + // We have to initialize the arena lazily because when we do so we want to allocate the root + // pointer immediately, and this will allocate a segment, which requires a virtual function + // call on the MessageBuilder. We can't do such a call in the constructor since the subclass + // isn't constructed yet. This is kind of annoying because it means that getOrphanage() is + // not thread-safe, but that shouldn't be a huge deal... + + _::BuilderArena* arena() { return reinterpret_cast<_::BuilderArena*>(arenaSpace); } + _::SegmentBuilder* getRootSegment(); + AnyPointer::Builder getRootInternal(); +}; + +template +typename RootType::Reader readMessageUnchecked(const word* data); +// IF THE INPUT IS INVALID, THIS MAY CRASH, CORRUPT MEMORY, CREATE A SECURITY HOLE IN YOUR APP, +// MURDER YOUR FIRST-BORN CHILD, AND/OR BRING ABOUT ETERNAL DAMNATION ON ALL OF HUMANITY. DO NOT +// USE UNLESS YOU UNDERSTAND THE CONSEQUENCES. +// +// Given a pointer to a known-valid message located in a single contiguous memory segment, +// returns a reader for that message. No bounds-checking will be done while traversing this +// message. Use this only if you have already verified that all pointers are valid and in-bounds, +// and there are no far pointers in the message. +// +// To create a message that can be passed to this function, build a message using a MallocAllocator +// whose preferred segment size is larger than the message size. This guarantees that the message +// will be allocated as a single segment, meaning getSegmentsForOutput() returns a single word +// array. That word array is your message; you may pass a pointer to its first word into +// readMessageUnchecked() to read the message. +// +// This can be particularly handy for embedding messages in generated code: you can +// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way +// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have +// a message MyMessage, you can read its default value like so: +// MyMessage::Reader reader = Message::readMessageUnchecked(MyMessage::DEFAULT.words); +// +// To sanitize a message from an untrusted source such that it can be safely passed to +// readMessageUnchecked(), use copyToUnchecked(). + +template +void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer); +// Copy the content of the given reader into the given buffer, such that it can safely be passed to +// readMessageUnchecked(). The buffer's size must be exactly reader.totalSizeInWords() + 1, +// otherwise an exception will be thrown. The buffer must be zero'd before calling. + +template +typename RootType::Reader readDataStruct(kj::ArrayPtr data); +// Interprets the given data as a single, data-only struct. Only primitive fields (booleans, +// numbers, and enums) will be readable; all pointers will be null. This is useful if you want +// to use Cap'n Proto as a language/platform-neutral way to pack some bits. +// +// The input is a word array rather than a byte array to enforce alignment. If you have a byte +// array which you know is word-aligned (or if your platform supports unaligned reads and you don't +// mind the performance penalty), then you can use `reinterpret_cast` to convert a byte array into +// a word array: +// +// kj::arrayPtr(reinterpret_cast(bytes.begin()), +// reinterpret_cast(bytes.end())) + +template +typename kj::ArrayPtr writeDataStruct(BuilderType builder); +// Given a struct builder, get the underlying data section as a word array, suitable for passing +// to `readDataStruct()`. +// +// Note that you may call `.toBytes()` on the returned value to convert to `ArrayPtr`. + +template +static typename Type::Reader defaultValue(); +// Get a default instance of the given struct or list type. +// +// TODO(cleanup): Find a better home for this function? + +// ======================================================================================= + +class SegmentArrayMessageReader: public MessageReader { + // A simple MessageReader that reads from an array of word arrays representing all segments. + // In particular you can read directly from the output of MessageBuilder::getSegmentsForOutput() + // (although it would probably make more sense to call builder.getRoot().asReader() in that case). + +public: + SegmentArrayMessageReader(kj::ArrayPtr> segments, + ReaderOptions options = ReaderOptions()); + // Creates a message pointing at the given segment array, without taking ownership of the + // segments. All arrays passed in must remain valid until the MessageReader is destroyed. + + KJ_DISALLOW_COPY(SegmentArrayMessageReader); + ~SegmentArrayMessageReader() noexcept(false); + + virtual kj::ArrayPtr getSegment(uint id) override; + +private: + kj::ArrayPtr> segments; +}; + +enum class AllocationStrategy: uint8_t { + FIXED_SIZE, + // The builder will prefer to allocate the same amount of space for each segment with no + // heuristic growth. It will still allocate larger segments when the preferred size is too small + // for some single object. This mode is generally not recommended, but can be particularly useful + // for testing in order to force a message to allocate a predictable number of segments. Note + // that you can force every single object in the message to be located in a separate segment by + // using this mode with firstSegmentWords = 0. + + GROW_HEURISTICALLY + // The builder will heuristically decide how much space to allocate for each segment. Each + // allocated segment will be progressively larger than the previous segments on the assumption + // that message sizes are exponentially distributed. The total number of segments that will be + // allocated for a message of size n is O(log n). +}; + +constexpr uint SUGGESTED_FIRST_SEGMENT_WORDS = 1024; +constexpr AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy::GROW_HEURISTICALLY; + +class MallocMessageBuilder: public MessageBuilder { + // A simple MessageBuilder that uses malloc() (actually, calloc()) to allocate segments. This + // implementation should be reasonable for any case that doesn't require writing the message to + // a specific location in memory. + +public: + explicit MallocMessageBuilder(uint firstSegmentWords = SUGGESTED_FIRST_SEGMENT_WORDS, + AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); + // Creates a BuilderContext which allocates at least the given number of words for the first + // segment, and then uses the given strategy to decide how much to allocate for subsequent + // segments. When choosing a value for firstSegmentWords, consider that: + // 1) Reading and writing messages gets slower when multiple segments are involved, so it's good + // if most messages fit in a single segment. + // 2) Unused bytes will not be written to the wire, so generally it is not a big deal to allocate + // more space than you need. It only becomes problematic if you are allocating many messages + // in parallel and thus use lots of memory, or if you allocate so much extra space that just + // zeroing it out becomes a bottleneck. + // The defaults have been chosen to be reasonable for most people, so don't change them unless you + // have reason to believe you need to. + + explicit MallocMessageBuilder(kj::ArrayPtr firstSegment, + AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY); + // This version always returns the given array for the first segment, and then proceeds with the + // allocation strategy. This is useful for optimization when building lots of small messages in + // a tight loop: you can reuse the space for the first segment. + // + // firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros + // over any space that was used so that it can be reused. + + KJ_DISALLOW_COPY(MallocMessageBuilder); + virtual ~MallocMessageBuilder() noexcept(false); + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; + +private: + uint nextSize; + AllocationStrategy allocationStrategy; + + bool ownFirstSegment; + bool returnedFirstSegment; + + void* firstSegment; + + struct MoreSegments; + kj::Maybe> moreSegments; +}; + +class FlatMessageBuilder: public MessageBuilder { + // THIS IS NOT THE CLASS YOU'RE LOOKING FOR. + // + // If you want to write a message into already-existing scratch space, use `MallocMessageBuilder` + // and pass the scratch space to its constructor. It will then only fall back to malloc() if + // the scratch space is not large enough. + // + // Do NOT use this class unless you really know what you're doing. This class is problematic + // because it requires advance knowledge of the size of your message, which is usually impossible + // to determine without actually building the message. The class was created primarily to + // implement `copyToUnchecked()`, which itself exists only to support other internal parts of + // the Cap'n Proto implementation. + +public: + explicit FlatMessageBuilder(kj::ArrayPtr array); + KJ_DISALLOW_COPY(FlatMessageBuilder); + virtual ~FlatMessageBuilder() noexcept(false); + + void requireFilled(); + // Throws an exception if the flat array is not exactly full. + + virtual kj::ArrayPtr allocateSegment(uint minimumSize) override; + +private: + kj::ArrayPtr array; + bool allocated; +}; + +// ======================================================================================= +// implementation details + +inline const ReaderOptions& MessageReader::getOptions() { + return options; +} + +template +inline typename RootType::Reader MessageReader::getRoot() { + return getRootInternal().getAs(); +} + +template +inline typename RootType::Builder MessageBuilder::initRoot() { + return getRootInternal().initAs(); +} + +template +inline void MessageBuilder::setRoot(Reader&& value) { + getRootInternal().setAs>(value); +} + +template +inline typename RootType::Builder MessageBuilder::getRoot() { + return getRootInternal().getAs(); +} + +template +void MessageBuilder::adoptRoot(Orphan&& orphan) { + return getRootInternal().adopt(kj::mv(orphan)); +} + +template +typename RootType::Reader MessageReader::getRoot(SchemaType schema) { + return getRootInternal().getAs(schema); +} + +template +typename RootType::Builder MessageBuilder::getRoot(SchemaType schema) { + return getRootInternal().getAs(schema); +} + +template +typename RootType::Builder MessageBuilder::initRoot(SchemaType schema) { + return getRootInternal().initAs(schema); +} + +template +typename RootType::Reader readMessageUnchecked(const word* data) { + return AnyPointer::Reader(_::PointerReader::getRootUnchecked(data)).getAs(); +} + +template +void copyToUnchecked(Reader&& reader, kj::ArrayPtr uncheckedBuffer) { + FlatMessageBuilder builder(uncheckedBuffer); + builder.setRoot(kj::fwd(reader)); + builder.requireFilled(); +} + +template +typename RootType::Reader readDataStruct(kj::ArrayPtr data) { + return typename RootType::Reader(_::StructReader(data)); +} + +template +typename kj::ArrayPtr writeDataStruct(BuilderType builder) { + auto bytes = _::PointerHelpers>::getInternalBuilder(kj::mv(builder)) + .getDataSectionAsBlob(); + return kj::arrayPtr(reinterpret_cast(bytes.begin()), + reinterpret_cast(bytes.end())); +} + +template +static typename Type::Reader defaultValue() { + return typename Type::Reader(_::StructReader()); +} + +template +kj::Array canonicalize(T&& reader) { + return _::PointerHelpers>::getInternalReader(reader).canonicalize(); +} + +} // namespace capnp + +#endif // CAPNP_MESSAGE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/orphan-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/orphan-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1752 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "message.h" +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Orphans, Structs) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root.initStructField()); + EXPECT_TRUE(root.hasStructField()); + + Orphan orphan = root.disownStructField(); + EXPECT_FALSE(orphan == nullptr); + + checkTestMessage(orphan.getReader()); + checkTestMessage(orphan.get()); + EXPECT_FALSE(root.hasStructField()); + + root.adoptStructField(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasStructField()); + checkTestMessage(root.asReader().getStructField()); +} + +TEST(Orphans, EmptyStruct) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + auto anyPointer = root.getAnyPointerField(); + EXPECT_TRUE(anyPointer.isNull()); + auto orphan = builder.getOrphanage().newOrphan(); + anyPointer.adopt(kj::mv(orphan)); + EXPECT_EQ(0, anyPointer.targetSize().wordCount); + EXPECT_FALSE(anyPointer.isNull()); +} + +TEST(Orphans, EmptyStructOverwrite) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + auto anyPointer = root.getAnyPointerField(); + EXPECT_TRUE(anyPointer.isNull()); + anyPointer.initAs(); + auto orphan = builder.getOrphanage().newOrphan(); + anyPointer.adopt(kj::mv(orphan)); + EXPECT_EQ(0, anyPointer.targetSize().wordCount); + EXPECT_FALSE(anyPointer.isNull()); +} + +TEST(Orphans, AdoptNullStruct) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + auto anyPointer = root.getAnyPointerField(); + EXPECT_TRUE(anyPointer.isNull()); + anyPointer.initAs(); + anyPointer.adopt(Orphan()); + EXPECT_EQ(0, anyPointer.targetSize().wordCount); + EXPECT_TRUE(anyPointer.isNull()); +} + +TEST(Orphans, Lists) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.setUInt32List({12, 34, 56}); + EXPECT_TRUE(root.hasUInt32List()); + + Orphan> orphan = root.disownUInt32List(); + EXPECT_FALSE(orphan == nullptr); + + checkList(orphan.getReader(), {12u, 34u, 56u}); + checkList(orphan.get(), {12u, 34u, 56u}); + EXPECT_FALSE(root.hasUInt32List()); + + root.adoptUInt32List(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasUInt32List()); + checkList(root.asReader().getUInt32List(), {12u, 34u, 56u}); +} + +TEST(Orphans, StructLists) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto list = root.initStructList(2); + list[0].setTextField("foo"); + list[1].setTextField("bar"); + EXPECT_TRUE(root.hasStructList()); + + Orphan> orphan = root.disownStructList(); + EXPECT_FALSE(orphan == nullptr); + + ASSERT_EQ(2u, orphan.getReader().size()); + EXPECT_EQ("foo", orphan.getReader()[0].getTextField()); + EXPECT_EQ("bar", orphan.getReader()[1].getTextField()); + ASSERT_EQ(2u, orphan.get().size()); + EXPECT_EQ("foo", orphan.get()[0].getTextField()); + EXPECT_EQ("bar", orphan.get()[1].getTextField()); + EXPECT_FALSE(root.hasStructList()); + + root.adoptStructList(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasStructList()); + ASSERT_EQ(2u, root.asReader().getStructList().size()); + EXPECT_EQ("foo", root.asReader().getStructList()[0].getTextField()); + EXPECT_EQ("bar", root.asReader().getStructList()[1].getTextField()); +} + +TEST(Orphans, Text) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.setTextField("foo"); + EXPECT_TRUE(root.hasTextField()); + + Orphan orphan = root.disownTextField(); + EXPECT_FALSE(orphan == nullptr); + + EXPECT_EQ("foo", orphan.getReader()); + EXPECT_EQ("foo", orphan.get()); + EXPECT_FALSE(root.hasTextField()); + + root.adoptTextField(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasTextField()); + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, Data) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.setDataField(data("foo")); + EXPECT_TRUE(root.hasDataField()); + + Orphan orphan = root.disownDataField(); + EXPECT_FALSE(orphan == nullptr); + + EXPECT_EQ(data("foo"), orphan.getReader()); + EXPECT_EQ(data("foo"), orphan.get()); + EXPECT_FALSE(root.hasDataField()); + + root.adoptDataField(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasDataField()); + EXPECT_EQ(data("foo"), root.getDataField()); +} + +TEST(Orphans, NoCrossMessageTransfers) { + MallocMessageBuilder builder1; + MallocMessageBuilder builder2; + auto root1 = builder1.initRoot(); + auto root2 = builder2.initRoot(); + + initTestMessage(root1.initStructField()); + + EXPECT_ANY_THROW(root2.adoptStructField(root1.disownStructField())); +} + +TEST(Orphans, OrphanageStruct) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphan(); + initTestMessage(orphan.get()); + checkTestMessage(orphan.getReader()); + + auto root = builder.initRoot(); + root.adoptStructField(kj::mv(orphan)); +} + +TEST(Orphans, OrphanageList) { + MallocMessageBuilder builder; + + Orphan> orphan = builder.getOrphanage().newOrphan>(2); + orphan.get().set(0, 123); + orphan.get().set(1, 456); + + List::Reader reader = orphan.getReader(); + ASSERT_EQ(2u, reader.size()); + EXPECT_EQ(123u, reader[0]); + EXPECT_EQ(456u, reader[1]); + + auto root = builder.initRoot(); + root.adoptUInt32List(kj::mv(orphan)); +} + +TEST(Orphans, OrphanageText) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphan(8); + ASSERT_EQ(8u, orphan.get().size()); + memcpy(orphan.get().begin(), "12345678", 8); + + auto root = builder.initRoot(); + root.adoptTextField(kj::mv(orphan)); + EXPECT_EQ("12345678", root.getTextField()); +} + +TEST(Orphans, OrphanageData) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphan(2); + ASSERT_EQ(2u, orphan.get().size()); + orphan.get()[0] = 123; + orphan.get()[1] = 45; + + auto root = builder.initRoot(); + root.adoptDataField(kj::mv(orphan)); + ASSERT_EQ(2u, root.getDataField().size()); + EXPECT_EQ(123u, root.getDataField()[0]); + EXPECT_EQ(45u, root.getDataField()[1]); +} + +TEST(Orphans, OrphanageStructCopy) { + MallocMessageBuilder builder1; + MallocMessageBuilder builder2; + + auto root1 = builder1.initRoot(); + initTestMessage(root1); + + Orphan orphan = builder2.getOrphanage().newOrphanCopy(root1.asReader()); + checkTestMessage(orphan.getReader()); + + auto root2 = builder2.initRoot(); + root2.adoptStructField(kj::mv(orphan)); +} + +TEST(Orphans, OrphanageListCopy) { + MallocMessageBuilder builder1; + MallocMessageBuilder builder2; + + auto root1 = builder1.initRoot(); + root1.setUInt32List({12, 34, 56}); + + Orphan> orphan = builder2.getOrphanage().newOrphanCopy( + root1.asReader().getUInt32List()); + checkList(orphan.getReader(), {12u, 34u, 56u}); + + auto root2 = builder2.initRoot(); + root2.adoptUInt32List(kj::mv(orphan)); +} + +TEST(Orphans, OrphanageTextCopy) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphanCopy(Text::Reader("foobarba")); + EXPECT_EQ("foobarba", orphan.getReader()); + + auto root = builder.initRoot(); + root.adoptTextField(kj::mv(orphan)); +} + +TEST(Orphans, OrphanageDataCopy) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphanCopy(data("foo")); + EXPECT_EQ(data("foo"), orphan.getReader()); + + auto root = builder.initRoot(); + root.adoptDataField(kj::mv(orphan)); +} + +TEST(Orphans, ZeroOut) { + MallocMessageBuilder builder; + TestAllTypes::Reader orphanReader; + + { + Orphan orphan = builder.getOrphanage().newOrphan(); + orphanReader = orphan.getReader(); + initTestMessage(orphan.get()); + checkTestMessage(orphan.getReader()); + } + + // Once the Orphan destructor is called, the message should be zero'd out. + checkTestMessageAllZero(orphanReader); +} + +TEST(Orphans, StructAnyPointer) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = root.getAnyPointerField().disownAs(); + EXPECT_FALSE(orphan == nullptr); + + checkTestMessage(orphan.getReader()); + EXPECT_FALSE(root.hasAnyPointerField()); + + root.getAnyPointerField().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasAnyPointerField()); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); +} + +TEST(Orphans, ListAnyPointer) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({12, 34, 56}); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan> orphan = root.getAnyPointerField().disownAs>(); + EXPECT_FALSE(orphan == nullptr); + + checkList(orphan.getReader(), {12u, 34u, 56u}); + EXPECT_FALSE(root.hasAnyPointerField()); + + root.getAnyPointerField().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasAnyPointerField()); + checkList(root.asReader().getAnyPointerField().getAs>(), {12u, 34u, 56u}); +} + +#if !CAPNP_LITE +TEST(Orphans, DynamicStruct) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = + root.getAnyPointerField().disownAs(Schema::from()); + EXPECT_FALSE(orphan == nullptr); + + EXPECT_TRUE(orphan.get().getSchema() == Schema::from()); + checkDynamicTestMessage(orphan.getReader()); + EXPECT_FALSE(root.hasAnyPointerField()); + + root.getAnyPointerField().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasAnyPointerField()); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); + + Orphan orphan2 = root.getAnyPointerField().disownAs(); + EXPECT_FALSE(orphan2 == nullptr); + EXPECT_TRUE(orphan2.get().getSchema() == Schema::from()); + checkDynamicTestMessage(orphan2.getReader()); +} + +TEST(Orphans, DynamicList) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({12, 34, 56}); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = + root.getAnyPointerField().disownAs(Schema::from>()); + EXPECT_FALSE(orphan == nullptr); + + checkList(orphan.getReader(), {12, 34, 56}); + EXPECT_FALSE(root.hasAnyPointerField()); + + root.getAnyPointerField().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasAnyPointerField()); + checkList(root.asReader().getAnyPointerField().getAs>(), {12u, 34u, 56u}); + + Orphan orphan2 = root.getAnyPointerField().disownAs>(); + EXPECT_FALSE(orphan2 == nullptr); + checkList(orphan2.getReader(), {12, 34, 56}); +} + +TEST(Orphans, DynamicStructList) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto list = root.getAnyPointerField().initAs>(2); + list[0].setTextField("foo"); + list[1].setTextField("bar"); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = + root.getAnyPointerField().disownAs(Schema::from>()); + EXPECT_FALSE(orphan == nullptr); + + ASSERT_EQ(2u, orphan.get().size()); + EXPECT_EQ("foo", orphan.get()[0].as().getTextField()); + EXPECT_EQ("bar", orphan.get()[1].as().getTextField()); + EXPECT_FALSE(root.hasAnyPointerField()); + + root.getAnyPointerField().adopt(kj::mv(orphan)); + EXPECT_TRUE(orphan == nullptr); + EXPECT_TRUE(root.hasAnyPointerField()); + ASSERT_EQ(2u, root.asReader().getAnyPointerField().getAs>().size()); + EXPECT_EQ("foo", root.asReader().getAnyPointerField() + .getAs>()[0].getTextField()); + EXPECT_EQ("bar", root.asReader().getAnyPointerField() + .getAs>()[1].getTextField()); +} + +TEST(Orphans, OrphanageDynamicStruct) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphan(Schema::from()); + initDynamicTestMessage(orphan.get()); + checkDynamicTestMessage(orphan.getReader()); + + auto root = builder.initRoot(); + root.getAnyPointerField().adopt(kj::mv(orphan)); + checkTestMessage(root.asReader().getAnyPointerField().getAs()); +} + +TEST(Orphans, OrphanageDynamicList) { + MallocMessageBuilder builder; + + Orphan orphan = builder.getOrphanage().newOrphan(Schema::from>(), 2); + orphan.get().set(0, 123); + orphan.get().set(1, 456); + + checkList(orphan.getReader(), {123, 456}); + + auto root = builder.initRoot(); + root.getAnyPointerField().adopt(kj::mv(orphan)); + checkList(root.getAnyPointerField().getAs>(), {123u, 456u}); +} + +TEST(Orphans, OrphanageDynamicStructCopy) { + MallocMessageBuilder builder1; + MallocMessageBuilder builder2; + + auto root1 = builder1.initRoot(); + initTestMessage(root1.getAnyPointerField().initAs()); + + Orphan orphan = builder2.getOrphanage().newOrphanCopy( + root1.asReader().getAnyPointerField().getAs(Schema::from())); + checkDynamicTestMessage(orphan.getReader()); + + auto root2 = builder2.initRoot(); + root2.getAnyPointerField().adopt(kj::mv(orphan)); + checkTestMessage(root2.asReader().getAnyPointerField().getAs()); +} + +TEST(Orphans, OrphanageDynamicListCopy) { + MallocMessageBuilder builder1; + MallocMessageBuilder builder2; + + auto root1 = builder1.initRoot(); + root1.getAnyPointerField().setAs>({12, 34, 56}); + + Orphan orphan = builder2.getOrphanage().newOrphanCopy( + root1.asReader().getAnyPointerField().getAs(Schema::from>())); + checkList(orphan.getReader(), {12, 34, 56}); + + auto root2 = builder2.initRoot(); + root2.getAnyPointerField().adopt(kj::mv(orphan)); + checkList(root2.getAnyPointerField().getAs>(), {12u, 34u, 56u}); +} + +TEST(Orphans, DynamicStructAs) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = + root.getAnyPointerField().disownAs(Schema::from()); + EXPECT_EQ(DynamicValue::STRUCT, orphan.getType()); + + checkTestMessage(orphan.getReader().as()); + checkTestMessage(orphan.get().as()); + + { + Orphan structOrphan = orphan.releaseAs(); + EXPECT_EQ(DynamicValue::UNKNOWN, orphan.getType()); + EXPECT_FALSE(structOrphan == nullptr); + checkDynamicTestMessage(structOrphan.getReader()); + checkDynamicTestMessage(structOrphan.get()); + checkTestMessage(structOrphan.getReader().as()); + checkTestMessage(structOrphan.get().as()); + + { + Orphan typedOrphan = structOrphan.releaseAs(); + EXPECT_TRUE(structOrphan == nullptr); + EXPECT_FALSE(typedOrphan == nullptr); + checkTestMessage(typedOrphan.getReader()); + checkTestMessage(typedOrphan.get()); + orphan = kj::mv(typedOrphan); + EXPECT_EQ(DynamicValue::STRUCT, orphan.getType()); + EXPECT_TRUE(typedOrphan == nullptr); + } + } + + { + Orphan typedOrphan = orphan.releaseAs(); + checkTestMessage(typedOrphan.getReader()); + checkTestMessage(typedOrphan.get()); + } +} + +TEST(Orphans, DynamicListAs) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getAnyPointerField().setAs>({12, 34, 56}); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = + root.getAnyPointerField().disownAs(Schema::from>()); + EXPECT_EQ(DynamicValue::LIST, orphan.getType()); + + checkList(orphan.getReader().as>(), {12, 34, 56}); + checkList(orphan.get().as>(), {12, 34, 56}); + + { + Orphan listOrphan = orphan.releaseAs(); + EXPECT_EQ(DynamicValue::UNKNOWN, orphan.getType()); + EXPECT_FALSE(listOrphan == nullptr); + checkList(listOrphan.getReader(), {12, 34, 56}); + checkList(listOrphan.get(), {12, 34, 56}); + checkList(listOrphan.getReader().as>(), {12, 34, 56}); + checkList(listOrphan.get().as>(), {12, 34, 56}); + + { + Orphan> typedOrphan = listOrphan.releaseAs>(); + EXPECT_TRUE(listOrphan == nullptr); + EXPECT_FALSE(typedOrphan == nullptr); + checkList(typedOrphan.getReader(), {12, 34, 56}); + checkList(typedOrphan.get(), {12, 34, 56}); + orphan = kj::mv(typedOrphan); + EXPECT_EQ(DynamicValue::LIST, orphan.getType()); + EXPECT_TRUE(typedOrphan == nullptr); + } + } + + { + Orphan> typedOrphan = orphan.releaseAs>(); + checkList(typedOrphan.getReader(), {12, 34, 56}); + checkList(typedOrphan.get(), {12, 34, 56}); + } +} + +TEST(Orphans, DynamicAnyPointer) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + initTestMessage(root.getAnyPointerField().initAs()); + EXPECT_TRUE(root.hasAnyPointerField()); + + Orphan orphan = root.getAnyPointerField().disown(); + EXPECT_EQ(DynamicValue::ANY_POINTER, orphan.getType()); + + Orphan objectOrphan = orphan.releaseAs(); + checkTestMessage(objectOrphan.getAs()); + checkDynamicTestMessage(objectOrphan.getAs(Schema::from())); +} + +TEST(Orphans, DynamicDisown) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + initTestMessage(root); + + Orphan dstOrphan = + Orphanage::getForMessageContaining(root).newOrphan(); + auto dst = dstOrphan.get(); + + DynamicStruct::Builder dynamic = root; + DynamicStruct::Builder dynamicDst = dst; + + for (auto field: dynamic.getSchema().getFields()) { + dynamicDst.adopt(field, dynamic.disown(field)); + } + + checkTestMessageAllZero(root.asReader()); + checkTestMessage(dst.asReader()); + + for (auto field: dynamic.getSchema().getFields()) { + dynamicDst.adopt(field, dynamic.disown(field)); + } + + checkTestMessageAllZero(root.asReader()); + checkTestMessageAllZero(dst.asReader()); +} + +TEST(Orphans, DynamicDisownGroup) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto bar = root.initGroups().initBar(); + bar.setCorge(123); + bar.setGrault("foo"); + bar.setGarply(9876543210987ll); + + Orphan dstOrphan = + Orphanage::getForMessageContaining(root).newOrphan(); + auto dst = dstOrphan.get(); + + toDynamic(dst).adopt("groups", toDynamic(root).disown("groups")); + + EXPECT_EQ(test::TestGroups::Groups::FOO, root.getGroups().which()); + + EXPECT_EQ(test::TestGroups::Groups::BAR, dst.getGroups().which()); + auto newBar = dst.getGroups().getBar(); + EXPECT_EQ(123, newBar.getCorge()); + EXPECT_EQ("foo", newBar.getGrault()); + EXPECT_EQ(9876543210987ll, newBar.getGarply()); +} +#endif // !CAPNP_LITE + +TEST(Orphans, OrphanageFromBuilder) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + { + Orphanage orphanage = Orphanage::getForMessageContaining(root); + Orphan orphan = orphanage.newOrphan(); + initTestMessage(orphan.get()); + root.adoptStructField(kj::mv(orphan)); + checkTestMessage(root.asReader().getStructField()); + } + + { + Orphanage orphanage = Orphanage::getForMessageContaining(root.initBoolList(3)); + Orphan orphan = orphanage.newOrphan(); + initTestMessage(orphan.get()); + root.adoptStructField(kj::mv(orphan)); + checkTestMessage(root.asReader().getStructField()); + } + +#if !CAPNP_LITE + { + Orphanage orphanage = Orphanage::getForMessageContaining(toDynamic(root)); + Orphan orphan = orphanage.newOrphan(); + initTestMessage(orphan.get()); + root.adoptStructField(kj::mv(orphan)); + checkTestMessage(root.asReader().getStructField()); + } + + { + Orphanage orphanage = Orphanage::getForMessageContaining(toDynamic(root.initBoolList(3))); + Orphan orphan = orphanage.newOrphan(); + initTestMessage(orphan.get()); + root.adoptStructField(kj::mv(orphan)); + checkTestMessage(root.asReader().getStructField()); + } +#endif // !CAPNP_LITE +} + +static bool allZero(const word* begin, const word* end) { + for (const byte* pos = reinterpret_cast(begin); + pos < reinterpret_cast(end); ++pos) { + if (*pos != 0) return false; + } + return true; +} + +TEST(Orphans, StructsZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + initTestMessage(root.initStructField()); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownStructField(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, ListsZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + root.setUInt32List({12, 34, 56}); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownUInt32List(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, EmptyListsZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + root.initUInt32List(0); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownUInt32List(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, StructListsZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + { + auto list = root.initStructList(2); + initTestMessage(list[0]); + initTestMessage(list[1]); + } + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownStructList(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, EmptyStructListsZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + root.initStructList(0); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownStructList(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, TextZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + root.setTextField("abcd123"); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setDataField(data("foo")); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownTextField(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ(data("foo"), root.getDataField()); +} + +TEST(Orphans, DataZerodAfterUse) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + const word* zerosStart = builder.getSegmentsForOutput()[0].end(); + root.setDataField(data("abcd123")); + const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); + + root.setTextField("foo"); // guard against overruns + + EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid + + root.disownDataField(); + + EXPECT_TRUE(allZero(zerosStart, zerosEnd)); + + EXPECT_EQ("foo", root.getTextField()); +} + +TEST(Orphans, FarPointer) { + MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE); + auto root = builder.initRoot(); + auto child = root.initStructField(); + initTestMessage(child); + + auto orphan = root.disownStructField(); + EXPECT_FALSE(root.hasStructField()); + EXPECT_TRUE(orphan != nullptr); + EXPECT_FALSE(orphan == nullptr); + + checkTestMessage(orphan.getReader()); + checkTestMessage(orphan.get()); +} + +TEST(Orphans, UpgradeStruct) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto old = root.getAnyPointerField().initAs(); + old.setOld1(1234); + old.setOld2("foo"); + + auto orphan = root.getAnyPointerField().disownAs(); + + // Relocation has not occurred yet. + old.setOld1(12345); + EXPECT_EQ(12345, orphan.getReader().getOld1()); + EXPECT_EQ("foo", old.getOld2()); + + // This will relocate the struct. + auto newVersion = orphan.get(); + + EXPECT_EQ(0, old.getOld1()); + EXPECT_EQ("", old.getOld2()); + + EXPECT_EQ(12345, newVersion.getOld1()); + EXPECT_EQ("foo", newVersion.getOld2()); +} + +TEST(Orphans, UpgradeStructList) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto old = root.getAnyPointerField().initAs>(2); + old[0].setOld1(1234); + old[0].setOld2("foo"); + old[1].setOld1(4321); + old[1].setOld2("bar"); + + auto orphan = root.getAnyPointerField().disownAs>(); + + // Relocation has not occurred yet. + old[0].setOld1(12345); + EXPECT_EQ(12345, orphan.getReader()[0].getOld1()); + EXPECT_EQ("foo", old[0].getOld2()); + + // This will relocate the struct. + auto newVersion = orphan.get(); + + EXPECT_EQ(0, old[0].getOld1()); + EXPECT_EQ("", old[0].getOld2()); + + EXPECT_EQ(12345, newVersion[0].getOld1()); + EXPECT_EQ("foo", newVersion[0].getOld2()); + EXPECT_EQ(4321, newVersion[1].getOld1()); + EXPECT_EQ("bar", newVersion[1].getOld2()); +} + +TEST(Orphans, DisownNull) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + { + Orphan orphan = root.disownStructField(); + EXPECT_TRUE(orphan == nullptr); + + checkTestMessageAllZero(orphan.getReader()); + EXPECT_TRUE(orphan == nullptr); + + // get()ing the orphan allocates an object, for security reasons. + checkTestMessageAllZero(orphan.get()); + EXPECT_FALSE(orphan == nullptr); + } + + { + Orphan> orphan = root.disownInt32List(); + EXPECT_TRUE(orphan == nullptr); + + EXPECT_EQ(0, orphan.getReader().size()); + EXPECT_TRUE(orphan == nullptr); + + EXPECT_EQ(0, orphan.get().size()); + EXPECT_TRUE(orphan == nullptr); + } + + { + Orphan> orphan = root.disownStructList(); + EXPECT_TRUE(orphan == nullptr); + + EXPECT_EQ(0, orphan.getReader().size()); + EXPECT_TRUE(orphan == nullptr); + + EXPECT_EQ(0, orphan.get().size()); + EXPECT_TRUE(orphan == nullptr); + } +} + +TEST(Orphans, ReferenceExternalData) { + MallocMessageBuilder builder; + + union { + word align; + byte data[50]; + }; + + memset(data, 0x55, sizeof(data)); + + auto orphan = builder.getOrphanage().referenceExternalData(Data::Builder(data, sizeof(data))); + + // Data was added as a new segment. + { + auto segments = builder.getSegmentsForOutput(); + ASSERT_EQ(2, segments.size()); + EXPECT_EQ(data, segments[1].asBytes().begin()); + EXPECT_EQ((sizeof(data) + 7) / 8, segments[1].size()); + } + + // Can't get builder because it's read-only. + EXPECT_ANY_THROW(orphan.get()); + + // Can get reader. + { + auto reader = orphan.getReader(); + EXPECT_EQ(data, reader.begin()); + EXPECT_EQ(sizeof(data), reader.size()); + } + + // Adopt into message tree. + auto root = builder.getRoot(); + root.adoptDataField(kj::mv(orphan)); + + // Can't get child builder. + EXPECT_ANY_THROW(root.getDataField()); + + // Can get child reader. + { + auto reader = root.asReader().getDataField(); + EXPECT_EQ(data, reader.begin()); + EXPECT_EQ(sizeof(data), reader.size()); + } + + // Back to orphan. + orphan = root.disownDataField(); + + // Now the orphan may be pointing to a far pointer landing pad, so check that it still does the + // right things. + + // Can't get builder because it's read-only. + EXPECT_ANY_THROW(orphan.get()); + + // Can get reader. + { + auto reader = orphan.getReader(); + EXPECT_EQ(data, reader.begin()); + EXPECT_EQ(sizeof(data), reader.size()); + } + + // Finally, let's abandon the orphan and check that this doesn't zero out the data. + orphan = Orphan(); + + for (byte b: data) { + EXPECT_EQ(0x55, b); + } +} + +TEST(Orphans, ReferenceExternalData_NoZeroOnSet) { + // Verify that an external blob is not zeroed by setFoo(). + + union { + word align; + byte data[50]; + }; + + memset(data, 0x55, sizeof(data)); + + MallocMessageBuilder builder; + auto root = builder.getRoot(); + root.adoptDataField(builder.getOrphanage().referenceExternalData( + Data::Builder(data, sizeof(data)))); + + root.setDataField(Data::Builder()); + + for (byte b: data) { + EXPECT_EQ(0x55, b); + } +} + +TEST(Orphans, ReferenceExternalData_NoZeroImmediateAbandon) { + // Verify that an external blob is not zeroed when abandoned immediately, without ever being + // adopted. + + union { + word align; + byte data[50]; + }; + + memset(data, 0x55, sizeof(data)); + + MallocMessageBuilder builder; + builder.getOrphanage().referenceExternalData(Data::Builder(data, sizeof(data))); + + for (byte b: data) { + EXPECT_EQ(0x55, b); + } +} + +TEST(Orphans, TruncateData) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 123, builder.size()); + + EXPECT_EQ(4, message.getSegmentsForOutput()[0].size()); + orphan.truncate(2); + EXPECT_EQ(2, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(2, reader.size()); + EXPECT_EQ(builder.begin(), reader.begin()); + + EXPECT_EQ(123, builder[0]); + EXPECT_EQ(123, builder[1]); + EXPECT_EQ(0, builder[2]); + EXPECT_EQ(0, builder[3]); + EXPECT_EQ(0, builder[16]); +} + +TEST(Orphans, ExtendData) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 123, builder.size()); + + EXPECT_EQ(4, message.getSegmentsForOutput()[0].size()); + orphan.truncate(27); + EXPECT_EQ(5, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(27, reader.size()); + EXPECT_EQ(builder.begin(), reader.begin()); + + for (uint i = 0; i < 17; i++) { + EXPECT_EQ(123, reader[i]); + } + for (uint i = 17; i < 27; i++) { + EXPECT_EQ(0, reader[i]); + } +} + +TEST(Orphans, ExtendDataCopy) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 123, builder.size()); + + auto orphan2 = message.getOrphanage().newOrphan(1); + orphan2.get()[0] = 32; + + orphan.truncate(27); + + auto reader = orphan.getReader(); + EXPECT_EQ(27, reader.size()); + EXPECT_NE(builder.begin(), reader.begin()); + + for (uint i = 0; i < 17; i++) { + EXPECT_EQ(123, reader[i]); + EXPECT_EQ(0, builder[i]); + } + for (uint i = 17; i < 27; i++) { + EXPECT_EQ(0, reader[i]); + } + + EXPECT_EQ(32, orphan2.getReader()[0]); +} + +TEST(Orphans, ExtendDataFromEmpty) { + MallocMessageBuilder message; + + auto orphan = message.initRoot().disownDataField(); + orphan.truncate(3); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ(0, reader[i]); + } +} + +TEST(Orphans, TruncateText) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 'a', builder.size()); + + EXPECT_EQ(4, message.getSegmentsForOutput()[0].size()); + orphan.truncate(2); + EXPECT_EQ(2, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(2, reader.size()); + EXPECT_EQ(builder.begin(), reader.begin()); + + EXPECT_EQ('a', builder[0]); + EXPECT_EQ('a', builder[1]); + EXPECT_EQ('\0', builder[2]); + EXPECT_EQ('\0', builder[3]); + EXPECT_EQ('\0', builder[16]); +} + +TEST(Orphans, ExtendText) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 'a', builder.size()); + + EXPECT_EQ(4, message.getSegmentsForOutput()[0].size()); + orphan.truncate(27); + EXPECT_EQ(5, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(27, reader.size()); + EXPECT_EQ(builder.begin(), reader.begin()); + + for (uint i = 0; i < 17; i++) { + EXPECT_EQ('a', reader[i]); + } + for (uint i = 17; i < 27; i++) { + EXPECT_EQ('\0', reader[i]); + } +} + +TEST(Orphans, ExtendTextCopy) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan(17); + auto builder = orphan.get(); + memset(builder.begin(), 'a', builder.size()); + + auto orphan2 = message.getOrphanage().newOrphan(1); + orphan2.get()[0] = 32; + + orphan.truncate(27); + + auto reader = orphan.getReader(); + EXPECT_EQ(27, reader.size()); + EXPECT_NE(builder.begin(), reader.begin()); + + for (uint i = 0; i < 17; i++) { + EXPECT_EQ('a', reader[i]); + EXPECT_EQ('\0', builder[i]); + } + for (uint i = 17; i < 27; i++) { + EXPECT_EQ('\0', reader[i]); + } + + EXPECT_EQ(32, orphan2.getReader()[0]); +} + +TEST(Orphans, ExtendTextFromEmpty) { + MallocMessageBuilder message; + + auto orphan = message.initRoot().disownTextField(); + orphan.truncate(3); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ('\0', reader[i]); + } +} + +TEST(Orphans, TruncatePrimitiveList) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.set(i, 123456789 + i); + } + + EXPECT_EQ(5, message.getSegmentsForOutput()[0].size()); + orphan.truncate(3); + EXPECT_EQ(3, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ(123456789 + i, builder[i]); + EXPECT_EQ(123456789 + i, reader[i]); + } + for (uint i = 3; i < 7; i++) { + EXPECT_EQ(0, builder[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, 321); + EXPECT_EQ(321, reader[0]); +} + +TEST(Orphans, ExtendPrimitiveList) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.set(i, 123456789 + i); + } + + EXPECT_EQ(5, message.getSegmentsForOutput()[0].size()); + orphan.truncate(11); + EXPECT_EQ(7, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(123456789 + i, reader[i]); + EXPECT_EQ(123456789 + i, builder[i]); + } + for (uint i = 7; i < 11; i++) { + EXPECT_EQ(0, reader[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, 321); + EXPECT_EQ(321, reader[0]); +} + +TEST(Orphans, ExtendPrimitiveListCopy) { + MallocMessageBuilder message; + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.set(i, 123456789 + i); + } + + auto orphan2 = message.getOrphanage().newOrphan(1); + orphan2.get()[0] = 32; + + orphan.truncate(11); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(123456789 + i, reader[i]); + EXPECT_EQ(0, builder[i]); + } + for (uint i = 7; i < 11; i++) { + EXPECT_EQ(0, reader[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, 321); + EXPECT_EQ(123456789, reader[0]); + + EXPECT_EQ(32, orphan2.getReader()[0]); +} + +TEST(Orphans, ExtendPointerListFromEmpty) { + MallocMessageBuilder message; + + auto orphan = message.initRoot().disownUInt32List(); + orphan.truncate(3); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ(0, reader[i]); + } +} + +TEST(Orphans, TruncatePointerList) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + pointers.add(message.getOrphanage().newOrphanCopy(Text::Reader(kj::str("foo", i)))); + } + size_t sizeBeforeList = message.getSegmentsForOutput()[0].size(); + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adopt(i, kj::mv(pointers[i])); + } + + EXPECT_EQ(sizeBeforeList + 7, message.getSegmentsForOutput()[0].size()); + orphan.truncate(3); + EXPECT_EQ(sizeBeforeList + 3, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ(kj::str("foo", i), builder[i]); + EXPECT_EQ(kj::str("foo", i), reader[i]); + } + for (uint i = 3; i < 7; i++) { + EXPECT_TRUE(builder[i] == nullptr); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, "bar"); + EXPECT_EQ("bar", reader[0]); +} + +TEST(Orphans, ExtendPointerList) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + pointers.add(message.getOrphanage().newOrphanCopy(Text::Reader(kj::str("foo", i)))); + } + size_t sizeBeforeList = message.getSegmentsForOutput()[0].size(); + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adopt(i, kj::mv(pointers[i])); + } + + EXPECT_EQ(sizeBeforeList + 7, message.getSegmentsForOutput()[0].size()); + orphan.truncate(11); + EXPECT_EQ(sizeBeforeList + 11, message.getSegmentsForOutput()[0].size()); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(kj::str("foo", i), reader[i]); + EXPECT_EQ(kj::str("foo", i), builder[i]); + } + for (uint i = 7; i < 11; i++) { + EXPECT_TRUE(reader[i] == nullptr); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, "bar"); + EXPECT_EQ("bar", reader[0]); +} + +TEST(Orphans, ExtendPointerListCopy) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + pointers.add(message.getOrphanage().newOrphanCopy(Text::Reader(kj::str("foo", i)))); + } + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adopt(i, kj::mv(pointers[i])); + } + + auto orphan2 = message.getOrphanage().newOrphan(1); + orphan2.get()[0] = 32; + + orphan.truncate(11); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(kj::str("foo", i), reader[i]); + EXPECT_TRUE(builder[i] == nullptr); + } + for (uint i = 7; i < 11; i++) { + EXPECT_TRUE(reader[i] == nullptr); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder.set(0, "bar"); + EXPECT_EQ("foo0", reader[0]); + + EXPECT_EQ(32, orphan2.getReader()[0]); +} + +TEST(Orphans, ExtendPointerListFromEmpty) { + MallocMessageBuilder message; + + auto orphan = message.initRoot().disownTextList(); + orphan.truncate(3); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ("", reader[i]); + } +} + +TEST(Orphans, TruncateStructList) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + auto o = message.getOrphanage().newOrphan(); + auto b = o.get(); + b.setUInt32Field(123456789 + i); + b.setTextField(kj::str("foo", i)); + b.setUInt8List({123, 45}); + pointers.add(kj::mv(o)); + } + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adoptWithCaveats(i, kj::mv(pointers[i])); + } + + size_t sizeBeforeTruncate = message.getSegmentsForOutput()[0].size(); + orphan.truncate(3); + EXPECT_LT(message.getSegmentsForOutput()[0].size(), sizeBeforeTruncate); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + EXPECT_EQ(123456789 + i, reader[i].getUInt32Field()); + EXPECT_EQ(kj::str("foo", i), reader[i].getTextField()); + checkList(reader[i].getUInt8List(), {123, 45}); + + EXPECT_EQ(123456789 + i, builder[i].getUInt32Field()); + EXPECT_EQ(kj::str("foo", i), builder[i].getTextField()); + checkList(builder[i].getUInt8List(), {123, 45}); + } + for (uint i = 3; i < 7; i++) { + checkTestMessageAllZero(builder[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder[0].setUInt32Field(321); + EXPECT_EQ(321, reader[0].getUInt32Field()); +} + +TEST(Orphans, ExtendStructList) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + auto o = message.getOrphanage().newOrphan(); + auto b = o.get(); + b.setUInt32Field(123456789 + i); + b.setTextField(kj::str("foo", i)); + b.setUInt8List({123, 45}); + pointers.add(kj::mv(o)); + } + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adoptWithCaveats(i, kj::mv(pointers[i])); + } + + orphan.truncate(11); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(123456789 + i, reader[i].getUInt32Field()); + EXPECT_EQ(kj::str("foo", i), reader[i].getTextField()); + checkList(reader[i].getUInt8List(), {123, 45}); + + EXPECT_EQ(123456789 + i, builder[i].getUInt32Field()); + EXPECT_EQ(kj::str("foo", i), builder[i].getTextField()); + checkList(builder[i].getUInt8List(), {123, 45}); + } + for (uint i = 7; i < 11; i++) { + checkTestMessageAllZero(reader[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder[0].setUInt32Field(321); + EXPECT_EQ(321, reader[0].getUInt32Field()); +} + +TEST(Orphans, ExtendStructListCopy) { + MallocMessageBuilder message; + + // Allocate data in advance so that the list itself is at the end of the segment. + kj::Vector> pointers(7); + for (uint i = 0; i < 7; i++) { + auto o = message.getOrphanage().newOrphan(); + auto b = o.get(); + b.setUInt32Field(123456789 + i); + b.setTextField(kj::str("foo", i)); + b.setUInt8List({123, 45}); + pointers.add(kj::mv(o)); + } + + auto orphan = message.getOrphanage().newOrphan>(7); + auto builder = orphan.get(); + for (uint i = 0; i < 7; i++) { + builder.adoptWithCaveats(i, kj::mv(pointers[i])); + } + + auto orphan2 = message.getOrphanage().newOrphan(1); + orphan2.get()[0] = 32; + + orphan.truncate(11); + + auto reader = orphan.getReader(); + EXPECT_EQ(11, reader.size()); + + for (uint i = 0; i < 7; i++) { + EXPECT_EQ(123456789 + i, reader[i].getUInt32Field()); + EXPECT_EQ(kj::str("foo", i), reader[i].getTextField()); + checkList(reader[i].getUInt8List(), {123, 45}); + + checkTestMessageAllZero(builder[i]); + } + for (uint i = 7; i < 11; i++) { + checkTestMessageAllZero(reader[i]); + } + + // Can't compare pointers directly, but we can check if builder modifications are visible using + // the reader. + builder[0].setUInt32Field(321); + EXPECT_EQ(123456789, reader[0].getUInt32Field()); + + EXPECT_EQ(32, orphan2.getReader()[0]); +} + +TEST(Orphans, ExtendStructListFromEmpty) { + MallocMessageBuilder message; + + auto orphan = message.initRoot().disownStructList(); + orphan.truncate(3); + + auto reader = orphan.getReader(); + EXPECT_EQ(3, reader.size()); + + for (uint i = 0; i < 3; i++) { + checkTestMessageAllZero(reader[i]); + } +} + +template +void initList(ListBuilder builder, + std::initializer_list>>> values) { + KJ_ASSERT(builder.size() == values.size()); + size_t i = 0; + for (auto& value: values) { + builder.set(i++, value); + } +} + +TEST(Orphans, ConcatenatePrimitiveLists) { + MallocMessageBuilder message; + auto orphanage = message.getOrphanage(); + + auto list1 = orphanage.newOrphan>(3); + initList(list1.get(), {12, 34, 56}); + + auto list2 = orphanage.newOrphan>(2); + initList(list2.get(), {78, 90}); + + auto list3 = orphanage.newOrphan>(4); + initList(list3.get(), {23, 45, 67, 89}); + + List::Reader lists[] = { list1.getReader(), list2.getReader(), list3.getReader() }; + kj::ArrayPtr::Reader> array = lists; + + auto cat = message.getOrphanage().newOrphanConcat(array); + + checkList(cat.getReader(), {12, 34, 56, 78, 90, 23, 45, 67, 89}); +} + +TEST(Orphans, ConcatenateBitLists) { + MallocMessageBuilder message; + auto orphanage = message.getOrphanage(); + + auto list1 = orphanage.newOrphan>(3); + initList(list1.get(), {true, true, false}); + + auto list2 = orphanage.newOrphan>(2); + initList(list2.get(), {false, true}); + + auto list3 = orphanage.newOrphan>(4); + initList(list3.get(), {false, false, true, false}); + + List::Reader lists[] = { list1.getReader(), list2.getReader(), list3.getReader() }; + kj::ArrayPtr::Reader> array = lists; + + auto cat = message.getOrphanage().newOrphanConcat(array); + + checkList(cat.getReader(), {true, true, false, false, true, false, false, true, false}); +} + +TEST(Orphans, ConcatenatePointerLists) { + MallocMessageBuilder message; + auto orphanage = message.getOrphanage(); + + auto list1 = orphanage.newOrphan>(3); + initList(list1.get(), {"foo", "bar", "baz"}); + + auto list2 = orphanage.newOrphan>(2); + initList(list2.get(), {"qux", "corge"}); + + auto list3 = orphanage.newOrphan>(4); + initList(list3.get(), {"grault", "garply", "waldo", "fred"}); + + List::Reader lists[] = { list1.getReader(), list2.getReader(), list3.getReader() }; + kj::ArrayPtr::Reader> array = lists; + + auto cat = message.getOrphanage().newOrphanConcat(array); + + checkList(cat.getReader(), { + "foo", "bar", "baz", "qux", "corge", "grault", "garply", "waldo", "fred"}); +} + +TEST(Orphans, ConcatenateStructLists) { + // In this test, we not only concatenate two struct lists, but we concatenate in a list that + // contains a newer-than-expected version of the struct with extra fields, in order to verify + // that the new fields aren't lost. + + MallocMessageBuilder message; + auto orphanage = message.getOrphanage(); + + auto orphan1 = orphanage.newOrphan>(2); + auto list1 = orphan1.get(); + list1[0].setOld1(12); + list1[0].setOld2("foo"); + list1[1].setOld1(34); + list1[1].setOld2("bar"); + + auto orphan2 = orphanage.newOrphan(); + auto list2 = orphan2.get().getAnyPointerField().initAs>(2); + list2[0].setOld1(56); + list2[0].setOld2("baz"); + list2[0].setNew1(123); + list2[0].setNew2("corge"); + list2[1].setOld1(78); + list2[1].setOld2("qux"); + list2[1].setNew1(456); + list2[1].setNew2("grault"); + + List::Reader lists[] = { + orphan1.getReader(), + orphan2.getReader().getAnyPointerField().getAs>() + }; + kj::ArrayPtr::Reader> array = lists; + + auto orphan3 = orphanage.newOrphan(); + orphan3.get().getAnyPointerField().adopt(message.getOrphanage().newOrphanConcat(array)); + + auto cat = orphan3.getReader().getAnyPointerField().getAs>(); + ASSERT_EQ(4, cat.size()); + + EXPECT_EQ(12, cat[0].getOld1()); + EXPECT_EQ("foo", cat[0].getOld2()); + EXPECT_EQ(987, cat[0].getNew1()); + EXPECT_FALSE(cat[0].hasNew2()); + + EXPECT_EQ(34, cat[1].getOld1()); + EXPECT_EQ("bar", cat[1].getOld2()); + EXPECT_EQ(987, cat[1].getNew1()); + EXPECT_FALSE(cat[1].hasNew2()); + + EXPECT_EQ(56, cat[2].getOld1()); + EXPECT_EQ("baz", cat[2].getOld2()); + EXPECT_EQ(123, cat[2].getNew1()); + EXPECT_EQ("corge", cat[2].getNew2()); + + EXPECT_EQ(78, cat[3].getOld1()); + EXPECT_EQ("qux", cat[3].getOld2()); + EXPECT_EQ(456, cat[3].getNew1()); + EXPECT_EQ("grault", cat[3].getNew2()); +} + +TEST(Orphans, ConcatenateStructListsUpgradeFromPrimitive) { + // Like above, but we're "upgrading" a primitive list to a struct list. + + MallocMessageBuilder message; + auto orphanage = message.getOrphanage(); + + auto orphan1 = orphanage.newOrphan>(2); + auto list1 = orphan1.get(); + list1[0].setOld1(12); + list1[0].setOld2("foo"); + list1[1].setOld1(34); + list1[1].setOld2("bar"); + + auto orphan2 = orphanage.newOrphan(); + auto list2 = orphan2.get().getAnyPointerField().initAs>(2); + initList(list2, {12345, 67890}); + + List::Reader lists[] = { + orphan1.getReader(), + orphan2.getReader().getAnyPointerField().getAs>() + }; + kj::ArrayPtr::Reader> array = lists; + + auto orphan3 = message.getOrphanage().newOrphanConcat(array); + auto cat = orphan3.getReader(); + ASSERT_EQ(4, cat.size()); + + EXPECT_EQ(12, cat[0].getOld1()); + EXPECT_EQ("foo", cat[0].getOld2()); + + EXPECT_EQ(34, cat[1].getOld1()); + EXPECT_EQ("bar", cat[1].getOld2()); + + EXPECT_EQ(12345, cat[2].getOld1()); + EXPECT_FALSE(cat[2].hasOld2()); + + EXPECT_EQ(67890, cat[3].getOld1()); + EXPECT_FALSE(cat[3].hasOld2()); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/orphan.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/orphan.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,440 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ORPHAN_H_ +#define CAPNP_ORPHAN_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" + +namespace capnp { + +class StructSchema; +class ListSchema; +struct DynamicStruct; +struct DynamicList; +namespace _ { struct OrphanageInternal; } + +template +class Orphan { + // Represents an object which is allocated within some message builder but has no pointers + // pointing at it. An Orphan can later be "adopted" by some other object as one of that object's + // fields, without having to copy the orphan. For a field `foo` of pointer type, the generated + // code will define builder methods `void adoptFoo(Orphan)` and `Orphan disownFoo()`. + // Orphans can also be created independently of any parent using an Orphanage. + // + // `Orphan` can be moved but not copied, like `Own`, so that it is impossible for one + // orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its + // contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space + // in a message arena). + +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {} + + inline BuilderFor get(); + // Get the underlying builder. If the orphan is null, this will allocate and return a default + // object rather than crash. This is done for security -- otherwise, you might enable a DoS + // attack any time you disown a field and fail to check if it is null. In the case of structs, + // this means that the orphan is no longer null after get() returns. In the case of lists, + // no actual object is allocated since a simple empty ListBuilder can be returned. + + inline ReaderFor getReader() const; + + inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } + + inline void truncate(uint size); + // Resize an object (which must be a list or a blob) to the given size. + // + // If the new size is less than the original, the remaining elements will be discarded. The + // list is never moved in this case. If the list happens to be located at the end of its segment + // (which is always true if the list was the last thing allocated), the removed memory will be + // reclaimed (reducing the messag size), otherwise it is simply zeroed. The reclaiming behavior + // is particularly useful for allocating buffer space when you aren't sure how much space you + // actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and + // then truncate it back to the amount of space actually used. + // + // If the new size is greater than the original, the list is extended with default values. If + // the list is the last object in its segment *and* there is enough space left in the segment to + // extend it to cover the new values, then the list is extended in-place. Otherwise, it must be + // moved to a new location, leaving a zero'd hole in the previous space that won't be filled. + // This copy is shallow; sub-objects will simply be reparented, not copied. + // + // Any existing readers or builders pointing at the object are invalidated by this call (even if + // it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer. + +private: + _::OrphanBuilder builder; + + template + friend struct _::PointerHelpers; + template + friend struct List; + template + friend class Orphan; + friend class Orphanage; + friend class MessageBuilder; +}; + +class Orphanage: private kj::DisallowConstCopy { + // Use to directly allocate Orphan objects, without having a parent object allocate and then + // disown the object. + +public: + inline Orphanage(): arena(nullptr) {} + + template + static Orphanage getForMessageContaining(BuilderType builder); + // Construct an Orphanage that allocates within the message containing the given Builder. This + // allows the constructed Orphans to be adopted by objects within said message. + // + // This constructor takes the builder rather than having the builder have a getOrphanage() method + // because this is an advanced feature and we don't want to pollute the builder APIs with it. + // + // Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its + // `getOrphanage()` method. + + template + Orphan newOrphan() const; + // Allocate a new orphaned struct. + + template + Orphan newOrphan(uint size) const; + // Allocate a new orphaned list or blob. + + Orphan newOrphan(StructSchema schema) const; + // Dynamically create an orphan struct with the given schema. You must + // #include to use this. + + Orphan newOrphan(ListSchema schema, uint size) const; + // Dynamically create an orphan list with the given schema. You must #include + // to use this. + + template + Orphan> newOrphanCopy(Reader copyFrom) const; + // Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the + // given object. + + template + Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; + template + Orphan>>> newOrphanConcat(kj::ArrayPtr lists) const; + // Given an array of List readers, copy and concatenate the lists, creating a new Orphan. + // + // Note that compared to allocating the list yourself and using `setWithCaveats()` to set each + // item, this method avoids the "caveats": the new list will be allocated with the element size + // being the maximum of that from all the input lists. This is particularly important when + // concatenating struct lists: if the lists were created using a newer version of the protocol + // in which some new fields had been added to the struct, using `setWithCaveats()` would + // truncate off those new fields. + + Orphan referenceExternalData(Data::Reader data) const; + // Creates an Orphan that points at an existing region of memory (e.g. from another message) + // without copying it. There are some SEVERE restrictions on how this can be used: + // - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is + // abandoned). + // - Because the data is const, you will not be allowed to obtain a `Data::Builder` + // for this blob. Any call which would return such a builder will throw an exception. You + // can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once + // the orphan is adopted). It is your responsibility to make sure your code can deal with + // these problems when using this optimization; if you can't, allocate a copy instead. + // - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on + // the CPU). Any pointer returned by malloc() as well as any data blob obtained from another + // Cap'n Proto message satisfies this. + // - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte + // boundary will be visible in the raw message when it is written out. Thus, there must be no + // secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe + // as these bytes should be zero (unless the sender had the same problem). + // + // The array will actually become one of the message's segments. The data can thus be adopted + // into the message tree without copying it. This is particularly useful when referencing very + // large blobs, such as whole mmap'd files. + +private: + _::BuilderArena* arena; + _::CapTableBuilder* capTable; + + inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable) + : arena(arena), capTable(capTable) {} + + template + struct GetInnerBuilder; + template + struct GetInnerReader; + template + struct NewOrphanListImpl; + + friend class MessageBuilder; + friend struct _::OrphanageInternal; +}; + +// ======================================================================================= +// Inline implementation details. + +namespace _ { // private + +template +struct OrphanGetImpl; + +template +struct OrphanGetImpl { + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::elementSizeForType()); + } +}; + +template +struct OrphanGetImpl { + static inline typename T::Builder apply(_::OrphanBuilder& builder) { + return typename T::Builder(builder.asStruct(_::structSize())); + } + static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) { + return typename T::Reader(builder.asStructReader(_::structSize())); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, _::structSize()); + } +}; + +#if !CAPNP_LITE +template +struct OrphanGetImpl { + static inline typename T::Client apply(_::OrphanBuilder& builder) { + return typename T::Client(builder.asCapability()); + } + static inline typename T::Client applyReader(const _::OrphanBuilder& builder) { + return typename T::Client(builder.asCapability()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; +#endif // !CAPNP_LITE + +template +struct OrphanGetImpl, Kind::LIST> { + static inline typename List::Builder apply(_::OrphanBuilder& builder) { + return typename List::Builder(builder.asList(_::ElementSizeForType::value)); + } + static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { + return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template +struct OrphanGetImpl, Kind::LIST> { + static inline typename List::Builder apply(_::OrphanBuilder& builder) { + return typename List::Builder(builder.asStructList(_::structSize())); + } + static inline typename List::Reader applyReader(const _::OrphanBuilder& builder) { + return typename List::Reader(builder.asListReader(_::ElementSizeForType::value)); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template <> +struct OrphanGetImpl { + static inline Text::Builder apply(_::OrphanBuilder& builder) { + return Text::Builder(builder.asText()); + } + static inline Text::Reader applyReader(const _::OrphanBuilder& builder) { + return Text::Reader(builder.asTextReader()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +template <> +struct OrphanGetImpl { + static inline Data::Builder apply(_::OrphanBuilder& builder) { + return Data::Builder(builder.asData()); + } + static inline Data::Reader applyReader(const _::OrphanBuilder& builder) { + return Data::Reader(builder.asDataReader()); + } + static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { + builder.truncate(size, ElementSize::POINTER); + } +}; + +struct OrphanageInternal { + static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; } + static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; } +}; + +} // namespace _ (private) + +template +inline BuilderFor Orphan::get() { + return _::OrphanGetImpl::apply(builder); +} + +template +inline ReaderFor Orphan::getReader() const { + return _::OrphanGetImpl::applyReader(builder); +} + +template +inline void Orphan::truncate(uint size) { + _::OrphanGetImpl>::truncateListOf(builder, bounded(size) * ELEMENTS); +} + +template <> +inline void Orphan::truncate(uint size) { + builder.truncateText(bounded(size) * ELEMENTS); +} + +template <> +inline void Orphan::truncate(uint size) { + builder.truncate(bounded(size) * ELEMENTS, ElementSize::BYTE); +} + +template +struct Orphanage::GetInnerBuilder { + static inline _::StructBuilder apply(typename T::Builder& t) { + return t._builder; + } +}; + +template +struct Orphanage::GetInnerBuilder { + static inline _::ListBuilder apply(typename T::Builder& t) { + return t.builder; + } +}; + +template +Orphanage Orphanage::getForMessageContaining(BuilderType builder) { + auto inner = GetInnerBuilder>::apply(builder); + return Orphanage(inner.getArena(), inner.getCapTable()); +} + +template +Orphan Orphanage::newOrphan() const { + return Orphan(_::OrphanBuilder::initStruct(arena, capTable, _::structSize())); +} + +template +struct Orphanage::NewOrphanListImpl> { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initList( + arena, capTable, bounded(size) * ELEMENTS, _::ElementSizeForType::value); + } +}; + +template +struct Orphanage::NewOrphanListImpl> { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initStructList( + arena, capTable, bounded(size) * ELEMENTS, _::structSize()); + } +}; + +template <> +struct Orphanage::NewOrphanListImpl { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initText(arena, capTable, bounded(size) * BYTES); + } +}; + +template <> +struct Orphanage::NewOrphanListImpl { + static inline _::OrphanBuilder apply( + _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { + return _::OrphanBuilder::initData(arena, capTable, bounded(size) * BYTES); + } +}; + +template +Orphan Orphanage::newOrphan(uint size) const { + return Orphan(NewOrphanListImpl::apply(arena, capTable, size)); +} + +template +struct Orphanage::GetInnerReader { + static inline _::StructReader apply(const typename T::Reader& t) { + return t._reader; + } +}; + +template +struct Orphanage::GetInnerReader { + static inline _::ListReader apply(const typename T::Reader& t) { + return t.reader; + } +}; + +template +struct Orphanage::GetInnerReader { + static inline const typename T::Reader& apply(const typename T::Reader& t) { + return t; + } +}; + +template +inline Orphan> Orphanage::newOrphanCopy(Reader copyFrom) const { + return Orphan>(_::OrphanBuilder::copy( + arena, capTable, GetInnerReader>::apply(copyFrom))); +} + +template +inline Orphan>>> +Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { + return newOrphanConcat(kj::implicitCast>(lists)); +} +template +inline Orphan>>> +Orphanage::newOrphanConcat(kj::ArrayPtr lists) const { + // Optimization / simplification: Rely on List::Reader containing nothing except a + // _::ListReader. + static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?"); + kj::ArrayPtr raw( + reinterpret_cast(lists.begin()), lists.size()); + typedef ListElementType> Element; + return Orphan>( + _::OrphanBuilder::concat(arena, capTable, + _::elementSizeForType(), + _::minStructSizeForElement(), raw)); +} + +inline Orphan Orphanage::referenceExternalData(Data::Reader data) const { + return Orphan(_::OrphanBuilder::referenceExternalData(arena, data)); +} + +} // namespace capnp + +#endif // CAPNP_ORPHAN_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/persistent.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/persistent.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,139 @@ +# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xb8630836983feed7; + +$import "/capnp/c++.capnp".namespace("capnp"); + +interface Persistent@0xc8cb212fcd9f5691(SturdyRef, Owner) { + # Interface implemented by capabilities that outlive a single connection. A client may save() + # the capability, producing a SturdyRef. The SturdyRef can be stored to disk, then later used to + # obtain a new reference to the capability on a future connection. + # + # The exact format of SturdyRef depends on the "realm" in which the SturdyRef appears. A "realm" + # is an abstract space in which all SturdyRefs have the same format and refer to the same set of + # resources. Every vat is in exactly one realm. All capability clients within that vat must + # produce SturdyRefs of the format appropriate for the realm. + # + # Similarly, every VatNetwork also resides in a particular realm. Usually, a vat's "realm" + # corresponds to the realm of its main VatNetwork. However, a Vat can in fact communicate over + # a VatNetwork in a different realm -- in this case, all SturdyRefs need to be transformed when + # coming or going through said VatNetwork. The RPC system has hooks for registering + # transformation callbacks for this purpose. + # + # Since the format of SturdyRef is realm-dependent, it is not defined here. An application should + # choose an appropriate realm for itself as part of its design. Note that under Sandstorm, every + # application exists in its own realm and is therefore free to define its own SturdyRef format; + # the Sandstorm platform handles translating between realms. + # + # Note that whether a capability is persistent is often orthogonal to its type. In these cases, + # the capability's interface should NOT inherit `Persistent`; instead, just perform a cast at + # runtime. It's not type-safe, but trying to be type-safe in these cases will likely lead to + # tears. In cases where a particular interface only makes sense on persistent capabilities, it + # still should not explicitly inherit Persistent because the `SturdyRef` and `Owner` types will + # vary between realms (they may even be different at the call site than they are on the + # implementation). Instead, mark persistent interfaces with the $persistent annotation (defined + # below). + # + # Sealing + # ------- + # + # As an added security measure, SturdyRefs may be "sealed" to a particular owner, such that + # if the SturdyRef itself leaks to a third party, that party cannot actually restore it because + # they are not the owner. To restore a sealed capability, you must first prove to its host that + # you are the rightful owner. The precise mechanism for this authentication is defined by the + # realm. + # + # Sealing is a defense-in-depth mechanism meant to mitigate damage in the case of catastrophic + # attacks. For example, say an attacker temporarily gains read access to a database full of + # SturdyRefs: it would be unfortunate if it were then necessary to revoke every single reference + # in the database to prevent the attacker from using them. + # + # In general, an "owner" is a course-grained identity. Because capability-based security is still + # the primary mechanism of security, it is not necessary nor desirable to have a separate "owner" + # identity for every single process or object; that is exactly what capabilities are supposed to + # avoid! Instead, it makes sense for an "owner" to literally identify the owner of the machines + # where the capability is stored. If untrusted third parties are able to run arbitrary code on + # said machines, then the sandbox for that code should be designed using Distributed Confinement + # such that the third-party code never sees the bits of the SturdyRefs and cannot directly + # exercise the owner's power to restore refs. See: + # + # http://www.erights.org/elib/capability/dist-confine.html + # + # Resist the urge to represent an Owner as a simple public key. The whole point of sealing is to + # defend against leaked-storage attacks. Such attacks can easily result in the owner's private + # key being stolen as well. A better solution is for `Owner` to contain a simple globally unique + # identifier for the owner, and for everyone to separately maintain a mapping of owner IDs to + # public keys. If an owner's private key is compromised, then humans will need to communicate + # and agree on a replacement public key, then update the mapping. + # + # As a concrete example, an `Owner` could simply contain a domain name, and restoring a SturdyRef + # would require signing a request using the domain's private key. Authenticating this key could + # be accomplished through certificate authorities or web-of-trust techniques. + + save @0 SaveParams -> SaveResults; + # Save a capability persistently so that it can be restored by a future connection. Not all + # capabilities can be saved -- application interfaces should define which capabilities support + # this and which do not. + + struct SaveParams { + sealFor @0 :Owner; + # Seal the SturdyRef so that it can only be restored by the specified Owner. This is meant + # to mitigate damage when a SturdyRef is leaked. See comments above. + # + # Leaving this value null may or may not be allowed; it is up to the realm to decide. If a + # realm does allow a null owner, this should indicate that anyone is allowed to restore the + # ref. + } + struct SaveResults { + sturdyRef @0 :SturdyRef; + } +} + +interface RealmGateway(InternalRef, ExternalRef, InternalOwner, ExternalOwner) { + # Interface invoked when a SturdyRef is about to cross realms. The RPC system supports providing + # a RealmGateway as a callback hook when setting up RPC over some VatNetwork. + + import @0 (cap :Persistent(ExternalRef, ExternalOwner), + params :Persistent(InternalRef, InternalOwner).SaveParams) + -> Persistent(InternalRef, InternalOwner).SaveResults; + # Given an external capability, save it and return an internal reference. Used when someone + # inside the realm tries to save a capability from outside the realm. + + export @1 (cap :Persistent(InternalRef, InternalOwner), + params :Persistent(ExternalRef, ExternalOwner).SaveParams) + -> Persistent(ExternalRef, ExternalOwner).SaveResults; + # Given an internal capability, save it and return an external reference. Used when someone + # outside the realm tries to save a capability from inside the realm. +} + +annotation persistent(interface, field) :Void; +# Apply this annotation to interfaces for objects that will always be persistent, instead of +# extending the Persistent capability, since the correct type parameters to Persistent depend on +# the realm, which is orthogonal to the interface type and therefore should not be defined +# along-side it. +# +# You may also apply this annotation to a capability-typed field which will always contain a +# persistent capability, but where the capability's interface itself is not already marked +# persistent. +# +# Note that absence of the $persistent annotation doesn't mean a capability of that type isn't +# persistent; it just means not *all* such capabilities are persistent. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/persistent.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/persistent.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,535 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: persistent.capnp + +#include "persistent.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<54> b_c8cb212fcd9f5691 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 23, 0, 0, 0, 3, 0, 0, 0, + 215, 238, 63, 152, 54, 8, 99, 184, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 37, 0, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 65, 0, 0, 0, 71, 0, 0, 0, + 145, 0, 0, 0, 7, 0, 0, 0, + 145, 0, 0, 0, 23, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 80, + 101, 114, 115, 105, 115, 116, 101, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 165, 115, 48, 24, 89, 186, 111, 247, + 9, 0, 0, 0, 90, 0, 0, 0, + 191, 239, 64, 140, 193, 72, 104, 183, + 9, 0, 0, 0, 98, 0, 0, 0, + 83, 97, 118, 101, 80, 97, 114, 97, + 109, 115, 0, 0, 0, 0, 0, 0, + 83, 97, 118, 101, 82, 101, 115, 117, + 108, 116, 115, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 115, 48, 24, 89, 186, 111, 247, + 191, 239, 64, 140, 193, 72, 104, 183, + 17, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 1, 0, + 28, 0, 0, 0, 0, 0, 1, 0, + 45, 0, 0, 0, 7, 0, 0, 0, + 115, 97, 118, 101, 0, 0, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 0, 0, 1, 0, + 5, 0, 0, 0, 82, 0, 0, 0, + 9, 0, 0, 0, 50, 0, 0, 0, + 83, 116, 117, 114, 100, 121, 82, 101, + 102, 0, 0, 0, 0, 0, 0, 0, + 79, 119, 110, 101, 114, 0, 0, 0, } +}; +::capnp::word const* const bp_c8cb212fcd9f5691 = b_c8cb212fcd9f5691.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c8cb212fcd9f5691[] = { + &s_b76848c18c40efbf, + &s_f76fba59183073a5, +}; +static const uint16_t m_c8cb212fcd9f5691[] = {0}; +KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_c8cb212fcd9f5691[] = { + { 33554432, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveResults::_capnpPrivate::brand() }, +}; +const ::capnp::_::RawSchema s_c8cb212fcd9f5691 = { + 0xc8cb212fcd9f5691, b_c8cb212fcd9f5691.words, 54, d_c8cb212fcd9f5691, m_c8cb212fcd9f5691, + 2, 1, nullptr, nullptr, nullptr, { &s_c8cb212fcd9f5691, nullptr, bd_c8cb212fcd9f5691, 0, sizeof(bd_c8cb212fcd9f5691) / sizeof(bd_c8cb212fcd9f5691[0]), nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<35> b_f76fba59183073a5 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 165, 115, 48, 24, 89, 186, 111, 247, + 34, 0, 0, 0, 1, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 106, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 80, + 101, 114, 115, 105, 115, 116, 101, 110, + 116, 46, 83, 97, 118, 101, 80, 97, + 114, 97, 109, 115, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 115, 101, 97, 108, 70, 111, 114, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f76fba59183073a5 = b_f76fba59183073a5.words; +#if !CAPNP_LITE +static const uint16_t m_f76fba59183073a5[] = {0}; +static const uint16_t i_f76fba59183073a5[] = {0}; +const ::capnp::_::RawSchema s_f76fba59183073a5 = { + 0xf76fba59183073a5, b_f76fba59183073a5.words, 35, nullptr, m_f76fba59183073a5, + 0, 1, i_f76fba59183073a5, nullptr, nullptr, { &s_f76fba59183073a5, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<36> b_b76848c18c40efbf = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 191, 239, 64, 140, 193, 72, 104, 183, + 34, 0, 0, 0, 1, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 114, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 80, + 101, 114, 115, 105, 115, 116, 101, 110, + 116, 46, 83, 97, 118, 101, 82, 101, + 115, 117, 108, 116, 115, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 24, 0, 0, 0, 2, 0, 1, 0, + 115, 116, 117, 114, 100, 121, 82, 101, + 102, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b76848c18c40efbf = b_b76848c18c40efbf.words; +#if !CAPNP_LITE +static const uint16_t m_b76848c18c40efbf[] = {0}; +static const uint16_t i_b76848c18c40efbf[] = {0}; +const ::capnp::_::RawSchema s_b76848c18c40efbf = { + 0xb76848c18c40efbf, b_b76848c18c40efbf.words, 36, nullptr, m_b76848c18c40efbf, + 0, 1, i_b76848c18c40efbf, nullptr, nullptr, { &s_b76848c18c40efbf, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<99> b_84ff286cd00a3ed4 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 23, 0, 0, 0, 3, 0, 0, 0, + 215, 238, 63, 152, 54, 8, 99, 184, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 34, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 135, 0, 0, 0, + 41, 1, 0, 0, 7, 0, 0, 0, + 41, 1, 0, 0, 39, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 82, + 101, 97, 108, 109, 71, 97, 116, 101, + 119, 97, 121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 87, 9, 57, 29, 204, 194, 240, + 191, 239, 64, 140, 193, 72, 104, 183, + 49, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 0, 0, 1, 0, + 60, 0, 0, 0, 0, 0, 1, 0, + 129, 0, 0, 0, 7, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 170, 163, 45, 72, 139, 161, 175, 236, + 191, 239, 64, 140, 193, 72, 104, 183, + 117, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 0, 0, 0, 0, 0, 1, 0, + 128, 0, 0, 0, 0, 0, 1, 0, + 197, 0, 0, 0, 7, 0, 0, 0, + 105, 109, 112, 111, 114, 116, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 2, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 101, 120, 112, 111, 114, 116, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 3, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 1, 0, + 13, 0, 0, 0, 98, 0, 0, 0, + 17, 0, 0, 0, 98, 0, 0, 0, + 21, 0, 0, 0, 114, 0, 0, 0, + 25, 0, 0, 0, 114, 0, 0, 0, + 73, 110, 116, 101, 114, 110, 97, 108, + 82, 101, 102, 0, 0, 0, 0, 0, + 69, 120, 116, 101, 114, 110, 97, 108, + 82, 101, 102, 0, 0, 0, 0, 0, + 73, 110, 116, 101, 114, 110, 97, 108, + 79, 119, 110, 101, 114, 0, 0, 0, + 69, 120, 116, 101, 114, 110, 97, 108, + 79, 119, 110, 101, 114, 0, 0, 0, } +}; +::capnp::word const* const bp_84ff286cd00a3ed4 = b_84ff286cd00a3ed4.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_84ff286cd00a3ed4[] = { + &s_b76848c18c40efbf, + &s_ecafa18b482da3aa, + &s_f0c2cc1d3909574d, +}; +static const uint16_t m_84ff286cd00a3ed4[] = {1, 0}; +KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_84ff286cd00a3ed4[] = { + { 33554432, ::capnp::RealmGateway< ::capnp::AnyPointer, ::capnp::AnyPointer, ::capnp::AnyPointer, ::capnp::AnyPointer>::ImportParams::_capnpPrivate::brand() }, + { 33554433, ::capnp::RealmGateway< ::capnp::AnyPointer, ::capnp::AnyPointer, ::capnp::AnyPointer, ::capnp::AnyPointer>::ExportParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveResults::_capnpPrivate::brand() }, + { 50331649, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveResults::_capnpPrivate::brand() }, +}; +const ::capnp::_::RawSchema s_84ff286cd00a3ed4 = { + 0x84ff286cd00a3ed4, b_84ff286cd00a3ed4.words, 99, d_84ff286cd00a3ed4, m_84ff286cd00a3ed4, + 3, 2, nullptr, nullptr, nullptr, { &s_84ff286cd00a3ed4, nullptr, bd_84ff286cd00a3ed4, 0, sizeof(bd_84ff286cd00a3ed4) / sizeof(bd_84ff286cd00a3ed4[0]), nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<86> b_f0c2cc1d3909574d = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 77, 87, 9, 57, 29, 204, 194, 240, + 36, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 146, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 82, + 101, 97, 108, 109, 71, 97, 116, 101, + 119, 97, 121, 46, 105, 109, 112, 111, + 114, 116, 36, 80, 97, 114, 97, 109, + 115, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 120, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 0, 0, 0, 3, 0, 1, 0, + 196, 0, 0, 0, 2, 0, 1, 0, + 99, 97, 112, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 3, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 165, 115, 48, 24, 89, 186, 111, 247, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 2, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f0c2cc1d3909574d = b_f0c2cc1d3909574d.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_f0c2cc1d3909574d[] = { + &s_c8cb212fcd9f5691, + &s_f76fba59183073a5, +}; +static const uint16_t m_f0c2cc1d3909574d[] = {0, 1}; +static const uint16_t i_f0c2cc1d3909574d[] = {0, 1}; +KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_f0c2cc1d3909574d[] = { + { 16777216, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveParams::_capnpPrivate::brand() }, +}; +const ::capnp::_::RawSchema s_f0c2cc1d3909574d = { + 0xf0c2cc1d3909574d, b_f0c2cc1d3909574d.words, 86, d_f0c2cc1d3909574d, m_f0c2cc1d3909574d, + 2, 2, i_f0c2cc1d3909574d, nullptr, nullptr, { &s_f0c2cc1d3909574d, nullptr, bd_f0c2cc1d3909574d, 0, sizeof(bd_f0c2cc1d3909574d) / sizeof(bd_f0c2cc1d3909574d[0]), nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<86> b_ecafa18b482da3aa = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 170, 163, 45, 72, 139, 161, 175, 236, + 36, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 21, 0, 0, 0, 146, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 82, + 101, 97, 108, 109, 71, 97, 116, 101, + 119, 97, 121, 46, 101, 120, 112, 111, + 114, 116, 36, 80, 97, 114, 97, 109, + 115, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 120, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 0, 0, 0, 3, 0, 1, 0, + 196, 0, 0, 0, 2, 0, 1, 0, + 99, 97, 112, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 2, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 165, 115, 48, 24, 89, 186, 111, 247, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 31, 0, 0, 0, + 4, 0, 0, 0, 2, 0, 1, 0, + 145, 86, 159, 205, 47, 33, 203, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 39, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 1, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 3, 0, 0, 0, 0, 0, + 212, 62, 10, 208, 108, 40, 255, 132, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ecafa18b482da3aa = b_ecafa18b482da3aa.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_ecafa18b482da3aa[] = { + &s_c8cb212fcd9f5691, + &s_f76fba59183073a5, +}; +static const uint16_t m_ecafa18b482da3aa[] = {0, 1}; +static const uint16_t i_ecafa18b482da3aa[] = {0, 1}; +KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_ecafa18b482da3aa[] = { + { 16777216, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent< ::capnp::AnyPointer, ::capnp::AnyPointer>::SaveParams::_capnpPrivate::brand() }, +}; +const ::capnp::_::RawSchema s_ecafa18b482da3aa = { + 0xecafa18b482da3aa, b_ecafa18b482da3aa.words, 86, d_ecafa18b482da3aa, m_ecafa18b482da3aa, + 2, 2, i_ecafa18b482da3aa, nullptr, nullptr, { &s_ecafa18b482da3aa, nullptr, bd_ecafa18b482da3aa, 0, sizeof(bd_ecafa18b482da3aa) / sizeof(bd_ecafa18b482da3aa[0]), nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<22> b_f622595091cafb67 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 103, 251, 202, 145, 80, 89, 34, 246, + 23, 0, 0, 0, 5, 0, 32, 1, + 215, 238, 63, 152, 54, 8, 99, 184, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 0, 0, 0, 3, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 112, 101, + 114, 115, 105, 115, 116, 101, 110, 116, + 46, 99, 97, 112, 110, 112, 58, 112, + 101, 114, 115, 105, 115, 116, 101, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f622595091cafb67 = b_f622595091cafb67.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_f622595091cafb67 = { + 0xf622595091cafb67, b_f622595091cafb67.words, 22, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_f622595091cafb67, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/persistent.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/persistent.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1328 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: persistent.capnp + +#ifndef CAPNP_INCLUDED_b8630836983feed7_ +#define CAPNP_INCLUDED_b8630836983feed7_ + +#include +#if !CAPNP_LITE +#include +#endif // !CAPNP_LITE + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(c8cb212fcd9f5691); +CAPNP_DECLARE_SCHEMA(f76fba59183073a5); +CAPNP_DECLARE_SCHEMA(b76848c18c40efbf); +CAPNP_DECLARE_SCHEMA(84ff286cd00a3ed4); +CAPNP_DECLARE_SCHEMA(f0c2cc1d3909574d); +CAPNP_DECLARE_SCHEMA(ecafa18b482da3aa); +CAPNP_DECLARE_SCHEMA(f622595091cafb67); + +} // namespace schemas +} // namespace capnp + +namespace capnp { + +template +struct Persistent { + Persistent() = delete; + +#if !CAPNP_LITE + class Client; + class Server; +#endif // !CAPNP_LITE + + struct SaveParams; + struct SaveResults; + + #if !CAPNP_LITE + struct _capnpPrivate { + CAPNP_DECLARE_INTERFACE_HEADER(c8cb212fcd9f5691) + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + }; + #endif // !CAPNP_LITE +}; + +template +struct Persistent::SaveParams { + SaveParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f76fba59183073a5, 0, 1) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct Persistent::SaveResults { + SaveResults() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b76848c18c40efbf, 0, 1) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, SturdyRef, Owner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct RealmGateway { + RealmGateway() = delete; + +#if !CAPNP_LITE + class Client; + class Server; +#endif // !CAPNP_LITE + + struct ImportParams; + struct ExportParams; + + #if !CAPNP_LITE + struct _capnpPrivate { + CAPNP_DECLARE_INTERFACE_HEADER(84ff286cd00a3ed4) + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + }; + #endif // !CAPNP_LITE +}; + +template +struct RealmGateway::ImportParams { + ImportParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f0c2cc1d3909574d, 0, 2) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +template +struct RealmGateway::ExportParams { + ExportParams() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ecafa18b482da3aa, 0, 2) + #if !CAPNP_LITE + static const ::capnp::_::RawBrandedSchema::Scope brandScopes[]; + static const ::capnp::_::RawBrandedSchema::Binding brandBindings[]; + static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[]; + static const ::capnp::_::RawBrandedSchema specificBrand; + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return ::capnp::_::ChooseBrand<_capnpPrivate, InternalRef, ExternalRef, InternalOwner, ExternalOwner>::brand(); } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +#if !CAPNP_LITE +template +class Persistent::Client + : public virtual ::capnp::Capability::Client { +public: + typedef Persistent Calls; + typedef Persistent Reads; + + Client(decltype(nullptr)); + explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); + template ()>> + Client(::kj::Own<_t>&& server); + template ()>> + Client(::kj::Promise<_t>&& promise); + Client(::kj::Exception&& exception); + Client(Client&) = default; + Client(Client&&) = default; + Client& operator=(Client& other); + Client& operator=(Client&& other); + + template + typename Persistent::Client asGeneric() { + return castAs>(); + } + + CAPNP_AUTO_IF_MSVC(::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults>) saveRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + +protected: + Client() = default; +}; + +template +class Persistent::Server + : public virtual ::capnp::Capability::Server { +public: + typedef Persistent Serves; + + ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) + override; + +protected: + typedef ::capnp::CallContext::SaveParams, typename ::capnp::Persistent::SaveResults> SaveContext; + virtual ::kj::Promise save(SaveContext context); + + inline typename ::capnp::Persistent::Client thisCap() { + return ::capnp::Capability::Server::thisCap() + .template castAs< ::capnp::Persistent>(); + } + + ::kj::Promise dispatchCallInternal(uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); +}; +#endif // !CAPNP_LITE + +template +class Persistent::SaveParams::Reader { +public: + typedef SaveParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveParams::Reader asPersistentGeneric() { + return typename Persistent::SaveParams::Reader(_reader); + } + + inline bool hasSealFor() const; + inline ::capnp::ReaderFor getSealFor() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class Persistent::SaveParams::Builder { +public: + typedef SaveParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveParams::Builder asPersistentGeneric() { + return typename Persistent::SaveParams::Builder(_builder); + } + + inline bool hasSealFor(); + inline ::capnp::BuilderFor getSealFor(); + inline void setSealFor( ::capnp::ReaderFor value); + inline ::capnp::BuilderFor initSealFor(); + inline ::capnp::BuilderFor initSealFor(unsigned int size); + inline void adoptSealFor(::capnp::Orphan&& value); + inline ::capnp::Orphan disownSealFor(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class Persistent::SaveParams::Pipeline { +public: + typedef SaveParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::PipelineFor getSealFor(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +template +class Persistent::SaveResults::Reader { +public: + typedef SaveResults Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveResults::Reader asPersistentGeneric() { + return typename Persistent::SaveResults::Reader(_reader); + } + + inline bool hasSturdyRef() const; + inline ::capnp::ReaderFor getSturdyRef() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class Persistent::SaveResults::Builder { +public: + typedef SaveResults Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename Persistent::SaveResults::Builder asPersistentGeneric() { + return typename Persistent::SaveResults::Builder(_builder); + } + + inline bool hasSturdyRef(); + inline ::capnp::BuilderFor getSturdyRef(); + inline void setSturdyRef( ::capnp::ReaderFor value); + inline ::capnp::BuilderFor initSturdyRef(); + inline ::capnp::BuilderFor initSturdyRef(unsigned int size); + inline void adoptSturdyRef(::capnp::Orphan&& value); + inline ::capnp::Orphan disownSturdyRef(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class Persistent::SaveResults::Pipeline { +public: + typedef SaveResults Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::PipelineFor getSturdyRef(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +class RealmGateway::Client + : public virtual ::capnp::Capability::Client { +public: + typedef RealmGateway Calls; + typedef RealmGateway Reads; + + Client(decltype(nullptr)); + explicit Client(::kj::Own< ::capnp::ClientHook>&& hook); + template ()>> + Client(::kj::Own<_t>&& server); + template ()>> + Client(::kj::Promise<_t>&& promise); + Client(::kj::Exception&& exception); + Client(Client&) = default; + Client(Client&&) = default; + Client& operator=(Client& other); + Client& operator=(Client&& other); + + template + typename RealmGateway::Client asGeneric() { + return castAs>(); + } + + CAPNP_AUTO_IF_MSVC(::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults>) importRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + CAPNP_AUTO_IF_MSVC(::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults>) exportRequest( + ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr); + +protected: + Client() = default; +}; + +template +class RealmGateway::Server + : public virtual ::capnp::Capability::Server { +public: + typedef RealmGateway Serves; + + ::kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) + override; + +protected: + typedef typename ::capnp::RealmGateway::ImportParams ImportParams; + typedef ::capnp::CallContext::SaveResults> ImportContext; + virtual ::kj::Promise import(ImportContext context); + typedef typename ::capnp::RealmGateway::ExportParams ExportParams; + typedef ::capnp::CallContext::SaveResults> ExportContext; + virtual ::kj::Promise export_(ExportContext context); + + inline typename ::capnp::RealmGateway::Client thisCap() { + return ::capnp::Capability::Server::thisCap() + .template castAs< ::capnp::RealmGateway>(); + } + + ::kj::Promise dispatchCallInternal(uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context); +}; +#endif // !CAPNP_LITE + +template +class RealmGateway::ImportParams::Reader { +public: + typedef ImportParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ImportParams::Reader asRealmGatewayGeneric() { + return typename RealmGateway::ImportParams::Reader(_reader); + } + + inline bool hasCap() const; +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap() const; +#endif // !CAPNP_LITE + + inline bool hasParams() const; + inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class RealmGateway::ImportParams::Builder { +public: + typedef ImportParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ImportParams::Builder asRealmGatewayGeneric() { + return typename RealmGateway::ImportParams::Builder(_builder); + } + + inline bool hasCap(); +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap(); + inline void setCap(typename ::capnp::Persistent::Client&& value); + inline void setCap(typename ::capnp::Persistent::Client& value); + inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); + inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); +#endif // !CAPNP_LITE + + inline bool hasParams(); + inline typename ::capnp::Persistent::SaveParams::Builder getParams(); + inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); + inline typename ::capnp::Persistent::SaveParams::Builder initParams(); + inline void adoptParams(::capnp::Orphan::SaveParams>&& value); + inline ::capnp::Orphan::SaveParams> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class RealmGateway::ImportParams::Pipeline { +public: + typedef ImportParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename ::capnp::Persistent::Client getCap(); + inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +template +class RealmGateway::ExportParams::Reader { +public: + typedef ExportParams Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ExportParams::Reader asRealmGatewayGeneric() { + return typename RealmGateway::ExportParams::Reader(_reader); + } + + inline bool hasCap() const; +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap() const; +#endif // !CAPNP_LITE + + inline bool hasParams() const; + inline typename ::capnp::Persistent::SaveParams::Reader getParams() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +template +class RealmGateway::ExportParams::Builder { +public: + typedef ExportParams Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + template + typename RealmGateway::ExportParams::Builder asRealmGatewayGeneric() { + return typename RealmGateway::ExportParams::Builder(_builder); + } + + inline bool hasCap(); +#if !CAPNP_LITE + inline typename ::capnp::Persistent::Client getCap(); + inline void setCap(typename ::capnp::Persistent::Client&& value); + inline void setCap(typename ::capnp::Persistent::Client& value); + inline void adoptCap(::capnp::Orphan< ::capnp::Persistent>&& value); + inline ::capnp::Orphan< ::capnp::Persistent> disownCap(); +#endif // !CAPNP_LITE + + inline bool hasParams(); + inline typename ::capnp::Persistent::SaveParams::Builder getParams(); + inline void setParams(typename ::capnp::Persistent::SaveParams::Reader value); + inline typename ::capnp::Persistent::SaveParams::Builder initParams(); + inline void adoptParams(::capnp::Orphan::SaveParams>&& value); + inline ::capnp::Orphan::SaveParams> disownParams(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +template +class RealmGateway::ExportParams::Pipeline { +public: + typedef ExportParams Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename ::capnp::Persistent::Client getCap(); + inline typename ::capnp::Persistent::SaveParams::Pipeline getParams(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +#if !CAPNP_LITE +template +inline Persistent::Client::Client(decltype(nullptr)) + : ::capnp::Capability::Client(nullptr) {} +template +inline Persistent::Client::Client( + ::kj::Own< ::capnp::ClientHook>&& hook) + : ::capnp::Capability::Client(::kj::mv(hook)) {} +template +template +inline Persistent::Client::Client(::kj::Own<_t>&& server) + : ::capnp::Capability::Client(::kj::mv(server)) {} +template +template +inline Persistent::Client::Client(::kj::Promise<_t>&& promise) + : ::capnp::Capability::Client(::kj::mv(promise)) {} +template +inline Persistent::Client::Client(::kj::Exception&& exception) + : ::capnp::Capability::Client(::kj::mv(exception)) {} +template +inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client& other) { + ::capnp::Capability::Client::operator=(other); + return *this; +} +template +inline typename ::capnp::Persistent::Client& Persistent::Client::operator=(Client&& other) { + ::capnp::Capability::Client::operator=(kj::mv(other)); + return *this; +} + +#endif // !CAPNP_LITE +template +inline bool Persistent::SaveParams::Reader::hasSealFor() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool Persistent::SaveParams::Builder::hasSealFor() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline ::capnp::ReaderFor Persistent::SaveParams::Reader::getSealFor() const { + return ::capnp::_::PointerHelpers::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::getSealFor() { + return ::capnp::_::PointerHelpers::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline ::capnp::PipelineFor Persistent::SaveParams::Pipeline::getSealFor() { + return ::capnp::PipelineFor(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +template +inline void Persistent::SaveParams::Builder::setSealFor( ::capnp::ReaderFor value) { + ::capnp::_::PointerHelpers::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor() { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveParams::Builder::initSealFor(unsigned int size) { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +template +inline void Persistent::SaveParams::Builder::adoptSealFor( + ::capnp::Orphan&& value) { + ::capnp::_::PointerHelpers::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan Persistent::SaveParams::Builder::disownSealFor() { + return ::capnp::_::PointerHelpers::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +// Persistent::SaveParams +template +constexpr uint16_t Persistent::SaveParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t Persistent::SaveParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::SaveParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::SaveParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveParams::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema Persistent::SaveParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_f76fba59183073a5, brandScopes, nullptr, + 1, 0, nullptr +}; +#endif // !CAPNP_LITE + +template +inline bool Persistent::SaveResults::Reader::hasSturdyRef() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool Persistent::SaveResults::Builder::hasSturdyRef() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline ::capnp::ReaderFor Persistent::SaveResults::Reader::getSturdyRef() const { + return ::capnp::_::PointerHelpers::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::getSturdyRef() { + return ::capnp::_::PointerHelpers::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline ::capnp::PipelineFor Persistent::SaveResults::Pipeline::getSturdyRef() { + return ::capnp::PipelineFor(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +template +inline void Persistent::SaveResults::Builder::setSturdyRef( ::capnp::ReaderFor value) { + ::capnp::_::PointerHelpers::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef() { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline ::capnp::BuilderFor Persistent::SaveResults::Builder::initSturdyRef(unsigned int size) { + return ::capnp::_::PointerHelpers::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +template +inline void Persistent::SaveResults::Builder::adoptSturdyRef( + ::capnp::Orphan&& value) { + ::capnp::_::PointerHelpers::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan Persistent::SaveResults::Builder::disownSturdyRef() { + return ::capnp::_::PointerHelpers::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +// Persistent::SaveResults +template +constexpr uint16_t Persistent::SaveResults::_capnpPrivate::dataWordSize; +template +constexpr uint16_t Persistent::SaveResults::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::SaveResults::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::SaveResults::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::SaveResults::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::SaveResults::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema Persistent::SaveResults::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_b76848c18c40efbf, brandScopes, nullptr, + 1, 0, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::SaveParams, typename ::capnp::Persistent::SaveResults>) +Persistent::Client::saveRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::SaveParams, typename ::capnp::Persistent::SaveResults>( + 0xc8cb212fcd9f5691ull, 0, sizeHint); +} +template +::kj::Promise Persistent::Server::save(SaveContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:Persistent", "save", + 0xc8cb212fcd9f5691ull, 0); +} +template +::kj::Promise Persistent::Server::dispatchCall( + uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (interfaceId) { + case 0xc8cb212fcd9f5691ull: + return dispatchCallInternal(methodId, context); + default: + return internalUnimplemented("capnp/persistent.capnp:Persistent", interfaceId); + } +} +template +::kj::Promise Persistent::Server::dispatchCallInternal( + uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (methodId) { + case 0: + return save(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::Persistent::SaveParams, typename ::capnp::Persistent::SaveResults>(context)); + default: + (void)context; + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:Persistent", + 0xc8cb212fcd9f5691ull, methodId); + } +} +#endif // !CAPNP_LITE + +// Persistent +#if !CAPNP_LITE +template +constexpr ::capnp::Kind Persistent::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* Persistent::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope Persistent::_capnpPrivate::brandScopes[] = { + { 0xc8cb212fcd9f5691, brandBindings + 0, 2, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding Persistent::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency Persistent::_capnpPrivate::brandDependencies[] = { + { 33554432, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema Persistent::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_c8cb212fcd9f5691, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +inline RealmGateway::Client::Client(decltype(nullptr)) + : ::capnp::Capability::Client(nullptr) {} +template +inline RealmGateway::Client::Client( + ::kj::Own< ::capnp::ClientHook>&& hook) + : ::capnp::Capability::Client(::kj::mv(hook)) {} +template +template +inline RealmGateway::Client::Client(::kj::Own<_t>&& server) + : ::capnp::Capability::Client(::kj::mv(server)) {} +template +template +inline RealmGateway::Client::Client(::kj::Promise<_t>&& promise) + : ::capnp::Capability::Client(::kj::mv(promise)) {} +template +inline RealmGateway::Client::Client(::kj::Exception&& exception) + : ::capnp::Capability::Client(::kj::mv(exception)) {} +template +inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client& other) { + ::capnp::Capability::Client::operator=(other); + return *this; +} +template +inline typename ::capnp::RealmGateway::Client& RealmGateway::Client::operator=(Client&& other) { + ::capnp::Capability::Client::operator=(kj::mv(other)); + return *this; +} + +#endif // !CAPNP_LITE +template +inline bool RealmGateway::ImportParams::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ImportParams::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Reader::getCap() const { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Builder::getCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ImportParams::Pipeline::getCap() { + return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); +} +template +inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(cap)); +} +template +inline void RealmGateway::ImportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), cap); +} +template +inline void RealmGateway::ImportParams::Builder::adoptCap( + ::capnp::Orphan< ::capnp::Persistent>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ImportParams::Builder::disownCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ImportParams::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ImportParams::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ImportParams::Reader::getParams() const { + return ::capnp::_::PointerHelpers::SaveParams>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::getParams() { + return ::capnp::_::PointerHelpers::SaveParams>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ImportParams::Pipeline::getParams() { + return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +template +inline void RealmGateway::ImportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { + ::capnp::_::PointerHelpers::SaveParams>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ImportParams::Builder::initParams() { + return ::capnp::_::PointerHelpers::SaveParams>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline void RealmGateway::ImportParams::Builder::adoptParams( + ::capnp::Orphan::SaveParams>&& value) { + ::capnp::_::PointerHelpers::SaveParams>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan::SaveParams> RealmGateway::ImportParams::Builder::disownParams() { + return ::capnp::_::PointerHelpers::SaveParams>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +// RealmGateway::ImportParams +template +constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t RealmGateway::ImportParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::ImportParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::ImportParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ImportParams::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ImportParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ImportParams::_capnpPrivate::brandDependencies[] = { + { 16777216, ::capnp::Persistent::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::ImportParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_f0c2cc1d3909574d, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ExportParams::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ExportParams::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Reader::getCap() const { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Builder::getCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::Client RealmGateway::ExportParams::Pipeline::getCap() { + return typename ::capnp::Persistent::Client(_typeless.getPointerField(0).asCap()); +} +template +inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client&& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(cap)); +} +template +inline void RealmGateway::ExportParams::Builder::setCap(typename ::capnp::Persistent::Client& cap) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), cap); +} +template +inline void RealmGateway::ExportParams::Builder::adoptCap( + ::capnp::Orphan< ::capnp::Persistent>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Persistent>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan< ::capnp::Persistent> RealmGateway::ExportParams::Builder::disownCap() { + return ::capnp::_::PointerHelpers< ::capnp::Persistent>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#endif // !CAPNP_LITE + +template +inline bool RealmGateway::ExportParams::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline bool RealmGateway::ExportParams::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +template +inline typename ::capnp::Persistent::SaveParams::Reader RealmGateway::ExportParams::Reader::getParams() const { + return ::capnp::_::PointerHelpers::SaveParams>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::getParams() { + return ::capnp::_::PointerHelpers::SaveParams>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +template +inline typename ::capnp::Persistent::SaveParams::Pipeline RealmGateway::ExportParams::Pipeline::getParams() { + return typename ::capnp::Persistent::SaveParams::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +template +inline void RealmGateway::ExportParams::Builder::setParams(typename ::capnp::Persistent::SaveParams::Reader value) { + ::capnp::_::PointerHelpers::SaveParams>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +template +inline typename ::capnp::Persistent::SaveParams::Builder RealmGateway::ExportParams::Builder::initParams() { + return ::capnp::_::PointerHelpers::SaveParams>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +template +inline void RealmGateway::ExportParams::Builder::adoptParams( + ::capnp::Orphan::SaveParams>&& value) { + ::capnp::_::PointerHelpers::SaveParams>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +template +inline ::capnp::Orphan::SaveParams> RealmGateway::ExportParams::Builder::disownParams() { + return ::capnp::_::PointerHelpers::SaveParams>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +// RealmGateway::ExportParams +template +constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::dataWordSize; +template +constexpr uint16_t RealmGateway::ExportParams::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::ExportParams::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::ExportParams::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::ExportParams::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::ExportParams::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::ExportParams::_capnpPrivate::brandDependencies[] = { + { 16777216, ::capnp::Persistent::_capnpPrivate::brand() }, + { 16777217, ::capnp::Persistent::SaveParams::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::ExportParams::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_ecafa18b482da3aa, brandScopes, brandDependencies, + 1, 2, nullptr +}; +#endif // !CAPNP_LITE + +#if !CAPNP_LITE +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::ImportParams, typename ::capnp::Persistent::SaveResults>) +RealmGateway::Client::importRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::ImportParams, typename ::capnp::Persistent::SaveResults>( + 0x84ff286cd00a3ed4ull, 0, sizeHint); +} +template +::kj::Promise RealmGateway::Server::import(ImportContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", "import", + 0x84ff286cd00a3ed4ull, 0); +} +template +CAPNP_AUTO_IF_MSVC(::capnp::Request::ExportParams, typename ::capnp::Persistent::SaveResults>) +RealmGateway::Client::exportRequest(::kj::Maybe< ::capnp::MessageSize> sizeHint) { + return newCall::ExportParams, typename ::capnp::Persistent::SaveResults>( + 0x84ff286cd00a3ed4ull, 1, sizeHint); +} +template +::kj::Promise RealmGateway::Server::export_(ExportContext) { + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", "export", + 0x84ff286cd00a3ed4ull, 1); +} +template +::kj::Promise RealmGateway::Server::dispatchCall( + uint64_t interfaceId, uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (interfaceId) { + case 0x84ff286cd00a3ed4ull: + return dispatchCallInternal(methodId, context); + default: + return internalUnimplemented("capnp/persistent.capnp:RealmGateway", interfaceId); + } +} +template +::kj::Promise RealmGateway::Server::dispatchCallInternal( + uint16_t methodId, + ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) { + switch (methodId) { + case 0: + return import(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::RealmGateway::ImportParams, typename ::capnp::Persistent::SaveResults>(context)); + case 1: + return export_(::capnp::Capability::Server::internalGetTypedContext< + typename ::capnp::RealmGateway::ExportParams, typename ::capnp::Persistent::SaveResults>(context)); + default: + (void)context; + return ::capnp::Capability::Server::internalUnimplemented( + "capnp/persistent.capnp:RealmGateway", + 0x84ff286cd00a3ed4ull, methodId); + } +} +#endif // !CAPNP_LITE + +// RealmGateway +#if !CAPNP_LITE +template +constexpr ::capnp::Kind RealmGateway::_capnpPrivate::kind; +template +constexpr ::capnp::_::RawSchema const* RealmGateway::_capnpPrivate::schema; +template +const ::capnp::_::RawBrandedSchema::Scope RealmGateway::_capnpPrivate::brandScopes[] = { + { 0x84ff286cd00a3ed4, brandBindings + 0, 4, false}, +}; +template +const ::capnp::_::RawBrandedSchema::Binding RealmGateway::_capnpPrivate::brandBindings[] = { + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), + ::capnp::_::brandBindingFor(), +}; +template +const ::capnp::_::RawBrandedSchema::Dependency RealmGateway::_capnpPrivate::brandDependencies[] = { + { 33554432, ::capnp::RealmGateway::ImportParams::_capnpPrivate::brand() }, + { 33554433, ::capnp::RealmGateway::ExportParams::_capnpPrivate::brand() }, + { 50331648, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, + { 50331649, ::capnp::Persistent::SaveResults::_capnpPrivate::brand() }, +}; +template +const ::capnp::_::RawBrandedSchema RealmGateway::_capnpPrivate::specificBrand = { + &::capnp::schemas::s_84ff286cd00a3ed4, brandScopes, brandDependencies, + 1, 4, nullptr +}; +#endif // !CAPNP_LITE + +} // namespace + +#endif // CAPNP_INCLUDED_b8630836983feed7_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/pointer-helpers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/pointer-helpers.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,160 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_POINTER_HELPERS_H_ +#define CAPNP_POINTER_HELPERS_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "layout.h" +#include "list.h" + +namespace capnp { +namespace _ { // private + +// PointerHelpers is a template class that assists in wrapping/unwrapping the low-level types in +// layout.h with the high-level public API and generated types. This way, the code generator +// and other templates do not have to specialize on each kind of pointer. + +template +struct PointerHelpers { + static inline typename T::Reader get(PointerReader reader, const word* defaultValue = nullptr) { + return typename T::Reader(reader.getStruct(defaultValue)); + } + static inline typename T::Builder get(PointerBuilder builder, + const word* defaultValue = nullptr) { + return typename T::Builder(builder.getStruct(structSize(), defaultValue)); + } + static inline void set(PointerBuilder builder, typename T::Reader value) { + builder.setStruct(value._reader); + } + static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { + builder.setStruct(value._reader, true); + } + static inline typename T::Builder init(PointerBuilder builder) { + return typename T::Builder(builder.initStruct(structSize())); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } + static inline _::StructReader getInternalReader(const typename T::Reader& reader) { + return reader._reader; + } + static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) { + return builder._builder; + } +}; + +template +struct PointerHelpers, Kind::LIST> { + static inline typename List::Reader get(PointerReader reader, + const word* defaultValue = nullptr) { + return typename List::Reader(List::getFromPointer(reader, defaultValue)); + } + static inline typename List::Builder get(PointerBuilder builder, + const word* defaultValue = nullptr) { + return typename List::Builder(List::getFromPointer(builder, defaultValue)); + } + static inline void set(PointerBuilder builder, typename List::Reader value) { + builder.setList(value.reader); + } + static inline void setCanonical(PointerBuilder builder, typename List::Reader value) { + builder.setList(value.reader, true); + } + static void set(PointerBuilder builder, kj::ArrayPtr> value) { + auto l = init(builder, value.size()); + uint i = 0; + for (auto& element: value) { + l.set(i++, element); + } + } + static inline typename List::Builder init(PointerBuilder builder, uint size) { + return typename List::Builder(List::initPointer(builder, size)); + } + static inline void adopt(PointerBuilder builder, Orphan>&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan> disown(PointerBuilder builder) { + return Orphan>(builder.disown()); + } + static inline _::ListReader getInternalReader(const typename List::Reader& reader) { + return reader.reader; + } + static inline _::ListBuilder getInternalBuilder(typename List::Builder&& builder) { + return builder.builder; + } +}; + +template +struct PointerHelpers { + static inline typename T::Reader get(PointerReader reader, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return reader.getBlob(defaultValue, bounded(defaultBytes) * BYTES); + } + static inline typename T::Builder get(PointerBuilder builder, + const void* defaultValue = nullptr, + uint defaultBytes = 0) { + return builder.getBlob(defaultValue, bounded(defaultBytes) * BYTES); + } + static inline void set(PointerBuilder builder, typename T::Reader value) { + builder.setBlob(value); + } + static inline void setCanonical(PointerBuilder builder, typename T::Reader value) { + builder.setBlob(value); + } + static inline typename T::Builder init(PointerBuilder builder, uint size) { + return builder.initBlob(bounded(size) * BYTES); + } + static inline void adopt(PointerBuilder builder, Orphan&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan disown(PointerBuilder builder) { + return Orphan(builder.disown()); + } +}; + +struct UncheckedMessage { + typedef const word* Reader; +}; + +template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; + +template <> +struct PointerHelpers { + // Reads an AnyPointer 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(PointerReader reader) { + return reader.getUnchecked(); + } +}; + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_POINTER_HELPERS_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/pretty-print.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/pretty-print.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,47 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_PRETTY_PRINT_H_ +#define CAPNP_PRETTY_PRINT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "dynamic.h" +#include + +namespace capnp { + +kj::StringTree prettyPrint(DynamicStruct::Reader value); +kj::StringTree prettyPrint(DynamicStruct::Builder value); +kj::StringTree prettyPrint(DynamicList::Reader value); +kj::StringTree prettyPrint(DynamicList::Builder value); +// Print the given Cap'n Proto struct or list with nice indentation. Note that you can pass any +// struct or list reader or builder type to this method, since they can be implicitly converted +// to one of the dynamic types. +// +// If you don't want indentation, just use the value's KJ stringifier (e.g. pass it to kj::str(), +// any of the KJ debug macros, etc.). + +} // namespace capnp + +#endif // PRETTY_PRINT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/raw-schema.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/raw-schema.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,242 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RAW_SCHEMA_H_ +#define CAPNP_RAW_SCHEMA_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" // for uint and friends + +#if _MSC_VER +#include +#endif + +namespace capnp { +namespace _ { // private + +struct RawSchema; + +struct RawBrandedSchema { + // Represents a combination of a schema and bindings for its generic parameters. + // + // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for + // every _instance_ of a generic type -- or, at least, every instance that is actually used. For + // generated-code types, we use template magic to initialize these. + + const RawSchema* generic; + // Generic type which we're branding. + + struct Binding { + uint8_t which; // Numeric value of one of schema::Type::Which. + + bool isImplicitParameter; + // For AnyPointer, true if it's an implicit method parameter. + + uint16_t listDepth; // Number of times to wrap the base type in List(). + + uint16_t paramIndex; + // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter + // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric + // value of one of schema::Type::AnyPointer::Unconstrained::Which. + + union { + const RawBrandedSchema* schema; // for struct, enum, interface + uint64_t scopeId; // for AnyPointer, if it's a type parameter + }; + + Binding() = default; + inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) + : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0), + schema(schema) {} + inline constexpr Binding(uint8_t which, uint16_t listDepth, + uint64_t scopeId, uint16_t paramIndex) + : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex), + scopeId(scopeId) {} + inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex) + : which(which), isImplicitParameter(true), listDepth(listDepth), + paramIndex(implicitParamIndex), scopeId(0) {} + }; + + struct Scope { + uint64_t typeId; + // Type ID whose parameters are being bound. + + const Binding* bindings; + uint bindingCount; + // Bindings for those parameters. + + bool isUnbound; + // This scope is unbound, in the sense of SchemaLoader::getUnbound(). + }; + + const Scope* scopes; + // Array of enclosing scopes for which generic variables have been bound, sorted by type ID. + + struct Dependency { + uint location; + const RawBrandedSchema* schema; + }; + + const Dependency* dependencies; + // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that + // are branded are included in this map; if a dependency is missing, use its `defaultBrand`. + + uint32_t scopeCount; + uint32_t dependencyCount; + + enum class DepKind { + // Component of a Dependency::location. Specifies what sort of dependency this is. + + INVALID, + // Mostly defined to ensure that zero is not a valid location. + + FIELD, + // Binding needed for a field's type. The index is the field index (NOT ordinal!). + + METHOD_PARAMS, + // Bindings needed for a method's params type. The index is the method number. + + METHOD_RESULTS, + // Bindings needed for a method's results type. The index is the method ordinal. + + SUPERCLASS, + // Bindings needed for a superclass type. The index is the superclass's index in the + // "extends" list. + + CONST_TYPE + // Bindings needed for the type of a constant. The index is zero. + }; + + static inline uint makeDepLocation(DepKind kind, uint index) { + // Make a number representing the location of a particular dependency within its parent + // schema. + + return (static_cast(kind) << 24) | index; + } + + class Initializer { + public: + virtual void init(const RawBrandedSchema* generic) 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. + +#if __GNUC__ + const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); +#elif _MSC_VER + const Initializer* i = *static_cast(&lazyInitializer); + std::atomic_thread_fence(std::memory_order_acquire); +#else +#error "Platform not supported" +#endif + if (i != nullptr) i->init(this); + } + + inline bool isUnbound() const; + // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case + // binding lookups need to be handled specially. +}; + +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(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. + + const uint16_t* 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 uint16_t* membersByDiscriminant; + // List of all member indexes ordered by discriminant value. Those which don't have a + // discriminant value are listed at the end, in order by ordinal. + + 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. + +#if __GNUC__ + const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); +#elif _MSC_VER + const Initializer* i = *static_cast(&lazyInitializer); + std::atomic_thread_fence(std::memory_order_acquire); +#else +#error "Platform not supported" +#endif + if (i != nullptr) i->init(this); + } + + RawBrandedSchema defaultBrand; + // Specifies the brand to use for this schema if no generic parameters have been bound to + // anything. Generally, in the default brand, all generic parameters are treated as if they were + // bound to `AnyPointer`. +}; + +inline bool RawBrandedSchema::isUnbound() const { + // The unbound schema is the only one that has no scopes but is not the default schema. + return scopeCount == 0 && this != &generic->defaultBrand; +} + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_RAW_SCHEMA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-prelude.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-prelude.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,130 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains a bunch of internal declarations that must appear before rpc.h can start. +// We don't define these directly in rpc.h because it makes the file hard to read. + +#ifndef CAPNP_RPC_PRELUDE_H_ +#define CAPNP_RPC_PRELUDE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "capability.h" +#include "persistent.capnp.h" + +namespace capnp { + +class OutgoingRpcMessage; +class IncomingRpcMessage; + +template +class RpcSystem; + +namespace _ { // private + +class VatNetworkBase { + // Non-template version of VatNetwork. Ignore this class; see VatNetwork in rpc.h. + +public: + class Connection; + + struct ConnectionAndProvisionId { + kj::Own connection; + kj::Own firstMessage; + Orphan provisionId; + }; + + class Connection { + public: + virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) = 0; + virtual kj::Promise>> receiveIncomingMessage() = 0; + virtual kj::Promise shutdown() = 0; + virtual AnyStruct::Reader baseGetPeerVatId() = 0; + }; + virtual kj::Maybe> baseConnect(AnyStruct::Reader vatId) = 0; + virtual kj::Promise> baseAccept() = 0; +}; + +class SturdyRefRestorerBase { +public: + virtual Capability::Client baseRestore(AnyPointer::Reader ref) = 0; +}; + +class BootstrapFactoryBase { + // Non-template version of BootstrapFactory. Ignore this class; see BootstrapFactory in rpc.h. +public: + virtual Capability::Client baseCreateFor(AnyStruct::Reader clientId) = 0; +}; + +class RpcSystemBase { + // Non-template version of RpcSystem. Ignore this class; see RpcSystem in rpc.h. + +public: + RpcSystemBase(VatNetworkBase& network, kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway); + RpcSystemBase(VatNetworkBase& network, BootstrapFactoryBase& bootstrapFactory, + kj::Maybe::Client> gateway); + RpcSystemBase(VatNetworkBase& network, SturdyRefRestorerBase& restorer); + RpcSystemBase(RpcSystemBase&& other) noexcept; + ~RpcSystemBase() noexcept(false); + +private: + class Impl; + kj::Own impl; + + Capability::Client baseBootstrap(AnyStruct::Reader vatId); + Capability::Client baseRestore(AnyStruct::Reader vatId, AnyPointer::Reader objectId); + void baseSetFlowLimit(size_t words); + + template + friend class capnp::RpcSystem; +}; + +template struct InternalRefFromRealmGateway_; +template +struct InternalRefFromRealmGateway_> { + typedef InternalRef Type; +}; +template +using InternalRefFromRealmGateway = typename InternalRefFromRealmGateway_::Type; +template +using InternalRefFromRealmGatewayClient = InternalRefFromRealmGateway; + +template struct ExternalRefFromRealmGateway_; +template +struct ExternalRefFromRealmGateway_> { + typedef ExternalRef Type; +}; +template +using ExternalRefFromRealmGateway = typename ExternalRefFromRealmGateway_::Type; +template +using ExternalRefFromRealmGatewayClient = ExternalRefFromRealmGateway; + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_RPC_PRELUDE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1261 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "rpc.h" +#include "test-util.h" +#include "schema.h" +#include "serialize.h" +#include +#include +#include +#include +#include +#include + +// TODO(cleanup): Auto-generate stringification functions for union discriminants. +namespace capnp { +namespace rpc { +inline kj::String KJ_STRINGIFY(Message::Which which) { + return kj::str(static_cast(which)); +} +} // namespace rpc +} // namespace capnp + +namespace capnp { +namespace _ { // private +namespace { + +class RpcDumper { + // Class which stringifies RPC messages for debugging purposes, including decoding params and + // results based on the call's interface and method IDs and extracting cap descriptors. + // + // TODO(cleanup): Clean this code up and move it to someplace reusable, so it can be used as + // a packet inspector / debugging tool for Cap'n Proto network traffic. + +public: + void addSchema(InterfaceSchema schema) { + schemas[schema.getProto().getId()] = schema; + } + + enum Sender { + CLIENT, + SERVER + }; + + kj::String dump(rpc::Message::Reader message, Sender sender) { + const char* senderName = sender == CLIENT ? "client" : "server"; + + switch (message.which()) { + case rpc::Message::CALL: { + auto call = message.getCall(); + auto iter = schemas.find(call.getInterfaceId()); + if (iter == schemas.end()) { + break; + } + InterfaceSchema schema = iter->second; + auto methods = schema.getMethods(); + if (call.getMethodId() >= methods.size()) { + break; + } + InterfaceSchema::Method method = methods[call.getMethodId()]; + + auto schemaProto = schema.getProto(); + auto interfaceName = + schemaProto.getDisplayName().slice(schemaProto.getDisplayNamePrefixLength()); + + auto methodProto = method.getProto(); + auto paramType = method.getParamType(); + auto resultType = method.getResultType(); + + if (call.getSendResultsTo().isCaller()) { + returnTypes[std::make_pair(sender, call.getQuestionId())] = resultType; + } + + auto payload = call.getParams(); + auto params = kj::str(payload.getContent().getAs(paramType)); + + auto sendResultsTo = call.getSendResultsTo(); + + return kj::str(senderName, "(", call.getQuestionId(), "): call ", + call.getTarget(), " <- ", interfaceName, ".", + methodProto.getName(), params, + " caps:[", kj::strArray(payload.getCapTable(), ", "), "]", + sendResultsTo.isCaller() ? kj::str() + : kj::str(" sendResultsTo:", sendResultsTo)); + } + + case rpc::Message::RETURN: { + auto ret = message.getReturn(); + + auto iter = returnTypes.find( + std::make_pair(sender == CLIENT ? SERVER : CLIENT, ret.getAnswerId())); + if (iter == returnTypes.end()) { + break; + } + + auto schema = iter->second; + returnTypes.erase(iter); + if (ret.which() != rpc::Return::RESULTS) { + // Oops, no results returned. We don't check this earlier because we want to make sure + // returnTypes.erase() gets a chance to happen. + break; + } + + auto payload = ret.getResults(); + + if (schema.getProto().isStruct()) { + auto results = kj::str(payload.getContent().getAs(schema.asStruct())); + + return kj::str(senderName, "(", ret.getAnswerId(), "): return ", results, + " caps:[", kj::strArray(payload.getCapTable(), ", "), "]"); + } else if (schema.getProto().isInterface()) { + payload.getContent().getAs(schema.asInterface()); + return kj::str(senderName, "(", ret.getAnswerId(), "): return cap ", + kj::strArray(payload.getCapTable(), ", ")); + } else { + break; + } + } + + case rpc::Message::BOOTSTRAP: { + auto restore = message.getBootstrap(); + + returnTypes[std::make_pair(sender, restore.getQuestionId())] = InterfaceSchema(); + + return kj::str(senderName, "(", restore.getQuestionId(), "): bootstrap ", + restore.getDeprecatedObjectId().getAs()); + } + + default: + break; + } + + return kj::str(senderName, ": ", message); + } + +private: + std::map schemas; + std::map, Schema> returnTypes; +}; + +// ======================================================================================= + +class TestNetworkAdapter; + +class TestNetwork { +public: + TestNetwork() { + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + dumper.addSchema(Schema::from()); + } + ~TestNetwork() noexcept(false); + + TestNetworkAdapter& add(kj::StringPtr name); + + kj::Maybe find(kj::StringPtr name) { + auto iter = map.find(name); + if (iter == map.end()) { + return nullptr; + } else { + return *iter->second; + } + } + + RpcDumper dumper; + +private: + std::map> map; +}; + +typedef VatNetwork< + test::TestSturdyRefHostId, test::TestProvisionId, test::TestRecipientId, + test::TestThirdPartyCapId, test::TestJoinResult> TestNetworkAdapterBase; + +class TestNetworkAdapter final: public TestNetworkAdapterBase { +public: + TestNetworkAdapter(TestNetwork& network): network(network) {} + + ~TestNetworkAdapter() { + kj::Exception exception = KJ_EXCEPTION(FAILED, "Network was destroyed."); + for (auto& entry: connections) { + entry.second->disconnect(kj::cp(exception)); + } + } + + uint getSentCount() { return sent; } + uint getReceivedCount() { return received; } + + typedef TestNetworkAdapterBase::Connection Connection; + + class ConnectionImpl final + : public Connection, public kj::Refcounted, public kj::TaskSet::ErrorHandler { + public: + ConnectionImpl(TestNetworkAdapter& network, RpcDumper::Sender sender) + : network(network), sender(sender), tasks(kj::heap(*this)) {} + + void attach(ConnectionImpl& other) { + KJ_REQUIRE(partner == nullptr); + KJ_REQUIRE(other.partner == nullptr); + partner = other; + other.partner = *this; + } + + void disconnect(kj::Exception&& exception) { + while (!fulfillers.empty()) { + fulfillers.front()->reject(kj::cp(exception)); + fulfillers.pop(); + } + + networkException = kj::mv(exception); + + tasks = nullptr; + } + + class IncomingRpcMessageImpl final: public IncomingRpcMessage, public kj::Refcounted { + public: + IncomingRpcMessageImpl(kj::Array data) + : data(kj::mv(data)), + message(this->data) {} + + AnyPointer::Reader getBody() override { + return message.getRoot(); + } + + kj::Array data; + FlatArrayMessageReader message; + }; + + class OutgoingRpcMessageImpl final: public OutgoingRpcMessage { + public: + OutgoingRpcMessageImpl(ConnectionImpl& connection, uint firstSegmentWordSize) + : connection(connection), + message(firstSegmentWordSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS + : firstSegmentWordSize) {} + + AnyPointer::Builder getBody() override { + return message.getRoot(); + } + + void send() override { + if (connection.networkException != nullptr) { + return; + } + + ++connection.network.sent; + + // Uncomment to get a debug dump. +// kj::String msg = connection.network.network.dumper.dump( +// message.getRoot(), connection.sender); +// KJ_ DBG(msg); + + auto incomingMessage = kj::heap(messageToFlatArray(message)); + + auto connectionPtr = &connection; + connection.tasks->add(kj::evalLater(kj::mvCapture(incomingMessage, + [connectionPtr](kj::Own&& message) { + KJ_IF_MAYBE(p, connectionPtr->partner) { + if (p->fulfillers.empty()) { + p->messages.push(kj::mv(message)); + } else { + ++p->network.received; + p->fulfillers.front()->fulfill( + kj::Own(kj::mv(message))); + p->fulfillers.pop(); + } + } + }))); + } + + private: + ConnectionImpl& connection; + MallocMessageBuilder message; + }; + + test::TestSturdyRefHostId::Reader getPeerVatId() override { + // Not actually implemented for the purpose of this test. + return test::TestSturdyRefHostId::Reader(); + } + + kj::Own newOutgoingMessage(uint firstSegmentWordSize) override { + return kj::heap(*this, firstSegmentWordSize); + } + kj::Promise>> receiveIncomingMessage() override { + KJ_IF_MAYBE(e, networkException) { + return kj::cp(*e); + } + + if (messages.empty()) { + KJ_IF_MAYBE(f, fulfillOnEnd) { + f->get()->fulfill(); + return kj::Maybe>(nullptr); + } else { + auto paf = kj::newPromiseAndFulfiller>>(); + fulfillers.push(kj::mv(paf.fulfiller)); + return kj::mv(paf.promise); + } + } else { + ++network.received; + auto result = kj::mv(messages.front()); + messages.pop(); + return kj::Maybe>(kj::mv(result)); + } + } + kj::Promise shutdown() override { + KJ_IF_MAYBE(p, partner) { + auto paf = kj::newPromiseAndFulfiller(); + p->fulfillOnEnd = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); + } else { + return kj::READY_NOW; + } + } + + void taskFailed(kj::Exception&& exception) override { + ADD_FAILURE() << kj::str(exception).cStr(); + } + + private: + TestNetworkAdapter& network; + RpcDumper::Sender sender KJ_UNUSED_MEMBER; + kj::Maybe partner; + + kj::Maybe networkException; + + std::queue>>>> fulfillers; + std::queue> messages; + kj::Maybe>> fulfillOnEnd; + + kj::Own tasks; + }; + + kj::Maybe> connect(test::TestSturdyRefHostId::Reader hostId) override { + TestNetworkAdapter& dst = KJ_REQUIRE_NONNULL(network.find(hostId.getHost())); + + auto iter = connections.find(&dst); + if (iter == connections.end()) { + auto local = kj::refcounted(*this, RpcDumper::CLIENT); + auto remote = kj::refcounted(dst, RpcDumper::SERVER); + local->attach(*remote); + + connections[&dst] = kj::addRef(*local); + dst.connections[this] = kj::addRef(*remote); + + if (dst.fulfillerQueue.empty()) { + dst.connectionQueue.push(kj::mv(remote)); + } else { + dst.fulfillerQueue.front()->fulfill(kj::mv(remote)); + dst.fulfillerQueue.pop(); + } + + return kj::Own(kj::mv(local)); + } else { + return kj::Own(kj::addRef(*iter->second)); + } + } + + kj::Promise> accept() override { + if (connectionQueue.empty()) { + auto paf = kj::newPromiseAndFulfiller>(); + fulfillerQueue.push(kj::mv(paf.fulfiller)); + return kj::mv(paf.promise); + } else { + auto result = kj::mv(connectionQueue.front()); + connectionQueue.pop(); + return kj::mv(result); + } + } + +private: + TestNetwork& network; + uint sent = 0; + uint received = 0; + + std::map> connections; + std::queue>>> fulfillerQueue; + std::queue> connectionQueue; +}; + +TestNetwork::~TestNetwork() noexcept(false) {} + +TestNetworkAdapter& TestNetwork::add(kj::StringPtr name) { + return *(map[name] = kj::heap(*this)); +} + +// ======================================================================================= + +class TestRestorer final: public SturdyRefRestorer { +public: + int callCount = 0; + int handleCount = 0; + + Capability::Client restore(test::TestSturdyRefObjectId::Reader objectId) override { + switch (objectId.getTag()) { + case test::TestSturdyRefObjectId::Tag::TEST_INTERFACE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_EXTENDS: + return Capability::Client(newBrokenCap("No TestExtends implemented.")); + case test::TestSturdyRefObjectId::Tag::TEST_PIPELINE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_TAIL_CALLEE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_TAIL_CALLER: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF: + return kj::heap(callCount, handleCount); + } + KJ_UNREACHABLE; + } +}; + +struct TestContext { + kj::EventLoop loop; + kj::WaitScope waitScope; + TestNetwork network; + TestRestorer restorer; + TestNetworkAdapter& clientNetwork; + TestNetworkAdapter& serverNetwork; + RpcSystem rpcClient; + RpcSystem rpcServer; + + TestContext() + : waitScope(loop), + clientNetwork(network.add("client")), + serverNetwork(network.add("server")), + rpcClient(makeRpcClient(clientNetwork)), + rpcServer(makeRpcServer(serverNetwork, restorer)) {} + TestContext(Capability::Client bootstrap, + RealmGateway::Client gateway) + : waitScope(loop), + clientNetwork(network.add("client")), + serverNetwork(network.add("server")), + rpcClient(makeRpcClient(clientNetwork, gateway)), + rpcServer(makeRpcServer(serverNetwork, bootstrap)) {} + TestContext(Capability::Client bootstrap, + RealmGateway::Client gateway, + bool) + : waitScope(loop), + clientNetwork(network.add("client")), + serverNetwork(network.add("server")), + rpcClient(makeRpcClient(clientNetwork)), + rpcServer(makeRpcServer(serverNetwork, bootstrap, gateway)) {} + + Capability::Client connect(test::TestSturdyRefObjectId::Tag tag) { + MallocMessageBuilder refMessage(128); + auto ref = refMessage.initRoot(); + auto hostId = ref.initHostId(); + hostId.setHost("server"); + ref.getObjectId().initAs().setTag(tag); + + return rpcClient.restore(hostId, ref.getObjectId()); + } +}; + +TEST(Rpc, Basic) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_INTERFACE) + .castAs(); + + auto request1 = client.fooRequest(); + request1.setI(123); + request1.setJ(true); + auto promise1 = request1.send(); + + // We used to call bar() after baz(), hence the numbering, but this masked the case where the + // RPC system actually disconnected on bar() (thus returning an exception, which we decided + // was expected). + bool barFailed = false; + auto request3 = client.barRequest(); + auto promise3 = request3.send().then( + [](Response&& response) { + ADD_FAILURE() << "Expected bar() call to fail."; + }, [&](kj::Exception&& e) { + barFailed = true; + }); + + auto request2 = client.bazRequest(); + initTestMessage(request2.initS()); + auto promise2 = request2.send(); + + EXPECT_EQ(0, context.restorer.callCount); + + auto response1 = promise1.wait(context.waitScope); + + EXPECT_EQ("foo", response1.getX()); + + auto response2 = promise2.wait(context.waitScope); + + promise3.wait(context.waitScope); + + EXPECT_EQ(2, context.restorer.callCount); + EXPECT_TRUE(barFailed); +} + +TEST(Rpc, Pipelining) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_PIPELINE) + .castAs(); + + int chainedCallCount = 0; + + auto request = client.getCapRequest(); + request.setN(234); + request.setInCap(kj::heap(chainedCallCount)); + + auto promise = request.send(); + + auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); + pipelineRequest.setI(321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = promise.getOutBox().getCap().castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, context.restorer.callCount); + EXPECT_EQ(0, chainedCallCount); + + auto response = pipelinePromise.wait(context.waitScope); + EXPECT_EQ("bar", response.getX()); + + auto response2 = pipelinePromise2.wait(context.waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, context.restorer.callCount); + EXPECT_EQ(1, chainedCallCount); +} + +TEST(Rpc, Release) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto handle1 = client.getHandleRequest().send().wait(context.waitScope).getHandle(); + auto promise = client.getHandleRequest().send(); + auto handle2 = promise.wait(context.waitScope).getHandle(); + + EXPECT_EQ(2, context.restorer.handleCount); + + handle1 = nullptr; + + for (uint i = 0; i < 16; i++) kj::evalLater([]() {}).wait(context.waitScope); + EXPECT_EQ(1, context.restorer.handleCount); + + handle2 = nullptr; + + for (uint i = 0; i < 16; i++) kj::evalLater([]() {}).wait(context.waitScope); + EXPECT_EQ(1, context.restorer.handleCount); + + promise = nullptr; + + for (uint i = 0; i < 16; i++) kj::evalLater([]() {}).wait(context.waitScope); + EXPECT_EQ(0, context.restorer.handleCount); +} + +TEST(Rpc, ReleaseOnCancel) { + // At one time, there was a bug where if a Return contained capabilities, but the client had + // canceled the request and already send a Finish (which presumably didn't reach the server before + // the Return), then we'd leak those caps. Test for that. + + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + client.whenResolved().wait(context.waitScope); + + { + auto promise = client.getHandleRequest().send(); + + // If the server receives cancellation too early, it won't even return a capability in the + // results, it will just return "canceled". We want to emulate the case where the return message + // and the cancel (finish) message cross paths. It turns out that exactly two evalLater()s get + // us there. + // + // TODO(cleanup): This is fragile, but I'm not sure how else to write it without a ton + // of scaffolding. + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + } + + for (uint i = 0; i < 16; i++) kj::evalLater([]() {}).wait(context.waitScope); + EXPECT_EQ(0, context.restorer.handleCount); +} + +TEST(Rpc, TailCall) { + TestContext context; + + auto caller = context.connect(test::TestSturdyRefObjectId::Tag::TEST_TAIL_CALLER) + .castAs(); + + int calleeCallCount = 0; + + test::TestTailCallee::Client callee(kj::heap(calleeCallCount)); + + auto request = caller.fooRequest(); + request.setI(456); + request.setCallee(callee); + + auto promise = request.send(); + + auto dependentCall0 = promise.getC().getCallSequenceRequest().send(); + + auto response = promise.wait(context.waitScope); + EXPECT_EQ(456, response.getI()); + EXPECT_EQ("from TestTailCaller", response.getT()); + + auto dependentCall1 = promise.getC().getCallSequenceRequest().send(); + + auto dependentCall2 = response.getC().getCallSequenceRequest().send(); + + EXPECT_EQ(0, dependentCall0.wait(context.waitScope).getN()); + EXPECT_EQ(1, dependentCall1.wait(context.waitScope).getN()); + EXPECT_EQ(2, dependentCall2.wait(context.waitScope).getN()); + + EXPECT_EQ(1, calleeCallCount); + EXPECT_EQ(1, context.restorer.callCount); +} + +TEST(Rpc, Cancelation) { + // Tests allowCancellation(). + + TestContext context; + + auto paf = kj::newPromiseAndFulfiller(); + bool destroyed = false; + auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + kj::Promise promise = nullptr; + + bool returned = false; + { + auto request = client.expectCancelRequest(); + request.setCap(kj::heap(kj::mv(paf.fulfiller))); + promise = request.send().then( + [&](Response&& response) { + returned = true; + }).eagerlyEvaluate(nullptr); + } + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + + // We can detect that the method was canceled because it will drop the cap. + EXPECT_FALSE(destroyed); + EXPECT_FALSE(returned); + + promise = nullptr; // request cancellation + destructionPromise.wait(context.waitScope); + + EXPECT_TRUE(destroyed); + EXPECT_FALSE(returned); +} + +TEST(Rpc, PromiseResolve) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + int chainedCallCount = 0; + + auto request = client.callFooRequest(); + auto request2 = client.callFooWhenResolvedRequest(); + + auto paf = kj::newPromiseAndFulfiller(); + + { + auto fork = paf.promise.fork(); + request.setCap(fork.addBranch()); + request2.setCap(fork.addBranch()); + } + + auto promise = request.send(); + auto promise2 = request2.send(); + + // Make sure getCap() has been called on the server side by sending another call and waiting + // for it. + EXPECT_EQ(2, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + EXPECT_EQ(3, context.restorer.callCount); + + // OK, now fulfill the local promise. + paf.fulfiller->fulfill(kj::heap(chainedCallCount)); + + // We should now be able to wait for getCap() to finish. + EXPECT_EQ("bar", promise.wait(context.waitScope).getS()); + EXPECT_EQ("bar", promise2.wait(context.waitScope).getS()); + + EXPECT_EQ(3, context.restorer.callCount); + EXPECT_EQ(2, chainedCallCount); +} + +TEST(Rpc, RetainAndRelease) { + TestContext context; + + auto paf = kj::newPromiseAndFulfiller(); + bool destroyed = false; + auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); + + { + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + { + auto request = client.holdRequest(); + request.setCap(kj::heap(kj::mv(paf.fulfiller))); + request.send().wait(context.waitScope); + } + + // Do some other call to add a round trip. + EXPECT_EQ(1, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + + // Shouldn't be destroyed because it's being held by the server. + EXPECT_FALSE(destroyed); + + // We can ask it to call the held capability. + EXPECT_EQ("bar", client.callHeldRequest().send().wait(context.waitScope).getS()); + + { + // We can get the cap back from it. + auto capCopy = client.getHeldRequest().send().wait(context.waitScope).getCap(); + + { + // And call it, without any network communications. + uint oldSentCount = context.clientNetwork.getSentCount(); + auto request = capCopy.fooRequest(); + request.setI(123); + request.setJ(true); + EXPECT_EQ("foo", request.send().wait(context.waitScope).getX()); + EXPECT_EQ(oldSentCount, context.clientNetwork.getSentCount()); + } + + { + // We can send another copy of the same cap to another method, and it works. + auto request = client.callFooRequest(); + request.setCap(capCopy); + EXPECT_EQ("bar", request.send().wait(context.waitScope).getS()); + } + } + + // Give some time to settle. + EXPECT_EQ(5, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + EXPECT_EQ(6, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + EXPECT_EQ(7, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + + // Can't be destroyed, we haven't released it. + EXPECT_FALSE(destroyed); + } + + // We released our client, which should cause the server to be released, which in turn will + // release the cap pointing back to us. + destructionPromise.wait(context.waitScope); + EXPECT_TRUE(destroyed); +} + +TEST(Rpc, Cancel) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto paf = kj::newPromiseAndFulfiller(); + bool destroyed = false; + auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); + + { + auto request = client.neverReturnRequest(); + request.setCap(kj::heap(kj::mv(paf.fulfiller))); + + { + auto responsePromise = request.send(); + + // Allow some time to settle. + EXPECT_EQ(1, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + EXPECT_EQ(2, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + + // The cap shouldn't have been destroyed yet because the call never returned. + EXPECT_FALSE(destroyed); + } + } + + // Now the cap should be released. + destructionPromise.wait(context.waitScope); + EXPECT_TRUE(destroyed); +} + +TEST(Rpc, SendTwice) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto paf = kj::newPromiseAndFulfiller(); + bool destroyed = false; + auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); + + auto cap = test::TestInterface::Client(kj::heap(kj::mv(paf.fulfiller))); + + { + auto request = client.callFooRequest(); + request.setCap(cap); + + EXPECT_EQ("bar", request.send().wait(context.waitScope).getS()); + } + + // Allow some time for the server to release `cap`. + EXPECT_EQ(1, client.getCallSequenceRequest().send().wait(context.waitScope).getN()); + + { + // More requests with the same cap. + auto request = client.callFooRequest(); + auto request2 = client.callFooRequest(); + request.setCap(cap); + request2.setCap(kj::mv(cap)); + + auto promise = request.send(); + auto promise2 = request2.send(); + + EXPECT_EQ("bar", promise.wait(context.waitScope).getS()); + EXPECT_EQ("bar", promise2.wait(context.waitScope).getS()); + } + + // Now the cap should be released. + destructionPromise.wait(context.waitScope); + EXPECT_TRUE(destroyed); +} + +RemotePromise getCallSequence( + test::TestCallOrder::Client& client, uint expected) { + auto req = client.getCallSequenceRequest(); + req.setExpected(expected); + return req.send(); +} + +TEST(Rpc, Embargo) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto cap = test::TestCallOrder::Client(kj::heap()); + + auto earlyCall = client.getCallSequenceRequest().send(); + + auto echoRequest = client.echoRequest(); + echoRequest.setCap(cap); + auto echo = echoRequest.send(); + + auto pipeline = echo.getCap(); + + auto call0 = getCallSequence(pipeline, 0); + auto call1 = getCallSequence(pipeline, 1); + + earlyCall.wait(context.waitScope); + + auto call2 = getCallSequence(pipeline, 2); + + auto resolved = echo.wait(context.waitScope).getCap(); + + auto call3 = getCallSequence(pipeline, 3); + auto call4 = getCallSequence(pipeline, 4); + auto call5 = getCallSequence(pipeline, 5); + + EXPECT_EQ(0, call0.wait(context.waitScope).getN()); + EXPECT_EQ(1, call1.wait(context.waitScope).getN()); + EXPECT_EQ(2, call2.wait(context.waitScope).getN()); + EXPECT_EQ(3, call3.wait(context.waitScope).getN()); + EXPECT_EQ(4, call4.wait(context.waitScope).getN()); + EXPECT_EQ(5, call5.wait(context.waitScope).getN()); +} + +template +void expectPromiseThrows(kj::Promise&& promise, kj::WaitScope& waitScope) { + EXPECT_TRUE(promise.then([](T&&) { return false; }, [](kj::Exception&&) { return true; }) + .wait(waitScope)); +} + +template <> +void expectPromiseThrows(kj::Promise&& promise, kj::WaitScope& waitScope) { + EXPECT_TRUE(promise.then([]() { return false; }, [](kj::Exception&&) { return true; }) + .wait(waitScope)); +} + +TEST(Rpc, EmbargoError) { + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto paf = kj::newPromiseAndFulfiller(); + + auto cap = test::TestCallOrder::Client(kj::mv(paf.promise)); + + auto earlyCall = client.getCallSequenceRequest().send(); + + auto echoRequest = client.echoRequest(); + echoRequest.setCap(cap); + auto echo = echoRequest.send(); + + auto pipeline = echo.getCap(); + + auto call0 = getCallSequence(pipeline, 0); + auto call1 = getCallSequence(pipeline, 1); + + earlyCall.wait(context.waitScope); + + auto call2 = getCallSequence(pipeline, 2); + + auto resolved = echo.wait(context.waitScope).getCap(); + + auto call3 = getCallSequence(pipeline, 3); + auto call4 = getCallSequence(pipeline, 4); + auto call5 = getCallSequence(pipeline, 5); + + paf.fulfiller->rejectIfThrows([]() { KJ_FAIL_ASSERT("foo") { break; } }); + + expectPromiseThrows(kj::mv(call0), context.waitScope); + expectPromiseThrows(kj::mv(call1), context.waitScope); + expectPromiseThrows(kj::mv(call2), context.waitScope); + expectPromiseThrows(kj::mv(call3), context.waitScope); + expectPromiseThrows(kj::mv(call4), context.waitScope); + expectPromiseThrows(kj::mv(call5), context.waitScope); + + // Verify that we're still connected (there were no protocol errors). + getCallSequence(client, 1).wait(context.waitScope); +} + +TEST(Rpc, EmbargoNull) { + // Set up a situation where we pipeline on a capability that ends up coming back null. This + // should NOT cause a Disembargo to be sent, but due to a bug in earlier versions of Cap'n Proto, + // a Disembargo was indeed sent to the null capability, which caused the server to disconnect + // due to protocol error. + + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + + auto promise = client.getNullRequest().send(); + + auto cap = promise.getNullCap(); + + auto call0 = cap.getCallSequenceRequest().send(); + + promise.wait(context.waitScope); + + auto call1 = cap.getCallSequenceRequest().send(); + + expectPromiseThrows(kj::mv(call0), context.waitScope); + expectPromiseThrows(kj::mv(call1), context.waitScope); + + // Verify that we're still connected (there were no protocol errors). + getCallSequence(client, 0).wait(context.waitScope); +} + +TEST(Rpc, CallBrokenPromise) { + // Tell the server to call back to a promise client, then resolve the promise to an error. + + TestContext context; + + auto client = context.connect(test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF) + .castAs(); + auto paf = kj::newPromiseAndFulfiller(); + + { + auto req = client.holdRequest(); + req.setCap(kj::mv(paf.promise)); + req.send().wait(context.waitScope); + } + + bool returned = false; + auto req = client.callHeldRequest().send() + .then([&](capnp::Response&&) { + returned = true; + }, [&](kj::Exception&& e) { + returned = true; + kj::throwRecoverableException(kj::mv(e)); + }).eagerlyEvaluate(nullptr); + + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + + EXPECT_FALSE(returned); + + paf.fulfiller->rejectIfThrows([]() { KJ_FAIL_ASSERT("foo") { break; } }); + + expectPromiseThrows(kj::mv(req), context.waitScope); + EXPECT_TRUE(returned); + + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + kj::evalLater([]() {}).wait(context.waitScope); + + // Verify that we're still connected (there were no protocol errors). + getCallSequence(client, 1).wait(context.waitScope); +} + +TEST(Rpc, Abort) { + // Verify that aborts are received. + + TestContext context; + + MallocMessageBuilder refMessage(128); + auto hostId = refMessage.initRoot(); + hostId.setHost("server"); + + auto conn = KJ_ASSERT_NONNULL(context.clientNetwork.connect(hostId)); + + { + // Send an invalid message (Return to non-existent question). + auto msg = conn->newOutgoingMessage(128); + auto body = msg->getBody().initAs().initReturn(); + body.setAnswerId(1234); + body.setCanceled(); + msg->send(); + } + + auto reply = KJ_ASSERT_NONNULL(conn->receiveIncomingMessage().wait(context.waitScope)); + EXPECT_EQ(rpc::Message::ABORT, reply->getBody().getAs().which()); + + EXPECT_TRUE(conn->receiveIncomingMessage().wait(context.waitScope) == nullptr); +} + +// ======================================================================================= + +typedef RealmGateway TestRealmGateway; + +class TestGateway final: public TestRealmGateway::Server { +public: + kj::Promise import(ImportContext context) override { + auto cap = context.getParams().getCap(); + context.releaseParams(); + return cap.saveRequest().send() + .then([KJ_CPCAP(context)](Response::SaveResults> response) mutable { + context.getResults().initSturdyRef().getObjectId().setAs( + kj::str("imported-", response.getSturdyRef())); + }); + } + + kj::Promise export_(ExportContext context) override { + auto cap = context.getParams().getCap(); + context.releaseParams(); + return cap.saveRequest().send() + .then([KJ_CPCAP(context)] + (Response::SaveResults> response) mutable { + context.getResults().setSturdyRef(kj::str("exported-", + response.getSturdyRef().getObjectId().getAs())); + }); + } +}; + +class TestPersistent final: public Persistent::Server { +public: + TestPersistent(kj::StringPtr name): name(name) {} + + kj::Promise save(SaveContext context) override { + context.initResults().initSturdyRef().getObjectId().setAs(name); + return kj::READY_NOW; + } + +private: + kj::StringPtr name; +}; + +class TestPersistentText final: public Persistent::Server { +public: + TestPersistentText(kj::StringPtr name): name(name) {} + + kj::Promise save(SaveContext context) override { + context.initResults().setSturdyRef(name); + return kj::READY_NOW; + } + +private: + kj::StringPtr name; +}; + +TEST(Rpc, RealmGatewayImport) { + TestRealmGateway::Client gateway = kj::heap(); + Persistent::Client bootstrap = kj::heap("foo"); + + MallocMessageBuilder hostIdBuilder; + auto hostId = hostIdBuilder.getRoot(); + hostId.setHost("server"); + + TestContext context(bootstrap, gateway); + auto client = context.rpcClient.bootstrap(hostId).castAs>(); + + auto response = client.saveRequest().send().wait(context.waitScope); + + EXPECT_EQ("imported-foo", response.getSturdyRef().getObjectId().getAs()); +} + +TEST(Rpc, RealmGatewayExport) { + TestRealmGateway::Client gateway = kj::heap(); + Persistent::Client bootstrap = kj::heap("foo"); + + MallocMessageBuilder hostIdBuilder; + auto hostId = hostIdBuilder.getRoot(); + hostId.setHost("server"); + + TestContext context(bootstrap, gateway, true); + auto client = context.rpcClient.bootstrap(hostId).castAs>(); + + auto response = client.saveRequest().send().wait(context.waitScope); + + EXPECT_EQ("exported-foo", response.getSturdyRef()); +} + +TEST(Rpc, RealmGatewayImportExport) { + // Test that a save request which leaves the realm, bounces through a promise capability, and + // then comes back into the realm, does not actually get translated both ways. + + TestRealmGateway::Client gateway = kj::heap(); + Persistent::Client bootstrap = kj::heap("foo"); + + MallocMessageBuilder serverHostIdBuilder; + auto serverHostId = serverHostIdBuilder.getRoot(); + serverHostId.setHost("server"); + + MallocMessageBuilder clientHostIdBuilder; + auto clientHostId = clientHostIdBuilder.getRoot(); + clientHostId.setHost("client"); + + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + TestNetwork network; + TestRestorer restorer; + TestNetworkAdapter& clientNetwork = network.add("client"); + TestNetworkAdapter& serverNetwork = network.add("server"); + RpcSystem rpcClient = + makeRpcServer(clientNetwork, bootstrap, gateway); + auto paf = kj::newPromiseAndFulfiller(); + RpcSystem rpcServer = + makeRpcServer(serverNetwork, kj::mv(paf.promise)); + + auto client = rpcClient.bootstrap(serverHostId).castAs>(); + + bool responseReady = false; + auto responsePromise = client.saveRequest().send() + .then([&](Response::SaveResults>&& response) { + responseReady = true; + return kj::mv(response); + }).eagerlyEvaluate(nullptr); + + // Crank the event loop to give the message time to reach the server and block on the promise + // resolution. + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + + EXPECT_FALSE(responseReady); + + paf.fulfiller->fulfill(rpcServer.bootstrap(clientHostId)); + + auto response = responsePromise.wait(waitScope); + + // Should have the original value. If it went through export and re-import, though, then this + // will be "imported-exported-foo", which is wrong. + EXPECT_EQ("foo", response.getSturdyRef().getObjectId().getAs()); +} + +TEST(Rpc, RealmGatewayImportExport) { + // Test that a save request which enters the realm, bounces through a promise capability, and + // then goes back out of the realm, does not actually get translated both ways. + + TestRealmGateway::Client gateway = kj::heap(); + Persistent::Client bootstrap = kj::heap("foo"); + + MallocMessageBuilder serverHostIdBuilder; + auto serverHostId = serverHostIdBuilder.getRoot(); + serverHostId.setHost("server"); + + MallocMessageBuilder clientHostIdBuilder; + auto clientHostId = clientHostIdBuilder.getRoot(); + clientHostId.setHost("client"); + + kj::EventLoop loop; + kj::WaitScope waitScope(loop); + TestNetwork network; + TestRestorer restorer; + TestNetworkAdapter& clientNetwork = network.add("client"); + TestNetworkAdapter& serverNetwork = network.add("server"); + RpcSystem rpcClient = + makeRpcServer(clientNetwork, bootstrap); + auto paf = kj::newPromiseAndFulfiller(); + RpcSystem rpcServer = + makeRpcServer(serverNetwork, kj::mv(paf.promise), gateway); + + auto client = rpcClient.bootstrap(serverHostId).castAs>(); + + bool responseReady = false; + auto responsePromise = client.saveRequest().send() + .then([&](Response::SaveResults>&& response) { + responseReady = true; + return kj::mv(response); + }).eagerlyEvaluate(nullptr); + + // Crank the event loop to give the message time to reach the server and block on the promise + // resolution. + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + kj::evalLater([]() {}).wait(waitScope); + + EXPECT_FALSE(responseReady); + + paf.fulfiller->fulfill(rpcServer.bootstrap(clientHostId)); + + auto response = responsePromise.wait(waitScope); + + // Should have the original value. If it went through import and re-export, though, then this + // will be "exported-imported-foo", which is wrong. + EXPECT_EQ("foo", response.getSturdyRef()); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,422 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "rpc-twoparty.h" +#include "test-util.h" +#include +#include +#include +#include + +// TODO(cleanup): Auto-generate stringification functions for union discriminants. +namespace capnp { +namespace rpc { +inline kj::String KJ_STRINGIFY(Message::Which which) { + return kj::str(static_cast(which)); +} +} // namespace rpc +} // namespace capnp + +namespace capnp { +namespace _ { +namespace { + +class TestRestorer final: public SturdyRefRestorer { +public: + TestRestorer(int& callCount, int& handleCount) + : callCount(callCount), handleCount(handleCount) {} + + Capability::Client restore(test::TestSturdyRefObjectId::Reader objectId) override { + switch (objectId.getTag()) { + case test::TestSturdyRefObjectId::Tag::TEST_INTERFACE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_EXTENDS: + return Capability::Client(newBrokenCap("No TestExtends implemented.")); + case test::TestSturdyRefObjectId::Tag::TEST_PIPELINE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_TAIL_CALLEE: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_TAIL_CALLER: + return kj::heap(callCount); + case test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF: + return kj::heap(callCount, handleCount); + } + KJ_UNREACHABLE; + } + +private: + int& callCount; + int& handleCount; +}; + +kj::AsyncIoProvider::PipeThread runServer(kj::AsyncIoProvider& ioProvider, + int& callCount, int& handleCount) { + return ioProvider.newPipeThread( + [&callCount, &handleCount]( + kj::AsyncIoProvider& ioProvider, kj::AsyncIoStream& stream, kj::WaitScope& waitScope) { + TwoPartyVatNetwork network(stream, rpc::twoparty::Side::SERVER); + TestRestorer restorer(callCount, handleCount); + auto server = makeRpcServer(network, restorer); + network.onDisconnect().wait(waitScope); + }); +} + +Capability::Client getPersistentCap(RpcSystem& client, + rpc::twoparty::Side side, + test::TestSturdyRefObjectId::Tag tag) { + // Create the VatId. + MallocMessageBuilder hostIdMessage(8); + auto hostId = hostIdMessage.initRoot(); + hostId.setSide(side); + + // Create the SturdyRefObjectId. + MallocMessageBuilder objectIdMessage(8); + objectIdMessage.initRoot().setTag(tag); + + // Connect to the remote capability. + return client.restore(hostId, objectIdMessage.getRoot()); +} + +TEST(TwoPartyNetwork, Basic) { + auto ioContext = kj::setupAsyncIo(); + int callCount = 0; + int handleCount = 0; + + auto serverThread = runServer(*ioContext.provider, callCount, handleCount); + TwoPartyVatNetwork network(*serverThread.pipe, rpc::twoparty::Side::CLIENT); + auto rpcClient = makeRpcClient(network); + + // Request the particular capability from the server. + auto client = getPersistentCap(rpcClient, rpc::twoparty::Side::SERVER, + test::TestSturdyRefObjectId::Tag::TEST_INTERFACE).castAs(); + + // Use the capability. + auto request1 = client.fooRequest(); + request1.setI(123); + request1.setJ(true); + auto promise1 = request1.send(); + + auto request2 = client.bazRequest(); + initTestMessage(request2.initS()); + auto promise2 = request2.send(); + + bool barFailed = false; + auto request3 = client.barRequest(); + auto promise3 = request3.send().then( + [](Response&& response) { + ADD_FAILURE() << "Expected bar() call to fail."; + }, [&](kj::Exception&& e) { + barFailed = true; + }); + + EXPECT_EQ(0, callCount); + + auto response1 = promise1.wait(ioContext.waitScope); + + EXPECT_EQ("foo", response1.getX()); + + auto response2 = promise2.wait(ioContext.waitScope); + + promise3.wait(ioContext.waitScope); + + EXPECT_EQ(2, callCount); + EXPECT_TRUE(barFailed); +} + +TEST(TwoPartyNetwork, Pipelining) { + auto ioContext = kj::setupAsyncIo(); + int callCount = 0; + int handleCount = 0; + int reverseCallCount = 0; // Calls back from server to client. + + auto serverThread = runServer(*ioContext.provider, callCount, handleCount); + TwoPartyVatNetwork network(*serverThread.pipe, rpc::twoparty::Side::CLIENT); + auto rpcClient = makeRpcClient(network); + + bool disconnected = false; + kj::Promise disconnectPromise = network.onDisconnect().then([&]() { disconnected = true; }); + + { + // Request the particular capability from the server. + auto client = getPersistentCap(rpcClient, rpc::twoparty::Side::SERVER, + test::TestSturdyRefObjectId::Tag::TEST_PIPELINE).castAs(); + + { + // Use the capability. + auto request = client.getCapRequest(); + request.setN(234); + request.setInCap(kj::heap(reverseCallCount)); + + auto promise = request.send(); + + auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); + pipelineRequest.setI(321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = promise.getOutBox().getCap() + .castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + promise = nullptr; // Just to be annoying, drop the original promise. + + EXPECT_EQ(0, callCount); + EXPECT_EQ(0, reverseCallCount); + + auto response = pipelinePromise.wait(ioContext.waitScope); + EXPECT_EQ("bar", response.getX()); + + auto response2 = pipelinePromise2.wait(ioContext.waitScope); + checkTestMessage(response2); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, reverseCallCount); + } + + EXPECT_FALSE(disconnected); + + // What if we disconnect? + serverThread.pipe->shutdownWrite(); + + // The other side should also disconnect. + disconnectPromise.wait(ioContext.waitScope); + + { + // Use the now-broken capability. + auto request = client.getCapRequest(); + request.setN(234); + request.setInCap(kj::heap(reverseCallCount)); + + auto promise = request.send(); + + auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); + pipelineRequest.setI(321); + auto pipelinePromise = pipelineRequest.send(); + + auto pipelineRequest2 = promise.getOutBox().getCap() + .castAs().graultRequest(); + auto pipelinePromise2 = pipelineRequest2.send(); + + EXPECT_ANY_THROW(pipelinePromise.wait(ioContext.waitScope)); + EXPECT_ANY_THROW(pipelinePromise2.wait(ioContext.waitScope)); + + EXPECT_EQ(3, callCount); + EXPECT_EQ(1, reverseCallCount); + } + } +} + +TEST(TwoPartyNetwork, Release) { + auto ioContext = kj::setupAsyncIo(); + int callCount = 0; + int handleCount = 0; + + auto serverThread = runServer(*ioContext.provider, callCount, handleCount); + TwoPartyVatNetwork network(*serverThread.pipe, rpc::twoparty::Side::CLIENT); + auto rpcClient = makeRpcClient(network); + + // Request the particular capability from the server. + auto client = getPersistentCap(rpcClient, rpc::twoparty::Side::SERVER, + test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF).castAs(); + + auto handle1 = client.getHandleRequest().send().wait(ioContext.waitScope).getHandle(); + auto promise = client.getHandleRequest().send(); + auto handle2 = promise.wait(ioContext.waitScope).getHandle(); + + EXPECT_EQ(2, handleCount); + + handle1 = nullptr; + + // There once was a bug where the last outgoing message (and any capabilities attached) would + // not get cleaned up (until a new message was sent). This appeared to be a bug in Release, + // becaues if a client received a message and then released a capability from it but then did + // not make any further calls, then the capability would not be released because the message + // introducing it remained the last server -> client message (because a "Release" message has + // no reply). Here we are explicitly trying to catch this bug. This proves tricky, because when + // we drop a reference on the client side, there's no particular way to wait for the release + // message to reach the server except to make a subsequent call and wait for the return -- but + // that would mask the bug. So, we wait spin waiting for handleCount to change. + + uint maxSpins = 1000; + + while (handleCount > 1) { + ioContext.provider->getTimer().afterDelay(10 * kj::MILLISECONDS).wait(ioContext.waitScope); + KJ_ASSERT(--maxSpins > 0); + } + EXPECT_EQ(1, handleCount); + + handle2 = nullptr; + + ioContext.provider->getTimer().afterDelay(10 * kj::MILLISECONDS).wait(ioContext.waitScope); + EXPECT_EQ(1, handleCount); + + promise = nullptr; + + while (handleCount > 0) { + ioContext.provider->getTimer().afterDelay(10 * kj::MILLISECONDS).wait(ioContext.waitScope); + KJ_ASSERT(--maxSpins > 0); + } + EXPECT_EQ(0, handleCount); +} + +TEST(TwoPartyNetwork, Abort) { + // Verify that aborts are received. + + auto ioContext = kj::setupAsyncIo(); + int callCount = 0; + int handleCount = 0; + + auto serverThread = runServer(*ioContext.provider, callCount, handleCount); + TwoPartyVatNetwork network(*serverThread.pipe, rpc::twoparty::Side::CLIENT); + + MallocMessageBuilder refMessage(128); + auto hostId = refMessage.initRoot(); + hostId.setSide(rpc::twoparty::Side::SERVER); + + auto conn = KJ_ASSERT_NONNULL(network.connect(hostId)); + + { + // Send an invalid message (Return to non-existent question). + auto msg = conn->newOutgoingMessage(128); + auto body = msg->getBody().initAs().initReturn(); + body.setAnswerId(1234); + body.setCanceled(); + msg->send(); + } + + auto reply = KJ_ASSERT_NONNULL(conn->receiveIncomingMessage().wait(ioContext.waitScope)); + EXPECT_EQ(rpc::Message::ABORT, reply->getBody().getAs().which()); + + EXPECT_TRUE(conn->receiveIncomingMessage().wait(ioContext.waitScope) == nullptr); +} + +TEST(TwoPartyNetwork, ConvenienceClasses) { + auto ioContext = kj::setupAsyncIo(); + + int callCount = 0; + TwoPartyServer server(kj::heap(callCount)); + + auto address = ioContext.provider->getNetwork() + .parseAddress("127.0.0.1").wait(ioContext.waitScope); + + auto listener = address->listen(); + auto listenPromise = server.listen(*listener); + + address = ioContext.provider->getNetwork() + .parseAddress("127.0.0.1", listener->getPort()).wait(ioContext.waitScope); + + auto connection = address->connect().wait(ioContext.waitScope); + TwoPartyClient client(*connection); + auto cap = client.bootstrap().castAs(); + + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + EXPECT_EQ(0, callCount); + auto response = request.send().wait(ioContext.waitScope); + EXPECT_EQ("foo", response.getX()); + EXPECT_EQ(1, callCount); +} + +TEST(TwoPartyNetwork, HugeMessage) { + auto ioContext = kj::setupAsyncIo(); + int callCount = 0; + int handleCount = 0; + + auto serverThread = runServer(*ioContext.provider, callCount, handleCount); + TwoPartyVatNetwork network(*serverThread.pipe, rpc::twoparty::Side::CLIENT); + auto rpcClient = makeRpcClient(network); + + auto client = getPersistentCap(rpcClient, rpc::twoparty::Side::SERVER, + test::TestSturdyRefObjectId::Tag::TEST_MORE_STUFF).castAs(); + + // Oversized request fails. + { + auto req = client.methodWithDefaultsRequest(); + req.initA(100000000); // 100 MB + + KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("larger than the single-message size limit", + req.send().ignoreResult().wait(ioContext.waitScope)); + } + + // Oversized response fails. + KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("larger than the single-message size limit", + client.getEnormousStringRequest().send().ignoreResult().wait(ioContext.waitScope)); + + // Connection is still up. + { + auto req = client.getCallSequenceRequest(); + req.setExpected(0); + KJ_EXPECT(req.send().wait(ioContext.waitScope).getN() == 0); + } +} + +class TestAuthenticatedBootstrapImpl final + : public test::TestAuthenticatedBootstrap::Server { +public: + TestAuthenticatedBootstrapImpl(rpc::twoparty::VatId::Reader clientId) { + this->clientId.setRoot(clientId); + } + +protected: + kj::Promise getCallerId(GetCallerIdContext context) override { + context.getResults().setCaller(clientId.getRoot()); + return kj::READY_NOW; + } + +private: + MallocMessageBuilder clientId; +}; + +class TestBootstrapFactory: public BootstrapFactory { +public: + Capability::Client createFor(rpc::twoparty::VatId::Reader clientId) { + called = true; + EXPECT_EQ(rpc::twoparty::Side::CLIENT, clientId.getSide()); + return kj::heap(clientId); + } + + bool called = false; +}; + +kj::AsyncIoProvider::PipeThread runAuthenticatingServer( + kj::AsyncIoProvider& ioProvider, BootstrapFactory& bootstrapFactory) { + return ioProvider.newPipeThread([&bootstrapFactory]( + kj::AsyncIoProvider& ioProvider, kj::AsyncIoStream& stream, kj::WaitScope& waitScope) { + TwoPartyVatNetwork network(stream, rpc::twoparty::Side::SERVER); + auto server = makeRpcServer(network, bootstrapFactory); + network.onDisconnect().wait(waitScope); + }); +} + +TEST(TwoPartyNetwork, BootstrapFactory) { + auto ioContext = kj::setupAsyncIo(); + TestBootstrapFactory bootstrapFactory; + auto serverThread = runAuthenticatingServer(*ioContext.provider, bootstrapFactory); + TwoPartyClient client(*serverThread.pipe); + auto resp = client.bootstrap().castAs>() + .getCallerIdRequest().send().wait(ioContext.waitScope); + EXPECT_EQ(rpc::twoparty::Side::CLIENT, resp.getCaller().getSide()); + EXPECT_TRUE(bootstrapFactory.called); +} + +} // namespace +} // namespace _ +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,213 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "rpc-twoparty.h" +#include "serialize-async.h" +#include + +namespace capnp { + +TwoPartyVatNetwork::TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side, + ReaderOptions receiveOptions) + : stream(stream), side(side), peerVatId(4), + receiveOptions(receiveOptions), previousWrite(kj::READY_NOW) { + peerVatId.initRoot().setSide( + side == rpc::twoparty::Side::CLIENT ? rpc::twoparty::Side::SERVER + : rpc::twoparty::Side::CLIENT); + + auto paf = kj::newPromiseAndFulfiller(); + disconnectPromise = paf.promise.fork(); + disconnectFulfiller.fulfiller = kj::mv(paf.fulfiller); +} + +void TwoPartyVatNetwork::FulfillerDisposer::disposeImpl(void* pointer) const { + if (--refcount == 0) { + fulfiller->fulfill(); + } +} + +kj::Own TwoPartyVatNetwork::asConnection() { + ++disconnectFulfiller.refcount; + return kj::Own(this, disconnectFulfiller); +} + +kj::Maybe> TwoPartyVatNetwork::connect( + rpc::twoparty::VatId::Reader ref) { + if (ref.getSide() == side) { + return nullptr; + } else { + return asConnection(); + } +} + +kj::Promise> TwoPartyVatNetwork::accept() { + if (side == rpc::twoparty::Side::SERVER && !accepted) { + accepted = true; + return asConnection(); + } else { + // Create a promise that will never be fulfilled. + auto paf = kj::newPromiseAndFulfiller>(); + acceptFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); + } +} + +class TwoPartyVatNetwork::OutgoingMessageImpl final + : public OutgoingRpcMessage, public kj::Refcounted { +public: + OutgoingMessageImpl(TwoPartyVatNetwork& network, uint firstSegmentWordSize) + : network(network), + message(firstSegmentWordSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : firstSegmentWordSize) {} + + AnyPointer::Builder getBody() override { + return message.getRoot(); + } + + void send() override { + size_t size = 0; + for (auto& segment: message.getSegmentsForOutput()) { + size += segment.size(); + } + KJ_REQUIRE(size < ReaderOptions().traversalLimitInWords, size, + "Trying to send Cap'n Proto message larger than the single-message size limit. The " + "other side probably won't accept it and would abort the connection, so I won't " + "send it.") { + return; + } + + network.previousWrite = KJ_ASSERT_NONNULL(network.previousWrite, "already shut down") + .then([&]() { + // Note that if the write fails, all further writes will be skipped due to the exception. + // We never actually handle this exception because we assume the read end will fail as well + // and it's cleaner to handle the failure there. + return writeMessage(network.stream, message); + }).attach(kj::addRef(*this)) + // Note that it's important that the eagerlyEvaluate() come *after* the attach() because + // otherwise the message (and any capabilities in it) will not be released until a new + // message is written! (Kenton once spent all afternoon tracking this down...) + .eagerlyEvaluate(nullptr); + } + +private: + TwoPartyVatNetwork& network; + MallocMessageBuilder message; +}; + +class TwoPartyVatNetwork::IncomingMessageImpl final: public IncomingRpcMessage { +public: + IncomingMessageImpl(kj::Own message): message(kj::mv(message)) {} + + AnyPointer::Reader getBody() override { + return message->getRoot(); + } + +private: + kj::Own message; +}; + +rpc::twoparty::VatId::Reader TwoPartyVatNetwork::getPeerVatId() { + return peerVatId.getRoot(); +} + +kj::Own TwoPartyVatNetwork::newOutgoingMessage(uint firstSegmentWordSize) { + return kj::refcounted(*this, firstSegmentWordSize); +} + +kj::Promise>> TwoPartyVatNetwork::receiveIncomingMessage() { + return kj::evalLater([&]() { + return tryReadMessage(stream, receiveOptions) + .then([&](kj::Maybe>&& message) + -> kj::Maybe> { + KJ_IF_MAYBE(m, message) { + return kj::Own(kj::heap(kj::mv(*m))); + } else { + return nullptr; + } + }); + }); +} + +kj::Promise TwoPartyVatNetwork::shutdown() { + kj::Promise result = KJ_ASSERT_NONNULL(previousWrite, "already shut down").then([this]() { + stream.shutdownWrite(); + }); + previousWrite = nullptr; + return kj::mv(result); +} + +// ======================================================================================= + +TwoPartyServer::TwoPartyServer(Capability::Client bootstrapInterface) + : bootstrapInterface(kj::mv(bootstrapInterface)), tasks(*this) {} + +struct TwoPartyServer::AcceptedConnection { + kj::Own connection; + TwoPartyVatNetwork network; + RpcSystem rpcSystem; + + explicit AcceptedConnection(Capability::Client bootstrapInterface, + kj::Own&& connectionParam) + : connection(kj::mv(connectionParam)), + network(*connection, rpc::twoparty::Side::SERVER), + rpcSystem(makeRpcServer(network, kj::mv(bootstrapInterface))) {} +}; + +void TwoPartyServer::accept(kj::Own&& connection) { + auto connectionState = kj::heap(bootstrapInterface, kj::mv(connection)); + + // Run the connection until disconnect. + auto promise = connectionState->network.onDisconnect(); + tasks.add(promise.attach(kj::mv(connectionState))); +} + +kj::Promise TwoPartyServer::listen(kj::ConnectionReceiver& listener) { + return listener.accept() + .then([this,&listener](kj::Own&& connection) mutable { + accept(kj::mv(connection)); + return listen(listener); + }); +} + +void TwoPartyServer::taskFailed(kj::Exception&& exception) { + KJ_LOG(ERROR, exception); +} + +TwoPartyClient::TwoPartyClient(kj::AsyncIoStream& connection) + : network(connection, rpc::twoparty::Side::CLIENT), + rpcSystem(makeRpcClient(network)) {} + + +TwoPartyClient::TwoPartyClient(kj::AsyncIoStream& connection, + Capability::Client bootstrapInterface, + rpc::twoparty::Side side) + : network(connection, side), + rpcSystem(network, bootstrapInterface) {} + +Capability::Client TwoPartyClient::bootstrap() { + MallocMessageBuilder message(4); + auto vatId = message.getRoot(); + vatId.setSide(network.getSide() == rpc::twoparty::Side::CLIENT + ? rpc::twoparty::Side::SERVER + : rpc::twoparty::Side::CLIENT); + return rpcSystem.bootstrap(vatId); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,169 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xa184c7885cdaf2a1; +# This file defines the "network-specific parameters" in rpc.capnp to support a network consisting +# of two vats. Each of these vats may in fact be in communication with other vats, but any +# capabilities they forward must be proxied. Thus, to each end of the connection, all capabilities +# received from the other end appear to live in a single vat. +# +# Two notable use cases for this model include: +# - Regular client-server communications, where a remote client machine (perhaps living on an end +# user's personal device) connects to a server. The server may be part of a cluster, and may +# call on other servers in the cluster to help service the user's request. It may even obtain +# capabilities from these other servers which it passes on to the user. To simplify network +# common traversal problems (e.g. if the user is behind a firewall), it is probably desirable to +# multiplex all communications between the server cluster and the client over the original +# connection rather than form new ones. This connection should use the two-party protocol, as +# the client has no interest in knowing about additional servers. +# - Applications running in a sandbox. A supervisor process may execute a confined application +# such that all of the confined app's communications with the outside world must pass through +# the supervisor. In this case, the connection between the confined app and the supervisor might +# as well use the two-party protocol, because the confined app is intentionally prevented from +# talking to any other vat anyway. Any external resources will be proxied through the supervisor, +# and so to the contained app will appear as if they were hosted by the supervisor itself. +# +# Since there are only two vats in this network, there is never a need for three-way introductions, +# so level 3 is free. Moreover, because it is never necessary to form new connections, the +# two-party protocol can be used easily anywhere where a two-way byte stream exists, without regard +# to where that byte stream goes or how it was initiated. This makes the two-party runtime library +# highly reusable. +# +# Joins (level 4) _could_ be needed in cases where one or both vats are participating in other +# networks that use joins. For instance, if Alice and Bob are speaking through the two-party +# protocol, and Bob is also participating on another network, Bob may send Alice two or more +# proxied capabilities which, unbeknownst to Bob at the time, are in fact pointing at the same +# remote object. Alice may then request to join these capabilities, at which point Bob will have +# to forward the join to the other network. Note, however, that if Alice is _not_ participating on +# any other network, then Alice will never need to _receive_ a Join, because Alice would always +# know when two locally-hosted capabilities are the same and would never export a redundant alias +# to Bob. So, Alice can respond to all incoming joins with an error, and only needs to implement +# outgoing joins if she herself desires to use this feature. Also, outgoing joins are relatively +# easy to implement in this scenario. +# +# What all this means is that a level 4 implementation of the confined network is barely more +# complicated than a level 2 implementation. However, such an implementation allows the "client" +# or "confined" app to access the server's/supervisor's network with equal functionality to any +# native participant. In other words, an application which implements only the two-party protocol +# can be paired with a proxy app in order to participate in any network. +# +# So, when implementing Cap'n Proto in a new language, it makes sense to implement only the +# two-party protocol initially, and then pair applications with an appropriate proxy written in +# C++, rather than implement other parameterizations of the RPC protocol directly. + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("capnp::rpc::twoparty"); + +# Note: SturdyRef is not specified here. It is up to the application to define semantics of +# SturdyRefs if desired. + +enum Side { + server @0; + # The object lives on the "server" or "supervisor" end of the connection. Only the + # server/supervisor knows how to interpret the ref; to the client, it is opaque. + # + # Note that containers intending to implement strong confinement should rewrite SturdyRefs + # received from the external network before passing them on to the confined app. The confined + # app thus does not ever receive the raw bits of the SturdyRef (which it could perhaps + # maliciously leak), but instead receives only a thing that it can pass back to the container + # later to restore the ref. See: + # http://www.erights.org/elib/capability/dist-confine.html + + client @1; + # The object lives on the "client" or "confined app" end of the connection. Only the client + # knows how to interpret the ref; to the server/supervisor, it is opaque. Most clients do not + # actually know how to persist capabilities at all, so use of this is unusual. +} + +struct VatId { + side @0 :Side; +} + +struct ProvisionId { + # Only used for joins, since three-way introductions never happen on a two-party network. + + joinId @0 :UInt32; + # The ID from `JoinKeyPart`. +} + +struct RecipientId {} +# Never used, because there are only two parties. + +struct ThirdPartyCapId {} +# Never used, because there is no third party. + +struct JoinKeyPart { + # Joins in the two-party case are simplified by a few observations. + # + # First, on a two-party network, a Join only ever makes sense if the receiving end is also + # connected to other networks. A vat which is not connected to any other network can safely + # reject all joins. + # + # Second, since a two-party connection bisects the network -- there can be no other connections + # between the networks at either end of the connection -- if one part of a join crosses the + # connection, then _all_ parts must cross it. Therefore, a vat which is receiving a Join request + # off some other network which needs to be forwarded across the two-party connection can + # collect all the parts on its end and only forward them across the two-party connection when all + # have been received. + # + # For example, imagine that Alice and Bob are vats connected over a two-party connection, and + # each is also connected to other networks. At some point, Alice receives one part of a Join + # request off her network. The request is addressed to a capability that Alice received from + # Bob and is proxying to her other network. Alice goes ahead and responds to the Join part as + # if she hosted the capability locally (this is important so that if not all the Join parts end + # up at Alice, the original sender can detect the failed Join without hanging). As other parts + # trickle in, Alice verifies that each part is addressed to a capability from Bob and continues + # to respond to each one. Once the complete set of join parts is received, Alice checks if they + # were all for the exact same capability. If so, she doesn't need to send anything to Bob at + # all. Otherwise, she collects the set of capabilities (from Bob) to which the join parts were + # addressed and essentially initiates a _new_ Join request on those capabilities to Bob. Alice + # does not forward the Join parts she received herself, but essentially forwards the Join as a + # whole. + # + # On Bob's end, since he knows that Alice will always send all parts of a Join together, he + # simply waits until he's received them all, then performs a join on the respective capabilities + # as if it had been requested locally. + + joinId @0 :UInt32; + # A number identifying this join, chosen by the sender. May be reused once `Finish` messages are + # sent corresponding to all of the `Join` messages. + + partCount @1 :UInt16; + # The number of capabilities to be joined. + + partNum @2 :UInt16; + # Which part this request targets -- a number in the range [0, partCount). +} + +struct JoinResult { + joinId @0 :UInt32; + # Matches `JoinKeyPart`. + + succeeded @1 :Bool; + # All JoinResults in the set will have the same value for `succeeded`. The receiver actually + # implements the join by waiting for all the `JoinKeyParts` and then performing its own join on + # them, then going back and answering all the join requests afterwards. + + cap @2 :AnyPointer; + # One of the JoinResults will have a non-null `cap` which is the joined capability. + # + # TODO(cleanup): Change `AnyPointer` to `Capability` when that is supported. +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,405 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc-twoparty.capnp + +#include "rpc-twoparty.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<26> b_9fd69ebc87b9719c = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 156, 113, 185, 135, 188, 158, 214, 159, + 25, 0, 0, 0, 2, 0, 0, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 83, 105, 100, 101, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 101, 114, 118, 101, 114, 0, 0, + 99, 108, 105, 101, 110, 116, 0, 0, } +}; +::capnp::word const* const bp_9fd69ebc87b9719c = b_9fd69ebc87b9719c.words; +#if !CAPNP_LITE +static const uint16_t m_9fd69ebc87b9719c[] = {1, 0}; +const ::capnp::_::RawSchema s_9fd69ebc87b9719c = { + 0x9fd69ebc87b9719c, b_9fd69ebc87b9719c.words, 26, nullptr, m_9fd69ebc87b9719c, + 0, 2, nullptr, nullptr, nullptr, { &s_9fd69ebc87b9719c, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +CAPNP_DEFINE_ENUM(Side_9fd69ebc87b9719c, 9fd69ebc87b9719c); +static const ::capnp::_::AlignedData<33> b_d20b909fee733a8e = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 142, 58, 115, 238, 159, 144, 11, 210, + 25, 0, 0, 0, 1, 0, 1, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 86, 97, 116, 73, 100, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 115, 105, 100, 101, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 156, 113, 185, 135, 188, 158, 214, 159, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d20b909fee733a8e = b_d20b909fee733a8e.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d20b909fee733a8e[] = { + &s_9fd69ebc87b9719c, +}; +static const uint16_t m_d20b909fee733a8e[] = {0}; +static const uint16_t i_d20b909fee733a8e[] = {0}; +const ::capnp::_::RawSchema s_d20b909fee733a8e = { + 0xd20b909fee733a8e, b_d20b909fee733a8e.words, 33, d_d20b909fee733a8e, m_d20b909fee733a8e, + 1, 1, i_d20b909fee733a8e, nullptr, nullptr, { &s_d20b909fee733a8e, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<34> b_b88d09a9c5f39817 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 23, 152, 243, 197, 169, 9, 141, 184, + 25, 0, 0, 0, 1, 0, 1, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 42, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 80, 114, 111, 118, 105, 115, 105, + 111, 110, 73, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 106, 111, 105, 110, 73, 100, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b88d09a9c5f39817 = b_b88d09a9c5f39817.words; +#if !CAPNP_LITE +static const uint16_t m_b88d09a9c5f39817[] = {0}; +static const uint16_t i_b88d09a9c5f39817[] = {0}; +const ::capnp::_::RawSchema s_b88d09a9c5f39817 = { + 0xb88d09a9c5f39817, b_b88d09a9c5f39817.words, 34, nullptr, m_b88d09a9c5f39817, + 0, 1, i_b88d09a9c5f39817, nullptr, nullptr, { &s_b88d09a9c5f39817, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<18> b_89f389b6fd4082c1 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 193, 130, 64, 253, 182, 137, 243, 137, + 25, 0, 0, 0, 1, 0, 0, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 42, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 82, 101, 99, 105, 112, 105, 101, + 110, 116, 73, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, } +}; +::capnp::word const* const bp_89f389b6fd4082c1 = b_89f389b6fd4082c1.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_89f389b6fd4082c1 = { + 0x89f389b6fd4082c1, b_89f389b6fd4082c1.words, 18, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_89f389b6fd4082c1, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<19> b_b47f4979672cb59d = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 157, 181, 44, 103, 121, 73, 127, 180, + 25, 0, 0, 0, 1, 0, 0, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 74, 1, 0, 0, + 41, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 84, 104, 105, 114, 100, 80, 97, + 114, 116, 121, 67, 97, 112, 73, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, } +}; +::capnp::word const* const bp_b47f4979672cb59d = b_b47f4979672cb59d.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_b47f4979672cb59d = { + 0xb47f4979672cb59d, b_b47f4979672cb59d.words, 19, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_b47f4979672cb59d, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<65> b_95b29059097fca83 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 131, 202, 127, 9, 89, 144, 178, 149, + 25, 0, 0, 0, 1, 0, 1, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 42, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 74, 111, 105, 110, 75, 101, 121, + 80, 97, 114, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 106, 111, 105, 110, 73, 100, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 116, 67, 111, 117, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 116, 78, 117, 109, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_95b29059097fca83 = b_95b29059097fca83.words; +#if !CAPNP_LITE +static const uint16_t m_95b29059097fca83[] = {0, 1, 2}; +static const uint16_t i_95b29059097fca83[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_95b29059097fca83 = { + 0x95b29059097fca83, b_95b29059097fca83.words, 65, nullptr, m_95b29059097fca83, + 0, 3, i_95b29059097fca83, nullptr, nullptr, { &s_95b29059097fca83, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<65> b_9d263a3630b7ebee = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 238, 235, 183, 48, 54, 58, 38, 157, + 25, 0, 0, 0, 1, 0, 1, 0, + 161, 242, 218, 92, 136, 199, 132, 161, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 34, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 45, 116, 119, 111, 112, 97, 114, + 116, 121, 46, 99, 97, 112, 110, 112, + 58, 74, 111, 105, 110, 82, 101, 115, + 117, 108, 116, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 106, 111, 105, 110, 73, 100, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 117, 99, 99, 101, 101, 100, 101, + 100, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9d263a3630b7ebee = b_9d263a3630b7ebee.words; +#if !CAPNP_LITE +static const uint16_t m_9d263a3630b7ebee[] = {2, 0, 1}; +static const uint16_t i_9d263a3630b7ebee[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_9d263a3630b7ebee = { + 0x9d263a3630b7ebee, b_9d263a3630b7ebee.words, 65, nullptr, m_9d263a3630b7ebee, + 0, 3, i_9d263a3630b7ebee, nullptr, nullptr, { &s_9d263a3630b7ebee, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { +namespace rpc { +namespace twoparty { + +// VatId +constexpr uint16_t VatId::_capnpPrivate::dataWordSize; +constexpr uint16_t VatId::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind VatId::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* VatId::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// ProvisionId +constexpr uint16_t ProvisionId::_capnpPrivate::dataWordSize; +constexpr uint16_t ProvisionId::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind ProvisionId::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* ProvisionId::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// RecipientId +constexpr uint16_t RecipientId::_capnpPrivate::dataWordSize; +constexpr uint16_t RecipientId::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind RecipientId::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* RecipientId::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// ThirdPartyCapId +constexpr uint16_t ThirdPartyCapId::_capnpPrivate::dataWordSize; +constexpr uint16_t ThirdPartyCapId::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind ThirdPartyCapId::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* ThirdPartyCapId::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// JoinKeyPart +constexpr uint16_t JoinKeyPart::_capnpPrivate::dataWordSize; +constexpr uint16_t JoinKeyPart::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind JoinKeyPart::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* JoinKeyPart::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// JoinResult +constexpr uint16_t JoinResult::_capnpPrivate::dataWordSize; +constexpr uint16_t JoinResult::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind JoinResult::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* JoinResult::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace +} // namespace +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,726 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc-twoparty.capnp + +#ifndef CAPNP_INCLUDED_a184c7885cdaf2a1_ +#define CAPNP_INCLUDED_a184c7885cdaf2a1_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(9fd69ebc87b9719c); +enum class Side_9fd69ebc87b9719c: uint16_t { + SERVER, + CLIENT, +}; +CAPNP_DECLARE_ENUM(Side, 9fd69ebc87b9719c); +CAPNP_DECLARE_SCHEMA(d20b909fee733a8e); +CAPNP_DECLARE_SCHEMA(b88d09a9c5f39817); +CAPNP_DECLARE_SCHEMA(89f389b6fd4082c1); +CAPNP_DECLARE_SCHEMA(b47f4979672cb59d); +CAPNP_DECLARE_SCHEMA(95b29059097fca83); +CAPNP_DECLARE_SCHEMA(9d263a3630b7ebee); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace rpc { +namespace twoparty { + +typedef ::capnp::schemas::Side_9fd69ebc87b9719c Side; + +struct VatId { + VatId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d20b909fee733a8e, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ProvisionId { + ProvisionId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b88d09a9c5f39817, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct RecipientId { + RecipientId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(89f389b6fd4082c1, 0, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ThirdPartyCapId { + ThirdPartyCapId() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b47f4979672cb59d, 0, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JoinKeyPart { + JoinKeyPart() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(95b29059097fca83, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct JoinResult { + JoinResult() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9d263a3630b7ebee, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class VatId::Reader { +public: + typedef VatId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::capnp::rpc::twoparty::Side getSide() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class VatId::Builder { +public: + typedef VatId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::capnp::rpc::twoparty::Side getSide(); + inline void setSide( ::capnp::rpc::twoparty::Side value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class VatId::Pipeline { +public: + typedef VatId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ProvisionId::Reader { +public: + typedef ProvisionId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ProvisionId::Builder { +public: + typedef ProvisionId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ProvisionId::Pipeline { +public: + typedef ProvisionId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class RecipientId::Reader { +public: + typedef RecipientId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class RecipientId::Builder { +public: + typedef RecipientId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class RecipientId::Pipeline { +public: + typedef RecipientId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ThirdPartyCapId::Reader { +public: + typedef ThirdPartyCapId Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ThirdPartyCapId::Builder { +public: + typedef ThirdPartyCapId Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ThirdPartyCapId::Pipeline { +public: + typedef ThirdPartyCapId Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JoinKeyPart::Reader { +public: + typedef JoinKeyPart Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + + inline ::uint16_t getPartCount() const; + + inline ::uint16_t getPartNum() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JoinKeyPart::Builder { +public: + typedef JoinKeyPart Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + + inline ::uint16_t getPartCount(); + inline void setPartCount( ::uint16_t value); + + inline ::uint16_t getPartNum(); + inline void setPartNum( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JoinKeyPart::Pipeline { +public: + typedef JoinKeyPart Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class JoinResult::Reader { +public: + typedef JoinResult Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId() const; + + inline bool getSucceeded() const; + + inline bool hasCap() const; + inline ::capnp::AnyPointer::Reader getCap() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class JoinResult::Builder { +public: + typedef JoinResult Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getJoinId(); + inline void setJoinId( ::uint32_t value); + + inline bool getSucceeded(); + inline void setSucceeded(bool value); + + inline bool hasCap(); + inline ::capnp::AnyPointer::Builder getCap(); + inline ::capnp::AnyPointer::Builder initCap(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class JoinResult::Pipeline { +public: + typedef JoinResult Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::rpc::twoparty::Side VatId::Reader::getSide() const { + return _reader.getDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::rpc::twoparty::Side VatId::Builder::getSide() { + return _builder.getDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void VatId::Builder::setSide( ::capnp::rpc::twoparty::Side value) { + _builder.setDataField< ::capnp::rpc::twoparty::Side>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t ProvisionId::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t ProvisionId::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void ProvisionId::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t JoinKeyPart::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t JoinKeyPart::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t JoinKeyPart::Reader::getPartCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t JoinKeyPart::Builder::getPartCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setPartCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t JoinKeyPart::Reader::getPartNum() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t JoinKeyPart::Builder::getPartNum() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void JoinKeyPart::Builder::setPartNum( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t JoinResult::Reader::getJoinId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t JoinResult::Builder::getJoinId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void JoinResult::Builder::setJoinId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool JoinResult::Reader::getSucceeded() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} + +inline bool JoinResult::Builder::getSucceeded() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} +inline void JoinResult::Builder::setSucceeded(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value); +} + +inline bool JoinResult::Reader::hasCap() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool JoinResult::Builder::hasCap() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader JoinResult::Reader::getCap() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder JoinResult::Builder::getCap() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder JoinResult::Builder::initCap() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +} // namespace +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_a184c7885cdaf2a1_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc-twoparty.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,160 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RPC_TWOPARTY_H_ +#define CAPNP_RPC_TWOPARTY_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "rpc.h" +#include "message.h" +#include +#include + +namespace capnp { + +namespace rpc { + namespace twoparty { + typedef VatId SturdyRefHostId; // For backwards-compatibility with version 0.4. + } +} + +typedef VatNetwork + TwoPartyVatNetworkBase; + +class TwoPartyVatNetwork: public TwoPartyVatNetworkBase, + private TwoPartyVatNetworkBase::Connection { + // A `VatNetwork` that consists of exactly two parties communicating over an arbitrary byte + // stream. This is used to implement the common case of a client/server network. + // + // See `ez-rpc.h` for a simple interface for setting up two-party clients and servers. + // Use `TwoPartyVatNetwork` only if you need the advanced features. + +public: + TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side, + ReaderOptions receiveOptions = ReaderOptions()); + KJ_DISALLOW_COPY(TwoPartyVatNetwork); + + kj::Promise onDisconnect() { return disconnectPromise.addBranch(); } + // Returns a promise that resolves when the peer disconnects. + + rpc::twoparty::Side getSide() { return side; } + + // implements VatNetwork ----------------------------------------------------- + + kj::Maybe> connect( + rpc::twoparty::VatId::Reader ref) override; + kj::Promise> accept() override; + +private: + class OutgoingMessageImpl; + class IncomingMessageImpl; + + kj::AsyncIoStream& stream; + rpc::twoparty::Side side; + MallocMessageBuilder peerVatId; + ReaderOptions receiveOptions; + bool accepted = false; + + kj::Maybe> previousWrite; + // Resolves when the previous write completes. This effectively serves as the write queue. + // Becomes null when shutdown() is called. + + kj::Own>> acceptFulfiller; + // Fulfiller for the promise returned by acceptConnectionAsRefHost() on the client side, or the + // second call on the server side. Never fulfilled, because there is only one connection. + + kj::ForkedPromise disconnectPromise = nullptr; + + class FulfillerDisposer: public kj::Disposer { + // Hack: TwoPartyVatNetwork is both a VatNetwork and a VatNetwork::Connection. When the RPC + // system detects (or initiates) a disconnection, it drops its reference to the Connection. + // When all references have been dropped, then we want disconnectPromise to be fulfilled. + // So we hand out Owns with this disposer attached, so that we can detect when + // they are dropped. + + public: + mutable kj::Own> fulfiller; + mutable uint refcount = 0; + + void disposeImpl(void* pointer) const override; + }; + FulfillerDisposer disconnectFulfiller; + + kj::Own asConnection(); + // Returns a pointer to this with the disposer set to disconnectFulfiller. + + // implements Connection ----------------------------------------------------- + + rpc::twoparty::VatId::Reader getPeerVatId() override; + kj::Own newOutgoingMessage(uint firstSegmentWordSize) override; + kj::Promise>> receiveIncomingMessage() override; + kj::Promise shutdown() override; +}; + +class TwoPartyServer: private kj::TaskSet::ErrorHandler { + // Convenience class which implements a simple server which accepts connections on a listener + // socket and serices them as two-party connections. + +public: + explicit TwoPartyServer(Capability::Client bootstrapInterface); + + void accept(kj::Own&& connection); + // Accepts the connection for servicing. + + kj::Promise listen(kj::ConnectionReceiver& listener); + // Listens for connections on the given listener. The returned promise never resolves unless an + // exception is thrown while trying to accept. You may discard the returned promise to cancel + // listening. + +private: + Capability::Client bootstrapInterface; + kj::TaskSet tasks; + + struct AcceptedConnection; + + void taskFailed(kj::Exception&& exception) override; +}; + +class TwoPartyClient { + // Convenience class which implements a simple client. + +public: + explicit TwoPartyClient(kj::AsyncIoStream& connection); + TwoPartyClient(kj::AsyncIoStream& connection, Capability::Client bootstrapInterface, + rpc::twoparty::Side side = rpc::twoparty::Side::CLIENT); + + Capability::Client bootstrap(); + // Get the server's bootstrap interface. + + inline kj::Promise onDisconnect() { return network.onDisconnect(); } + +private: + TwoPartyVatNetwork network; + RpcSystem rpcSystem; +}; + +} // namespace capnp + +#endif // CAPNP_RPC_TWOPARTY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,2917 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "rpc.h" +#include "message.h" +#include +#include +#include +#include +#include +#include // std::greater +#include +#include +#include +#include + +namespace capnp { +namespace _ { // private + +namespace { + +template +inline constexpr uint messageSizeHint() { + return 1 + sizeInWords() + sizeInWords(); +} +template <> +inline constexpr uint messageSizeHint() { + return 1 + sizeInWords(); +} + +constexpr const uint MESSAGE_TARGET_SIZE_HINT = sizeInWords() + + sizeInWords() + 16; // +16 for ops; hope that's enough + +constexpr const uint CAP_DESCRIPTOR_SIZE_HINT = sizeInWords() + + sizeInWords(); + +constexpr const uint64_t MAX_SIZE_HINT = 1 << 20; + +uint copySizeHint(MessageSize size) { + uint64_t sizeHint = size.wordCount + size.capCount * CAP_DESCRIPTOR_SIZE_HINT; + return kj::min(MAX_SIZE_HINT, sizeHint); +} + +uint firstSegmentSize(kj::Maybe sizeHint, uint additional) { + KJ_IF_MAYBE(s, sizeHint) { + return copySizeHint(*s) + additional; + } else { + return 0; + } +} + +kj::Maybe> toPipelineOps(List::Reader ops) { + auto result = kj::heapArrayBuilder(ops.size()); + for (auto opReader: ops) { + PipelineOp op; + switch (opReader.which()) { + case rpc::PromisedAnswer::Op::NOOP: + op.type = PipelineOp::NOOP; + break; + case rpc::PromisedAnswer::Op::GET_POINTER_FIELD: + op.type = PipelineOp::GET_POINTER_FIELD; + op.pointerIndex = opReader.getGetPointerField(); + break; + default: + KJ_FAIL_REQUIRE("Unsupported pipeline op.", (uint)opReader.which()) { + return nullptr; + } + } + result.add(op); + } + return result.finish(); +} + +Orphan> fromPipelineOps( + Orphanage orphanage, kj::ArrayPtr ops) { + auto result = orphanage.newOrphan>(ops.size()); + auto builder = result.get(); + for (uint i: kj::indices(ops)) { + rpc::PromisedAnswer::Op::Builder opBuilder = builder[i]; + switch (ops[i].type) { + case PipelineOp::NOOP: + opBuilder.setNoop(); + break; + case PipelineOp::GET_POINTER_FIELD: + opBuilder.setGetPointerField(ops[i].pointerIndex); + break; + } + } + return result; +} + +kj::Exception toException(const rpc::Exception::Reader& exception) { + return kj::Exception(static_cast(exception.getType()), + "(remote)", 0, kj::str("remote exception: ", exception.getReason())); +} + +void fromException(const kj::Exception& exception, rpc::Exception::Builder builder) { + // TODO(someday): Indicate the remote server name as part of the stack trace. Maybe even + // transmit stack traces? + + kj::StringPtr description = exception.getDescription(); + + // Include context, if any. + kj::Vector contextLines; + for (auto context = exception.getContext();;) { + KJ_IF_MAYBE(c, context) { + contextLines.add(kj::str("context: ", c->file, ": ", c->line, ": ", c->description)); + context = c->next; + } else { + break; + } + } + kj::String scratch; + if (contextLines.size() > 0) { + scratch = kj::str(description, '\n', kj::strArray(contextLines, "\n")); + description = scratch; + } + + builder.setReason(description); + builder.setType(static_cast(exception.getType())); + + if (exception.getType() == kj::Exception::Type::FAILED && + !exception.getDescription().startsWith("remote exception:")) { + KJ_LOG(INFO, "returning failure over rpc", exception); + } +} + +uint exceptionSizeHint(const kj::Exception& exception) { + return sizeInWords() + exception.getDescription().size() / sizeof(word) + 1; +} + +// ======================================================================================= + +template +class ExportTable { + // Table mapping integers to T, where the integers are chosen locally. + +public: + kj::Maybe find(Id id) { + if (id < slots.size() && slots[id] != nullptr) { + return slots[id]; + } else { + return nullptr; + } + } + + T erase(Id id, T& entry) { + // Remove an entry from the table and return it. We return it so that the caller can be + // careful to release it (possibly invoking arbitrary destructors) at a time that makes sense. + // `entry` is a reference to the entry being released -- we require this in order to prove + // that the caller has already done a find() to check that this entry exists. We can't check + // ourselves because the caller may have nullified the entry in the meantime. + KJ_DREQUIRE(&entry == &slots[id]); + T toRelease = kj::mv(slots[id]); + slots[id] = T(); + freeIds.push(id); + return toRelease; + } + + T& next(Id& id) { + if (freeIds.empty()) { + id = slots.size(); + return slots.add(); + } else { + id = freeIds.top(); + freeIds.pop(); + return slots[id]; + } + } + + template + void forEach(Func&& func) { + for (Id i = 0; i < slots.size(); i++) { + if (slots[i] != nullptr) { + func(i, slots[i]); + } + } + } + +private: + kj::Vector slots; + std::priority_queue, std::greater> freeIds; +}; + +template +class ImportTable { + // Table mapping integers to T, where the integers are chosen remotely. + +public: + T& operator[](Id id) { + if (id < kj::size(low)) { + return low[id]; + } else { + return high[id]; + } + } + + kj::Maybe find(Id id) { + if (id < kj::size(low)) { + return low[id]; + } else { + auto iter = high.find(id); + if (iter == high.end()) { + return nullptr; + } else { + return iter->second; + } + } + } + + T erase(Id id) { + // Remove an entry from the table and return it. We return it so that the caller can be + // careful to release it (possibly invoking arbitrary destructors) at a time that makes sense. + if (id < kj::size(low)) { + T toRelease = kj::mv(low[id]); + low[id] = T(); + return toRelease; + } else { + T toRelease = kj::mv(high[id]); + high.erase(id); + return toRelease; + } + } + + template + void forEach(Func&& func) { + for (Id i: kj::indices(low)) { + func(i, low[i]); + } + for (auto& entry: high) { + func(entry.first, entry.second); + } + } + +private: + T low[16]; + std::unordered_map high; +}; + +// ======================================================================================= + +class RpcConnectionState final: public kj::TaskSet::ErrorHandler, public kj::Refcounted { +public: + struct DisconnectInfo { + kj::Promise shutdownPromise; + // Task which is working on sending an abort message and cleanly ending the connection. + }; + + RpcConnectionState(BootstrapFactoryBase& bootstrapFactory, + kj::Maybe::Client> gateway, + kj::Maybe restorer, + kj::Own&& connectionParam, + kj::Own>&& disconnectFulfiller, + size_t flowLimit) + : bootstrapFactory(bootstrapFactory), gateway(kj::mv(gateway)), + restorer(restorer), disconnectFulfiller(kj::mv(disconnectFulfiller)), flowLimit(flowLimit), + tasks(*this) { + connection.init(kj::mv(connectionParam)); + tasks.add(messageLoop()); + } + + kj::Own restore(AnyPointer::Reader objectId) { + if (connection.is()) { + return newBrokenCap(kj::cp(connection.get())); + } + + QuestionId questionId; + auto& question = questions.next(questionId); + + question.isAwaitingReturn = true; + + auto paf = kj::newPromiseAndFulfiller>>(); + + auto questionRef = kj::refcounted(*this, questionId, kj::mv(paf.fulfiller)); + question.selfRef = *questionRef; + + paf.promise = paf.promise.attach(kj::addRef(*questionRef)); + + { + auto message = connection.get()->newOutgoingMessage( + objectId.targetSize().wordCount + messageSizeHint()); + + auto builder = message->getBody().initAs().initBootstrap(); + builder.setQuestionId(questionId); + builder.getDeprecatedObjectId().set(objectId); + + message->send(); + } + + auto pipeline = kj::refcounted(*this, kj::mv(questionRef), kj::mv(paf.promise)); + + return pipeline->getPipelinedCap(kj::Array(nullptr)); + } + + void taskFailed(kj::Exception&& exception) override { + disconnect(kj::mv(exception)); + } + + void disconnect(kj::Exception&& exception) { + if (!connection.is()) { + // Already disconnected. + return; + } + + kj::Exception networkException(kj::Exception::Type::DISCONNECTED, + exception.getFile(), exception.getLine(), kj::heapString(exception.getDescription())); + + KJ_IF_MAYBE(newException, kj::runCatchingExceptions([&]() { + // Carefully pull all the objects out of the tables prior to releasing them because their + // destructors could come back and mess with the tables. + kj::Vector> pipelinesToRelease; + kj::Vector> clientsToRelease; + kj::Vector>> tailCallsToRelease; + kj::Vector> resolveOpsToRelease; + + // All current questions complete with exceptions. + questions.forEach([&](QuestionId id, Question& question) { + KJ_IF_MAYBE(questionRef, question.selfRef) { + // QuestionRef still present. + questionRef->reject(kj::cp(networkException)); + } + }); + + answers.forEach([&](AnswerId id, Answer& answer) { + KJ_IF_MAYBE(p, answer.pipeline) { + pipelinesToRelease.add(kj::mv(*p)); + } + + KJ_IF_MAYBE(promise, answer.redirectedResults) { + tailCallsToRelease.add(kj::mv(*promise)); + } + + KJ_IF_MAYBE(context, answer.callContext) { + context->requestCancel(); + } + }); + + exports.forEach([&](ExportId id, Export& exp) { + clientsToRelease.add(kj::mv(exp.clientHook)); + resolveOpsToRelease.add(kj::mv(exp.resolveOp)); + exp = Export(); + }); + + imports.forEach([&](ImportId id, Import& import) { + KJ_IF_MAYBE(f, import.promiseFulfiller) { + f->get()->reject(kj::cp(networkException)); + } + }); + + embargoes.forEach([&](EmbargoId id, Embargo& embargo) { + KJ_IF_MAYBE(f, embargo.fulfiller) { + f->get()->reject(kj::cp(networkException)); + } + }); + })) { + // Some destructor must have thrown an exception. There is no appropriate place to report + // these errors. + KJ_LOG(ERROR, "Uncaught exception when destroying capabilities dropped by disconnect.", + *newException); + } + + // Send an abort message, but ignore failure. + kj::runCatchingExceptions([&]() { + auto message = connection.get()->newOutgoingMessage( + messageSizeHint() + exceptionSizeHint(exception)); + fromException(exception, message->getBody().getAs().initAbort()); + message->send(); + }); + + // Indicate disconnect. + auto shutdownPromise = connection.get()->shutdown() + .attach(kj::mv(connection.get())) + .then([]() -> kj::Promise { return kj::READY_NOW; }, + [](kj::Exception&& e) -> kj::Promise { + // Don't report disconnects as an error. + if (e.getType() != kj::Exception::Type::DISCONNECTED) { + return kj::mv(e); + } + return kj::READY_NOW; + }); + disconnectFulfiller->fulfill(DisconnectInfo { kj::mv(shutdownPromise) }); + connection.init(kj::mv(networkException)); + } + + void setFlowLimit(size_t words) { + flowLimit = words; + maybeUnblockFlow(); + } + +private: + class RpcClient; + class ImportClient; + class PromiseClient; + class QuestionRef; + class RpcPipeline; + class RpcCallContext; + class RpcResponse; + + // ======================================================================================= + // The Four Tables entry types + // + // We have to define these before we can define the class's fields. + + typedef uint32_t QuestionId; + typedef QuestionId AnswerId; + typedef uint32_t ExportId; + typedef ExportId ImportId; + // See equivalent definitions in rpc.capnp. + // + // We always use the type that refers to the local table of the same name. So e.g. although + // QuestionId and AnswerId are the same type, we use QuestionId when referring to an entry in + // the local question table (which corresponds to the peer's answer table) and use AnswerId + // to refer to an entry in our answer table (which corresponds to the peer's question table). + // Since all messages in the RPC protocol are defined from the sender's point of view, this + // means that any time we read an ID from a received message, its type should invert. + // TODO(cleanup): Perhaps we could enforce that in a type-safe way? Hmm... + + struct Question { + kj::Array paramExports; + // List of exports that were sent in the request. If the response has `releaseParamCaps` these + // will need to be released. + + kj::Maybe selfRef; + // The local QuestionRef, set to nullptr when it is destroyed, which is also when `Finish` is + // sent. + + bool isAwaitingReturn = false; + // True from when `Call` is sent until `Return` is received. + + bool isTailCall = false; + // Is this a tail call? If so, we don't expect to receive results in the `Return`. + + bool skipFinish = false; + // If true, don't send a Finish message. + + inline bool operator==(decltype(nullptr)) const { + return !isAwaitingReturn && selfRef == nullptr; + } + inline bool operator!=(decltype(nullptr)) const { return !operator==(nullptr); } + }; + + struct Answer { + Answer() = default; + Answer(const Answer&) = delete; + Answer(Answer&&) = default; + Answer& operator=(Answer&&) = default; + // If we don't explicitly write all this, we get some stupid error deep in STL. + + bool active = false; + // True from the point when the Call message is received to the point when both the `Finish` + // message has been received and the `Return` has been sent. + + kj::Maybe> pipeline; + // Send pipelined calls here. Becomes null as soon as a `Finish` is received. + + kj::Maybe>> redirectedResults; + // For locally-redirected calls (Call.sendResultsTo.yourself), this is a promise for the call + // result, to be picked up by a subsequent `Return`. + + kj::Maybe callContext; + // The call context, if it's still active. Becomes null when the `Return` message is sent. + // This object, if non-null, is owned by `asyncOp`. + + kj::Array resultExports; + // List of exports that were sent in the results. If the finish has `releaseResultCaps` these + // will need to be released. + }; + + struct Export { + uint refcount = 0; + // When this reaches 0, drop `clientHook` and free this export. + + kj::Own clientHook; + + kj::Promise resolveOp = nullptr; + // If this export is a promise (not a settled capability), the `resolveOp` represents the + // ongoing operation to wait for that promise to resolve and then send a `Resolve` message. + + inline bool operator==(decltype(nullptr)) const { return refcount == 0; } + inline bool operator!=(decltype(nullptr)) const { return refcount != 0; } + }; + + struct Import { + Import() = default; + Import(const Import&) = delete; + Import(Import&&) = default; + Import& operator=(Import&&) = default; + // If we don't explicitly write all this, we get some stupid error deep in STL. + + kj::Maybe importClient; + // Becomes null when the import is destroyed. + + kj::Maybe appClient; + // Either a copy of importClient, or, in the case of promises, the wrapping PromiseClient. + // Becomes null when it is discarded *or* when the import is destroyed (e.g. the promise is + // resolved and the import is no longer needed). + + kj::Maybe>>> promiseFulfiller; + // If non-null, the import is a promise. + }; + + typedef uint32_t EmbargoId; + + struct Embargo { + // For handling the `Disembargo` message when looping back to self. + + kj::Maybe>> fulfiller; + // Fulfill this when the Disembargo arrives. + + inline bool operator==(decltype(nullptr)) const { return fulfiller == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return fulfiller != nullptr; } + }; + + // ======================================================================================= + // OK, now we can define RpcConnectionState's member data. + + BootstrapFactoryBase& bootstrapFactory; + kj::Maybe::Client> gateway; + kj::Maybe restorer; + + typedef kj::Own Connected; + typedef kj::Exception Disconnected; + kj::OneOf connection; + // Once the connection has failed, we drop it and replace it with an exception, which will be + // thrown from all further calls. + + kj::Own> disconnectFulfiller; + + ExportTable exports; + ExportTable questions; + ImportTable answers; + ImportTable imports; + // The Four Tables! + // The order of the tables is important for correct destruction. + + std::unordered_map exportsByCap; + // Maps already-exported ClientHook objects to their ID in the export table. + + ExportTable embargoes; + // There are only four tables. This definitely isn't a fifth table. I don't know what you're + // talking about. + + size_t flowLimit; + size_t callWordsInFlight = 0; + + kj::Maybe>> flowWaiter; + // If non-null, we're currently blocking incoming messages waiting for callWordsInFlight to drop + // below flowLimit. Fulfill this to un-block. + + kj::TaskSet tasks; + + // ===================================================================================== + // ClientHook implementations + + class RpcClient: public ClientHook, public kj::Refcounted { + public: + RpcClient(RpcConnectionState& connectionState) + : connectionState(kj::addRef(connectionState)) {} + + virtual kj::Maybe writeDescriptor(rpc::CapDescriptor::Builder descriptor) = 0; + // Writes a CapDescriptor referencing this client. The CapDescriptor must be sent as part of + // the very next message sent on the connection, as it may become invalid if other things + // happen. + // + // If writing the descriptor adds a new export to the export table, or increments the refcount + // on an existing one, then the ID is returned and the caller is responsible for removing it + // later. + + virtual kj::Maybe> writeTarget( + rpc::MessageTarget::Builder target) = 0; + // Writes the appropriate call target for calls to this capability and returns null. + // + // - OR - + // + // If calls have been redirected to some other local ClientHook, returns that hook instead. + // This can happen if the capability represents a promise that has been resolved. + + virtual kj::Own getInnermostClient() = 0; + // If this client just wraps some other client -- even if it is only *temporarily* wrapping + // that other client -- return a reference to the other client, transitively. Otherwise, + // return a new reference to *this. + + // implements ClientHook ----------------------------------------- + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + if (interfaceId == typeId>() && methodId == 0) { + KJ_IF_MAYBE(g, connectionState->gateway) { + // Wait, this is a call to Persistent.save() and we need to translate it through our + // gateway. + // + // We pull a neat trick here: We actually end up returning a RequestHook for an import + // request on the gateway cap, but with the "root" of the request actually pointing + // to the "params" field of the real request. + + sizeHint = sizeHint.map([](MessageSize hint) { + ++hint.capCount; + hint.wordCount += sizeInWords::ImportParams>(); + return hint; + }); + + auto request = g->importRequest(sizeHint); + request.setCap(Persistent<>::Client(kj::refcounted(*this))); + + // Awkwardly, request.initParams() would return a SaveParams struct, but to construct + // the Request to return we need an AnyPointer::Builder, and you + // can't go backwards from a struct builder to an AnyPointer builder. So instead we + // manually get at the pointer by converting the outer request to AnyStruct and then + // pulling the pointer from the pointer section. + auto pointers = toAny(request).getPointerSection(); + KJ_ASSERT(pointers.size() >= 2); + auto paramsPtr = pointers[1]; + KJ_ASSERT(paramsPtr.isNull()); + + return Request(paramsPtr, RequestHook::from(kj::mv(request))); + } + } + + return newCallNoIntercept(interfaceId, methodId, sizeHint); + } + + Request newCallNoIntercept( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) { + if (!connectionState->connection.is()) { + return newBrokenRequest(kj::cp(connectionState->connection.get()), sizeHint); + } + + auto request = kj::heap( + *connectionState, *connectionState->connection.get(), + sizeHint, kj::addRef(*this)); + auto callBuilder = request->getCall(); + + callBuilder.setInterfaceId(interfaceId); + callBuilder.setMethodId(methodId); + + auto root = request->getRoot(); + return Request(root, kj::mv(request)); + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + if (interfaceId == typeId>() && methodId == 0) { + KJ_IF_MAYBE(g, connectionState->gateway) { + // Wait, this is a call to Persistent.save() and we need to translate it through our + // gateway. + auto params = context->getParams().getAs::SaveParams>(); + + auto requestSize = params.totalSize(); + ++requestSize.capCount; + requestSize.wordCount += sizeInWords::ImportParams>(); + + auto request = g->importRequest(requestSize); + request.setCap(Persistent<>::Client(kj::refcounted(*this))); + request.setParams(params); + + context->allowCancellation(); + context->releaseParams(); + return context->directTailCall(RequestHook::from(kj::mv(request))); + } + } + + return callNoIntercept(interfaceId, methodId, kj::mv(context)); + } + + VoidPromiseAndPipeline callNoIntercept(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) { + // Implement call() by copying params and results messages. + + auto params = context->getParams(); + auto request = newCallNoIntercept(interfaceId, methodId, params.targetSize()); + + request.set(params); + context->releaseParams(); + + // We can and should propagate cancellation. + context->allowCancellation(); + + return context->directTailCall(RequestHook::from(kj::mv(request))); + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + const void* getBrand() override { + return connectionState.get(); + } + + kj::Own connectionState; + }; + + class ImportClient final: public RpcClient { + // A ClientHook that wraps an entry in the import table. + + public: + ImportClient(RpcConnectionState& connectionState, ImportId importId) + : RpcClient(connectionState), importId(importId) {} + + ~ImportClient() noexcept(false) { + unwindDetector.catchExceptionsIfUnwinding([&]() { + // Remove self from the import table, if the table is still pointing at us. + KJ_IF_MAYBE(import, connectionState->imports.find(importId)) { + KJ_IF_MAYBE(i, import->importClient) { + if (i == this) { + connectionState->imports.erase(importId); + } + } + } + + // Send a message releasing our remote references. + if (remoteRefcount > 0 && connectionState->connection.is()) { + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint()); + rpc::Release::Builder builder = message->getBody().initAs().initRelease(); + builder.setId(importId); + builder.setReferenceCount(remoteRefcount); + message->send(); + } + }); + } + + void addRemoteRef() { + // Add a new RemoteRef and return a new ref to this client representing it. + ++remoteRefcount; + } + + kj::Maybe writeDescriptor(rpc::CapDescriptor::Builder descriptor) override { + descriptor.setReceiverHosted(importId); + return nullptr; + } + + kj::Maybe> writeTarget( + rpc::MessageTarget::Builder target) override { + target.setImportedCap(importId); + return nullptr; + } + + kj::Own getInnermostClient() override { + return kj::addRef(*this); + } + + // implements ClientHook ----------------------------------------- + + kj::Maybe getResolved() override { + return nullptr; + } + + kj::Maybe>> whenMoreResolved() override { + return nullptr; + } + + private: + ImportId importId; + + uint remoteRefcount = 0; + // Number of times we've received this import from the peer. + + kj::UnwindDetector unwindDetector; + }; + + class PipelineClient final: public RpcClient { + // A ClientHook representing a pipelined promise. Always wrapped in PromiseClient. + + public: + PipelineClient(RpcConnectionState& connectionState, + kj::Own&& questionRef, + kj::Array&& ops) + : RpcClient(connectionState), questionRef(kj::mv(questionRef)), ops(kj::mv(ops)) {} + + kj::Maybe writeDescriptor(rpc::CapDescriptor::Builder descriptor) override { + auto promisedAnswer = descriptor.initReceiverAnswer(); + promisedAnswer.setQuestionId(questionRef->getId()); + promisedAnswer.adoptTransform(fromPipelineOps( + Orphanage::getForMessageContaining(descriptor), ops)); + return nullptr; + } + + kj::Maybe> writeTarget( + rpc::MessageTarget::Builder target) override { + auto builder = target.initPromisedAnswer(); + builder.setQuestionId(questionRef->getId()); + builder.adoptTransform(fromPipelineOps(Orphanage::getForMessageContaining(builder), ops)); + return nullptr; + } + + kj::Own getInnermostClient() override { + return kj::addRef(*this); + } + + // implements ClientHook ----------------------------------------- + + kj::Maybe getResolved() override { + return nullptr; + } + + kj::Maybe>> whenMoreResolved() override { + return nullptr; + } + + private: + kj::Own questionRef; + kj::Array ops; + }; + + class PromiseClient final: public RpcClient { + // A ClientHook that initially wraps one client (in practice, an ImportClient or a + // PipelineClient) and then, later on, redirects to some other client. + + public: + PromiseClient(RpcConnectionState& connectionState, + kj::Own initial, + kj::Promise> eventual, + kj::Maybe importId) + : RpcClient(connectionState), + isResolved(false), + cap(kj::mv(initial)), + importId(importId), + fork(eventual.fork()), + resolveSelfPromise(fork.addBranch().then( + [this](kj::Own&& resolution) { + resolve(kj::mv(resolution), false); + }, [this](kj::Exception&& exception) { + resolve(newBrokenCap(kj::mv(exception)), true); + }).eagerlyEvaluate([&](kj::Exception&& e) { + // Make any exceptions thrown from resolve() go to the connection's TaskSet which + // will cause the connection to be terminated. + connectionState.tasks.add(kj::mv(e)); + })) { + // Create a client that starts out forwarding all calls to `initial` but, once `eventual` + // resolves, will forward there instead. In addition, `whenMoreResolved()` will return a fork + // of `eventual`. Note that this means the application could hold on to `eventual` even after + // the `PromiseClient` is destroyed; `eventual` must therefore make sure to hold references to + // anything that needs to stay alive in order to resolve it correctly (such as making sure the + // import ID is not released). + } + + ~PromiseClient() noexcept(false) { + KJ_IF_MAYBE(id, importId) { + // This object is representing an import promise. That means the import table may still + // contain a pointer back to it. Remove that pointer. Note that we have to verify that + // the import still exists and the pointer still points back to this object because this + // object may actually outlive the import. + KJ_IF_MAYBE(import, connectionState->imports.find(*id)) { + KJ_IF_MAYBE(c, import->appClient) { + if (c == this) { + import->appClient = nullptr; + } + } + } + } + } + + kj::Maybe writeDescriptor(rpc::CapDescriptor::Builder descriptor) override { + receivedCall = true; + return connectionState->writeDescriptor(*cap, descriptor); + } + + kj::Maybe> writeTarget( + rpc::MessageTarget::Builder target) override { + receivedCall = true; + return connectionState->writeTarget(*cap, target); + } + + kj::Own getInnermostClient() override { + receivedCall = true; + return connectionState->getInnermostClient(*cap); + } + + // implements ClientHook ----------------------------------------- + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + if (!isResolved && interfaceId == typeId>() && methodId == 0 && + connectionState->gateway != nullptr) { + // This is a call to Persistent.save(), and we're not resolved yet, and the underlying + // remote capability will perform a gateway translation. This isn't right if the promise + // ultimately resolves to a local capability. Instead, we'll need to queue the call until + // the promise resolves. + return newLocalPromiseClient(fork.addBranch()) + ->newCall(interfaceId, methodId, sizeHint); + } + + receivedCall = true; + return cap->newCall(interfaceId, methodId, sizeHint); + } + + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + if (!isResolved && interfaceId == typeId>() && methodId == 0 && + connectionState->gateway != nullptr) { + // This is a call to Persistent.save(), and we're not resolved yet, and the underlying + // remote capability will perform a gateway translation. This isn't right if the promise + // ultimately resolves to a local capability. Instead, we'll need to queue the call until + // the promise resolves. + + auto vpapPromises = fork.addBranch().then(kj::mvCapture(context, + [interfaceId,methodId](kj::Own&& context, + kj::Own resolvedCap) { + auto vpap = resolvedCap->call(interfaceId, methodId, kj::mv(context)); + return kj::tuple(kj::mv(vpap.promise), kj::mv(vpap.pipeline)); + })).split(); + + return { + kj::mv(kj::get<0>(vpapPromises)), + newLocalPromisePipeline(kj::mv(kj::get<1>(vpapPromises))), + }; + } + + receivedCall = true; + return cap->call(interfaceId, methodId, kj::mv(context)); + } + + kj::Maybe getResolved() override { + if (isResolved) { + return *cap; + } else { + return nullptr; + } + } + + kj::Maybe>> whenMoreResolved() override { + return fork.addBranch(); + } + + private: + bool isResolved; + kj::Own cap; + + kj::Maybe importId; + kj::ForkedPromise> fork; + + // Keep this last, because the continuation uses *this, so it should be destroyed first to + // ensure the continuation is not still running. + kj::Promise resolveSelfPromise; + + bool receivedCall = false; + + void resolve(kj::Own replacement, bool isError) { + const void* replacementBrand = replacement->getBrand(); + if (replacementBrand != connectionState.get() && + replacementBrand != &ClientHook::NULL_CAPABILITY_BRAND && + receivedCall && !isError && connectionState->connection.is()) { + // The new capability is hosted locally, not on the remote machine. And, we had made calls + // to the promise. We need to make sure those calls echo back to us before we allow new + // calls to go directly to the local capability, so we need to set a local embargo and send + // a `Disembargo` to echo through the peer. + + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint() + MESSAGE_TARGET_SIZE_HINT); + + auto disembargo = message->getBody().initAs().initDisembargo(); + + { + auto redirect = connectionState->writeTarget(*cap, disembargo.initTarget()); + KJ_ASSERT(redirect == nullptr, + "Original promise target should always be from this RPC connection."); + } + + EmbargoId embargoId; + Embargo& embargo = connectionState->embargoes.next(embargoId); + + disembargo.getContext().setSenderLoopback(embargoId); + + auto paf = kj::newPromiseAndFulfiller(); + embargo.fulfiller = kj::mv(paf.fulfiller); + + // Make a promise which resolves to `replacement` as soon as the `Disembargo` comes back. + auto embargoPromise = paf.promise.then( + kj::mvCapture(replacement, [](kj::Own&& replacement) { + return kj::mv(replacement); + })); + + // We need to queue up calls in the meantime, so we'll resolve ourselves to a local promise + // client instead. + replacement = newLocalPromiseClient(kj::mv(embargoPromise)); + + // Send the `Disembargo`. + message->send(); + } + + cap = kj::mv(replacement); + isResolved = true; + } + }; + + class NoInterceptClient final: public RpcClient { + // A wrapper around an RpcClient which bypasses special handling of "save" requests. When we + // intercept a "save" request and invoke a RealmGateway, we give it a version of the capability + // with intercepting disabled, since usually the first thing the RealmGateway will do is turn + // around and call save() again. + // + // This is admittedly sort of backwards: the interception of "save" ought to be the part + // implemented by a wrapper. However, that would require placing a wrapper around every + // RpcClient we create whereas NoInterceptClient only needs to be injected after a save() + // request occurs and is intercepted. + + public: + NoInterceptClient(RpcClient& inner) + : RpcClient(*inner.connectionState), + inner(kj::addRef(inner)) {} + + kj::Maybe writeDescriptor(rpc::CapDescriptor::Builder descriptor) override { + return inner->writeDescriptor(descriptor); + } + + kj::Maybe> writeTarget(rpc::MessageTarget::Builder target) override { + return inner->writeTarget(target); + } + + kj::Own getInnermostClient() override { + return inner->getInnermostClient(); + } + + Request newCall( + uint64_t interfaceId, uint16_t methodId, kj::Maybe sizeHint) override { + return inner->newCallNoIntercept(interfaceId, methodId, sizeHint); + } + VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, + kj::Own&& context) override { + return inner->callNoIntercept(interfaceId, methodId, kj::mv(context)); + } + + kj::Maybe getResolved() override { + return nullptr; + } + + kj::Maybe>> whenMoreResolved() override { + return nullptr; + } + + private: + kj::Own inner; + }; + + kj::Maybe writeDescriptor(ClientHook& cap, rpc::CapDescriptor::Builder descriptor) { + // Write a descriptor for the given capability. + + // Find the innermost wrapped capability. + ClientHook* inner = ∩ + for (;;) { + KJ_IF_MAYBE(resolved, inner->getResolved()) { + inner = resolved; + } else { + break; + } + } + + if (inner->getBrand() == this) { + return kj::downcast(*inner).writeDescriptor(descriptor); + } else { + auto iter = exportsByCap.find(inner); + if (iter != exportsByCap.end()) { + // We've already seen and exported this capability before. Just up the refcount. + auto& exp = KJ_ASSERT_NONNULL(exports.find(iter->second)); + ++exp.refcount; + descriptor.setSenderHosted(iter->second); + return iter->second; + } else { + // This is the first time we've seen this capability. + ExportId exportId; + auto& exp = exports.next(exportId); + exportsByCap[inner] = exportId; + exp.refcount = 1; + exp.clientHook = inner->addRef(); + + KJ_IF_MAYBE(wrapped, inner->whenMoreResolved()) { + // This is a promise. Arrange for the `Resolve` message to be sent later. + exp.resolveOp = resolveExportedPromise(exportId, kj::mv(*wrapped)); + descriptor.setSenderPromise(exportId); + } else { + descriptor.setSenderHosted(exportId); + } + + return exportId; + } + } + } + + kj::Array writeDescriptors(kj::ArrayPtr>> capTable, + rpc::Payload::Builder payload) { + auto capTableBuilder = payload.initCapTable(capTable.size()); + kj::Vector exports(capTable.size()); + for (uint i: kj::indices(capTable)) { + KJ_IF_MAYBE(cap, capTable[i]) { + KJ_IF_MAYBE(exportId, writeDescriptor(**cap, capTableBuilder[i])) { + exports.add(*exportId); + } + } else { + capTableBuilder[i].setNone(); + } + } + return exports.releaseAsArray(); + } + + kj::Maybe> writeTarget(ClientHook& cap, rpc::MessageTarget::Builder target) { + // If calls to the given capability should pass over this connection, fill in `target` + // appropriately for such a call and return nullptr. Otherwise, return a `ClientHook` to which + // the call should be forwarded; the caller should then delegate the call to that `ClientHook`. + // + // The main case where this ends up returning non-null is if `cap` is a promise that has + // recently resolved. The application might have started building a request before the promise + // resolved, and so the request may have been built on the assumption that it would be sent over + // this network connection, but then the promise resolved to point somewhere else before the + // request was sent. Now the request has to be redirected to the new target instead. + + if (cap.getBrand() == this) { + return kj::downcast(cap).writeTarget(target); + } else { + return cap.addRef(); + } + } + + kj::Own getInnermostClient(ClientHook& client) { + ClientHook* ptr = &client; + for (;;) { + KJ_IF_MAYBE(inner, ptr->getResolved()) { + ptr = inner; + } else { + break; + } + } + + if (ptr->getBrand() == this) { + return kj::downcast(*ptr).getInnermostClient(); + } else { + return ptr->addRef(); + } + } + + kj::Promise resolveExportedPromise( + ExportId exportId, kj::Promise>&& promise) { + // Implements exporting of a promise. The promise has been exported under the given ID, and is + // to eventually resolve to the ClientHook produced by `promise`. This method waits for that + // resolve to happen and then sends the appropriate `Resolve` message to the peer. + + return promise.then( + [this,exportId](kj::Own&& resolution) -> kj::Promise { + // Successful resolution. + + KJ_ASSERT(connection.is(), + "Resolving export should have been canceled on disconnect.") { + return kj::READY_NOW; + } + + // Get the innermost ClientHook backing the resolved client. This includes traversing + // PromiseClients that haven't resolved yet to their underlying ImportClient or + // PipelineClient, so that we get a remote promise that might resolve later. This is + // important to make sure that if the peer sends a `Disembargo` back to us, it bounces back + // correctly instead of going to the result of some future resolution. See the documentation + // for `Disembargo` in `rpc.capnp`. + resolution = getInnermostClient(*resolution); + + // Update the export table to point at this object instead. We know that our entry in the + // export table is still live because when it is destroyed the asynchronous resolution task + // (i.e. this code) is canceled. + auto& exp = KJ_ASSERT_NONNULL(exports.find(exportId)); + exportsByCap.erase(exp.clientHook); + exp.clientHook = kj::mv(resolution); + + if (exp.clientHook->getBrand() != this) { + // We're resolving to a local capability. If we're resolving to a promise, we might be + // able to reuse our export table entry and avoid sending a message. + + KJ_IF_MAYBE(promise, exp.clientHook->whenMoreResolved()) { + // We're replacing a promise with another local promise. In this case, we might actually + // be able to just reuse the existing export table entry to represent the new promise -- + // unless it already has an entry. Let's check. + + auto insertResult = exportsByCap.insert(std::make_pair(exp.clientHook.get(), exportId)); + + if (insertResult.second) { + // The new promise was not already in the table, therefore the existing export table + // entry has now been repurposed to represent it. There is no need to send a resolve + // message at all. We do, however, have to start resolving the next promise. + return resolveExportedPromise(exportId, kj::mv(*promise)); + } + } + } + + // OK, we have to send a `Resolve` message. + auto message = connection.get()->newOutgoingMessage( + messageSizeHint() + sizeInWords() + 16); + auto resolve = message->getBody().initAs().initResolve(); + resolve.setPromiseId(exportId); + writeDescriptor(*exp.clientHook, resolve.initCap()); + message->send(); + + return kj::READY_NOW; + }, [this,exportId](kj::Exception&& exception) { + // send error resolution + auto message = connection.get()->newOutgoingMessage( + messageSizeHint() + exceptionSizeHint(exception) + 8); + auto resolve = message->getBody().initAs().initResolve(); + resolve.setPromiseId(exportId); + fromException(exception, resolve.initException()); + message->send(); + }).eagerlyEvaluate([this](kj::Exception&& exception) { + // Put the exception on the TaskSet which will cause the connection to be terminated. + tasks.add(kj::mv(exception)); + }); + } + + // ===================================================================================== + // Interpreting CapDescriptor + + kj::Own import(ImportId importId, bool isPromise) { + // Receive a new import. + + auto& import = imports[importId]; + kj::Own importClient; + + // Create the ImportClient, or if one already exists, use it. + KJ_IF_MAYBE(c, import.importClient) { + importClient = kj::addRef(*c); + } else { + importClient = kj::refcounted(*this, importId); + import.importClient = *importClient; + } + + // We just received a copy of this import ID, so the remote refcount has gone up. + importClient->addRemoteRef(); + + if (isPromise) { + // We need to construct a PromiseClient around this import, if we haven't already. + KJ_IF_MAYBE(c, import.appClient) { + // Use the existing one. + return kj::addRef(*c); + } else { + // Create a promise for this import's resolution. + auto paf = kj::newPromiseAndFulfiller>(); + import.promiseFulfiller = kj::mv(paf.fulfiller); + + // Make sure the import is not destroyed while this promise exists. + paf.promise = paf.promise.attach(kj::addRef(*importClient)); + + // Create a PromiseClient around it and return it. + auto result = kj::refcounted( + *this, kj::mv(importClient), kj::mv(paf.promise), importId); + import.appClient = *result; + return kj::mv(result); + } + } else { + import.appClient = *importClient; + return kj::mv(importClient); + } + } + + kj::Maybe> receiveCap(rpc::CapDescriptor::Reader descriptor) { + switch (descriptor.which()) { + case rpc::CapDescriptor::NONE: + return nullptr; + + case rpc::CapDescriptor::SENDER_HOSTED: + return import(descriptor.getSenderHosted(), false); + case rpc::CapDescriptor::SENDER_PROMISE: + return import(descriptor.getSenderPromise(), true); + + case rpc::CapDescriptor::RECEIVER_HOSTED: + KJ_IF_MAYBE(exp, exports.find(descriptor.getReceiverHosted())) { + return exp->clientHook->addRef(); + } else { + return newBrokenCap("invalid 'receiverHosted' export ID"); + } + + case rpc::CapDescriptor::RECEIVER_ANSWER: { + auto promisedAnswer = descriptor.getReceiverAnswer(); + + KJ_IF_MAYBE(answer, answers.find(promisedAnswer.getQuestionId())) { + if (answer->active) { + KJ_IF_MAYBE(pipeline, answer->pipeline) { + KJ_IF_MAYBE(ops, toPipelineOps(promisedAnswer.getTransform())) { + return pipeline->get()->getPipelinedCap(*ops); + } else { + return newBrokenCap("unrecognized pipeline ops"); + } + } + } + } + + return newBrokenCap("invalid 'receiverAnswer'"); + } + + case rpc::CapDescriptor::THIRD_PARTY_HOSTED: + // We don't support third-party caps, so use the vine instead. + return import(descriptor.getThirdPartyHosted().getVineId(), false); + + default: + KJ_FAIL_REQUIRE("unknown CapDescriptor type") { break; } + return newBrokenCap("unknown CapDescriptor type"); + } + } + + kj::Array>> receiveCaps(List::Reader capTable) { + auto result = kj::heapArrayBuilder>>(capTable.size()); + for (auto cap: capTable) { + result.add(receiveCap(cap)); + } + return result.finish(); + } + + // ===================================================================================== + // RequestHook/PipelineHook/ResponseHook implementations + + class QuestionRef: public kj::Refcounted { + // A reference to an entry on the question table. Used to detect when the `Finish` message + // can be sent. + + public: + inline QuestionRef( + RpcConnectionState& connectionState, QuestionId id, + kj::Own>>> fulfiller) + : connectionState(kj::addRef(connectionState)), id(id), fulfiller(kj::mv(fulfiller)) {} + + ~QuestionRef() { + unwindDetector.catchExceptionsIfUnwinding([&]() { + auto& question = KJ_ASSERT_NONNULL( + connectionState->questions.find(id), "Question ID no longer on table?"); + + // Send the "Finish" message (if the connection is not already broken). + if (connectionState->connection.is() && !question.skipFinish) { + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint()); + auto builder = message->getBody().getAs().initFinish(); + builder.setQuestionId(id); + // If we're still awaiting a return, then this request is being canceled, and we're going + // to ignore any capabilities in the return message, so set releaseResultCaps true. If we + // already received the return, then we've already built local proxies for the caps and + // will send Release messages when those are destroyed. + builder.setReleaseResultCaps(question.isAwaitingReturn); + message->send(); + } + + // Check if the question has returned and, if so, remove it from the table. + // Remove question ID from the table. Must do this *after* sending `Finish` to ensure that + // the ID is not re-allocated before the `Finish` message can be sent. + if (question.isAwaitingReturn) { + // Still waiting for return, so just remove the QuestionRef pointer from the table. + question.selfRef = nullptr; + } else { + // Call has already returned, so we can now remove it from the table. + connectionState->questions.erase(id, question); + } + }); + } + + inline QuestionId getId() const { return id; } + + void fulfill(kj::Own&& response) { + fulfiller->fulfill(kj::mv(response)); + } + + void fulfill(kj::Promise>&& promise) { + fulfiller->fulfill(kj::mv(promise)); + } + + void reject(kj::Exception&& exception) { + fulfiller->reject(kj::mv(exception)); + } + + private: + kj::Own connectionState; + QuestionId id; + kj::Own>>> fulfiller; + kj::UnwindDetector unwindDetector; + }; + + class RpcRequest final: public RequestHook { + public: + RpcRequest(RpcConnectionState& connectionState, VatNetworkBase::Connection& connection, + kj::Maybe sizeHint, kj::Own&& target) + : connectionState(kj::addRef(connectionState)), + target(kj::mv(target)), + message(connection.newOutgoingMessage( + firstSegmentSize(sizeHint, messageSizeHint() + + sizeInWords() + MESSAGE_TARGET_SIZE_HINT))), + callBuilder(message->getBody().getAs().initCall()), + paramsBuilder(capTable.imbue(callBuilder.getParams().getContent())) {} + + inline AnyPointer::Builder getRoot() { + return paramsBuilder; + } + inline rpc::Call::Builder getCall() { + return callBuilder; + } + + RemotePromise send() override { + if (!connectionState->connection.is()) { + // Connection is broken. + const kj::Exception& e = connectionState->connection.get(); + return RemotePromise( + kj::Promise>(kj::cp(e)), + AnyPointer::Pipeline(newBrokenPipeline(kj::cp(e)))); + } + + KJ_IF_MAYBE(redirect, target->writeTarget(callBuilder.getTarget())) { + // Whoops, this capability has been redirected while we were building the request! + // We'll have to make a new request and do a copy. Ick. + + auto replacement = redirect->get()->newCall( + callBuilder.getInterfaceId(), callBuilder.getMethodId(), paramsBuilder.targetSize()); + replacement.set(paramsBuilder); + return replacement.send(); + } else { + auto sendResult = sendInternal(false); + + auto forkedPromise = sendResult.promise.fork(); + + // The pipeline must get notified of resolution before the app does to maintain ordering. + auto pipeline = kj::refcounted( + *connectionState, kj::mv(sendResult.questionRef), forkedPromise.addBranch()); + + auto appPromise = forkedPromise.addBranch().then( + [=](kj::Own&& response) { + auto reader = response->getResults(); + return Response(reader, kj::mv(response)); + }); + + return RemotePromise( + kj::mv(appPromise), + AnyPointer::Pipeline(kj::mv(pipeline))); + } + } + + struct TailInfo { + QuestionId questionId; + kj::Promise promise; + kj::Own pipeline; + }; + + kj::Maybe tailSend() { + // Send the request as a tail call. + // + // Returns null if for some reason a tail call is not possible and the caller should fall + // back to using send() and copying the response. + + SendInternalResult sendResult; + + if (!connectionState->connection.is()) { + // Disconnected; fall back to a regular send() which will fail appropriately. + return nullptr; + } + + KJ_IF_MAYBE(redirect, target->writeTarget(callBuilder.getTarget())) { + // Whoops, this capability has been redirected while we were building the request! + // Fall back to regular send(). + return nullptr; + } else { + sendResult = sendInternal(true); + } + + auto promise = sendResult.promise.then([](kj::Own&& response) { + // Response should be null if `Return` handling code is correct. + KJ_ASSERT(!response) { break; } + }); + + QuestionId questionId = sendResult.questionRef->getId(); + + auto pipeline = kj::refcounted(*connectionState, kj::mv(sendResult.questionRef)); + + return TailInfo { questionId, kj::mv(promise), kj::mv(pipeline) }; + } + + const void* getBrand() override { + return connectionState.get(); + } + + private: + kj::Own connectionState; + + kj::Own target; + kj::Own message; + BuilderCapabilityTable capTable; + rpc::Call::Builder callBuilder; + AnyPointer::Builder paramsBuilder; + + struct SendInternalResult { + kj::Own questionRef; + kj::Promise> promise = nullptr; + }; + + SendInternalResult sendInternal(bool isTailCall) { + // Build the cap table. + auto exports = connectionState->writeDescriptors( + capTable.getTable(), callBuilder.getParams()); + + // Init the question table. Do this after writing descriptors to avoid interference. + QuestionId questionId; + auto& question = connectionState->questions.next(questionId); + question.isAwaitingReturn = true; + question.paramExports = kj::mv(exports); + question.isTailCall = isTailCall; + + // Make the QuentionRef and result promise. + SendInternalResult result; + auto paf = kj::newPromiseAndFulfiller>>(); + result.questionRef = kj::refcounted( + *connectionState, questionId, kj::mv(paf.fulfiller)); + question.selfRef = *result.questionRef; + result.promise = paf.promise.attach(kj::addRef(*result.questionRef)); + + // Finish and send. + callBuilder.setQuestionId(questionId); + if (isTailCall) { + callBuilder.getSendResultsTo().setYourself(); + } + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + KJ_CONTEXT("sending RPC call", + callBuilder.getInterfaceId(), callBuilder.getMethodId()); + message->send(); + })) { + // We can't safely throw the exception from here since we've already modified the question + // table state. We'll have to reject the promise instead. + question.isAwaitingReturn = false; + question.skipFinish = true; + result.questionRef->reject(kj::mv(*exception)); + } + + // Send and return. + return kj::mv(result); + } + }; + + class RpcPipeline final: public PipelineHook, public kj::Refcounted { + public: + RpcPipeline(RpcConnectionState& connectionState, kj::Own&& questionRef, + kj::Promise>&& redirectLaterParam) + : connectionState(kj::addRef(connectionState)), + redirectLater(redirectLaterParam.fork()), + resolveSelfPromise(KJ_ASSERT_NONNULL(redirectLater).addBranch().then( + [this](kj::Own&& response) { + resolve(kj::mv(response)); + }, [this](kj::Exception&& exception) { + resolve(kj::mv(exception)); + }).eagerlyEvaluate([&](kj::Exception&& e) { + // Make any exceptions thrown from resolve() go to the connection's TaskSet which + // will cause the connection to be terminated. + connectionState.tasks.add(kj::mv(e)); + })) { + // Construct a new RpcPipeline. + + state.init(kj::mv(questionRef)); + } + + RpcPipeline(RpcConnectionState& connectionState, kj::Own&& questionRef) + : connectionState(kj::addRef(connectionState)), + resolveSelfPromise(nullptr) { + // Construct a new RpcPipeline that is never expected to resolve. + + state.init(kj::mv(questionRef)); + } + + // implements PipelineHook --------------------------------------- + + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) override { + auto copy = kj::heapArrayBuilder(ops.size()); + for (auto& op: ops) { + copy.add(op); + } + return getPipelinedCap(copy.finish()); + } + + kj::Own getPipelinedCap(kj::Array&& ops) override { + if (state.is()) { + // Wrap a PipelineClient in a PromiseClient. + auto pipelineClient = kj::refcounted( + *connectionState, kj::addRef(*state.get()), kj::heapArray(ops.asPtr())); + + KJ_IF_MAYBE(r, redirectLater) { + auto resolutionPromise = r->addBranch().then(kj::mvCapture(ops, + [](kj::Array ops, kj::Own&& response) { + return response->getResults().getPipelinedCap(ops); + })); + + return kj::refcounted( + *connectionState, kj::mv(pipelineClient), kj::mv(resolutionPromise), nullptr); + } else { + // Oh, this pipeline will never get redirected, so just return the PipelineClient. + return kj::mv(pipelineClient); + } + } else if (state.is()) { + return state.get()->getResults().getPipelinedCap(ops); + } else { + return newBrokenCap(kj::cp(state.get())); + } + } + + private: + kj::Own connectionState; + kj::Maybe>> redirectLater; + + typedef kj::Own Waiting; + typedef kj::Own Resolved; + typedef kj::Exception Broken; + kj::OneOf state; + + // Keep this last, because the continuation uses *this, so it should be destroyed first to + // ensure the continuation is not still running. + kj::Promise resolveSelfPromise; + + void resolve(kj::Own&& response) { + KJ_ASSERT(state.is(), "Already resolved?"); + state.init(kj::mv(response)); + } + + void resolve(const kj::Exception&& exception) { + KJ_ASSERT(state.is(), "Already resolved?"); + state.init(kj::mv(exception)); + } + }; + + class RpcResponse: public ResponseHook { + public: + virtual AnyPointer::Reader getResults() = 0; + virtual kj::Own addRef() = 0; + }; + + class RpcResponseImpl final: public RpcResponse, public kj::Refcounted { + public: + RpcResponseImpl(RpcConnectionState& connectionState, + kj::Own&& questionRef, + kj::Own&& message, + kj::Array>> capTableArray, + AnyPointer::Reader results) + : connectionState(kj::addRef(connectionState)), + message(kj::mv(message)), + capTable(kj::mv(capTableArray)), + reader(capTable.imbue(results)), + questionRef(kj::mv(questionRef)) {} + + AnyPointer::Reader getResults() override { + return reader; + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + private: + kj::Own connectionState; + kj::Own message; + ReaderCapabilityTable capTable; + AnyPointer::Reader reader; + kj::Own questionRef; + }; + + // ===================================================================================== + // CallContextHook implementation + + class RpcServerResponse { + public: + virtual AnyPointer::Builder getResultsBuilder() = 0; + }; + + class RpcServerResponseImpl final: public RpcServerResponse { + public: + RpcServerResponseImpl(RpcConnectionState& connectionState, + kj::Own&& message, + rpc::Payload::Builder payload) + : connectionState(connectionState), + message(kj::mv(message)), + payload(payload) {} + + AnyPointer::Builder getResultsBuilder() override { + return capTable.imbue(payload.getContent()); + } + + kj::Maybe> send() { + // Send the response and return the export list. Returns nullptr if there were no caps. + // (Could return a non-null empty array if there were caps but none of them were exports.) + + // Build the cap table. + auto capTable = this->capTable.getTable(); + auto exports = connectionState.writeDescriptors(capTable, payload); + + // Capabilities that we are returning are subject to embargos. See `Disembargo` in rpc.capnp. + // As explained there, in order to deal with the Tribble 4-way race condition, we need to + // make sure that if we're returning any remote promises, that we ignore any subsequent + // resolution of those promises for the purpose of pipelined requests on this answer. Luckily, + // we can modify the cap table in-place. + for (auto& slot: capTable) { + KJ_IF_MAYBE(cap, slot) { + slot = connectionState.getInnermostClient(**cap); + } + } + + message->send(); + if (capTable.size() == 0) { + return nullptr; + } else { + return kj::mv(exports); + } + } + + private: + RpcConnectionState& connectionState; + kj::Own message; + BuilderCapabilityTable capTable; + rpc::Payload::Builder payload; + }; + + class LocallyRedirectedRpcResponse final + : public RpcResponse, public RpcServerResponse, public kj::Refcounted{ + public: + LocallyRedirectedRpcResponse(kj::Maybe sizeHint) + : message(sizeHint.map([](MessageSize size) { return size.wordCount; }) + .orDefault(SUGGESTED_FIRST_SEGMENT_WORDS)) {} + + AnyPointer::Builder getResultsBuilder() override { + return message.getRoot(); + } + + AnyPointer::Reader getResults() override { + return message.getRoot(); + } + + kj::Own addRef() override { + return kj::addRef(*this); + } + + private: + MallocMessageBuilder message; + }; + + class RpcCallContext final: public CallContextHook, public kj::Refcounted { + public: + RpcCallContext(RpcConnectionState& connectionState, AnswerId answerId, + kj::Own&& request, + kj::Array>> capTableArray, + const AnyPointer::Reader& params, + bool redirectResults, kj::Own>&& cancelFulfiller, + uint64_t interfaceId, uint16_t methodId) + : connectionState(kj::addRef(connectionState)), + answerId(answerId), + interfaceId(interfaceId), + methodId(methodId), + requestSize(request->getBody().targetSize().wordCount), + request(kj::mv(request)), + paramsCapTable(kj::mv(capTableArray)), + params(paramsCapTable.imbue(params)), + returnMessage(nullptr), + redirectResults(redirectResults), + cancelFulfiller(kj::mv(cancelFulfiller)) { + connectionState.callWordsInFlight += requestSize; + } + + ~RpcCallContext() noexcept(false) { + if (isFirstResponder()) { + // We haven't sent a return yet, so we must have been canceled. Send a cancellation return. + unwindDetector.catchExceptionsIfUnwinding([&]() { + // Don't send anything if the connection is broken. + if (connectionState->connection.is()) { + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint() + sizeInWords()); + auto builder = message->getBody().initAs().initReturn(); + + builder.setAnswerId(answerId); + builder.setReleaseParamCaps(false); + + if (redirectResults) { + // The reason we haven't sent a return is because the results were sent somewhere + // else. + builder.setResultsSentElsewhere(); + } else { + builder.setCanceled(); + } + + message->send(); + } + + cleanupAnswerTable(nullptr, true); + }); + } + } + + kj::Own consumeRedirectedResponse() { + KJ_ASSERT(redirectResults); + + if (response == nullptr) getResults(MessageSize{0, 0}); // force initialization of response + + // Note that the context needs to keep its own reference to the response so that it doesn't + // get GC'd until the PipelineHook drops its reference to the context. + return kj::downcast(*KJ_ASSERT_NONNULL(response)).addRef(); + } + + void sendReturn() { + KJ_ASSERT(!redirectResults); + + // Avoid sending results if canceled so that we don't have to figure out whether or not + // `releaseResultCaps` was set in the already-received `Finish`. + if (!(cancellationFlags & CANCEL_REQUESTED) && isFirstResponder()) { + KJ_ASSERT(connectionState->connection.is(), + "Cancellation should have been requested on disconnect.") { + return; + } + + if (response == nullptr) getResults(MessageSize{0, 0}); // force initialization of response + + returnMessage.setAnswerId(answerId); + returnMessage.setReleaseParamCaps(false); + + kj::Maybe> exports; + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + // Debug info incase send() fails due to overside message. + KJ_CONTEXT("returning from RPC call", interfaceId, methodId); + exports = kj::downcast(*KJ_ASSERT_NONNULL(response)).send(); + })) { + responseSent = false; + sendErrorReturn(kj::mv(*exception)); + return; + } + + KJ_IF_MAYBE(e, exports) { + // Caps were returned, so we can't free the pipeline yet. + cleanupAnswerTable(kj::mv(*e), false); + } else { + // No caps in the results, therefore the pipeline is irrelevant. + cleanupAnswerTable(nullptr, true); + } + } + } + void sendErrorReturn(kj::Exception&& exception) { + KJ_ASSERT(!redirectResults); + if (isFirstResponder()) { + if (connectionState->connection.is()) { + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint() + exceptionSizeHint(exception)); + auto builder = message->getBody().initAs().initReturn(); + + builder.setAnswerId(answerId); + builder.setReleaseParamCaps(false); + fromException(exception, builder.initException()); + + message->send(); + } + + // Do not allow releasing the pipeline because we want pipelined calls to propagate the + // exception rather than fail with a "no such field" exception. + cleanupAnswerTable(nullptr, false); + } + } + + void requestCancel() { + // Hints that the caller wishes to cancel this call. At the next time when cancellation is + // deemed safe, the RpcCallContext shall send a canceled Return -- or if it never becomes + // safe, the RpcCallContext will send a normal return when the call completes. Either way + // the RpcCallContext is now responsible for cleaning up the entry in the answer table, since + // a Finish message was already received. + + bool previouslyAllowedButNotRequested = cancellationFlags == CANCEL_ALLOWED; + cancellationFlags |= CANCEL_REQUESTED; + + if (previouslyAllowedButNotRequested) { + // We just set CANCEL_REQUESTED, and CANCEL_ALLOWED was already set previously. Initiate + // the cancellation. + cancelFulfiller->fulfill(); + } + } + + // implements CallContextHook ------------------------------------ + + AnyPointer::Reader getParams() override { + KJ_REQUIRE(request != nullptr, "Can't call getParams() after releaseParams()."); + return params; + } + void releaseParams() override { + request = nullptr; + } + AnyPointer::Builder getResults(kj::Maybe sizeHint) override { + KJ_IF_MAYBE(r, response) { + return r->get()->getResultsBuilder(); + } else { + kj::Own response; + + if (redirectResults || !connectionState->connection.is()) { + response = kj::refcounted(sizeHint); + } else { + auto message = connectionState->connection.get()->newOutgoingMessage( + firstSegmentSize(sizeHint, messageSizeHint() + + sizeInWords())); + returnMessage = message->getBody().initAs().initReturn(); + response = kj::heap( + *connectionState, kj::mv(message), returnMessage.getResults()); + } + + auto results = response->getResultsBuilder(); + this->response = kj::mv(response); + return results; + } + } + kj::Promise tailCall(kj::Own&& request) override { + auto result = directTailCall(kj::mv(request)); + KJ_IF_MAYBE(f, tailCallPipelineFulfiller) { + f->get()->fulfill(AnyPointer::Pipeline(kj::mv(result.pipeline))); + } + return kj::mv(result.promise); + } + ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own&& request) override { + KJ_REQUIRE(response == nullptr, + "Can't call tailCall() after initializing the results struct."); + + if (request->getBrand() == connectionState.get() && !redirectResults) { + // The tail call is headed towards the peer that called us in the first place, so we can + // optimize out the return trip. + + KJ_IF_MAYBE(tailInfo, kj::downcast(*request).tailSend()) { + if (isFirstResponder()) { + if (connectionState->connection.is()) { + auto message = connectionState->connection.get()->newOutgoingMessage( + messageSizeHint()); + auto builder = message->getBody().initAs().initReturn(); + + builder.setAnswerId(answerId); + builder.setReleaseParamCaps(false); + builder.setTakeFromOtherQuestion(tailInfo->questionId); + + message->send(); + } + + // There are no caps in our return message, but of course the tail results could have + // caps, so we must continue to honor pipeline calls (and just bounce them back). + cleanupAnswerTable(nullptr, false); + } + return { kj::mv(tailInfo->promise), kj::mv(tailInfo->pipeline) }; + } + } + + // Just forwarding to another local call. + auto promise = request->send(); + + // Wait for response. + auto voidPromise = promise.then([this](Response&& tailResponse) { + // Copy the response. + // TODO(perf): It would be nice if we could somehow make the response get built in-place + // but requires some refactoring. + getResults(tailResponse.targetSize()).set(tailResponse); + }); + + return { kj::mv(voidPromise), PipelineHook::from(kj::mv(promise)) }; + } + kj::Promise onTailCall() override { + auto paf = kj::newPromiseAndFulfiller(); + tailCallPipelineFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); + } + void allowCancellation() override { + bool previouslyRequestedButNotAllowed = cancellationFlags == CANCEL_REQUESTED; + cancellationFlags |= CANCEL_ALLOWED; + + if (previouslyRequestedButNotAllowed) { + // We just set CANCEL_ALLOWED, and CANCEL_REQUESTED was already set previously. Initiate + // the cancellation. + cancelFulfiller->fulfill(); + } + } + kj::Own addRef() override { + return kj::addRef(*this); + } + + private: + kj::Own connectionState; + AnswerId answerId; + + uint64_t interfaceId; + uint16_t methodId; + // For debugging. + + // Request --------------------------------------------- + + size_t requestSize; // for flow limit purposes + kj::Maybe> request; + ReaderCapabilityTable paramsCapTable; + AnyPointer::Reader params; + + // Response -------------------------------------------- + + kj::Maybe> response; + rpc::Return::Builder returnMessage; + bool redirectResults = false; + bool responseSent = false; + kj::Maybe>> tailCallPipelineFulfiller; + + // Cancellation state ---------------------------------- + + enum CancellationFlags { + CANCEL_REQUESTED = 1, + CANCEL_ALLOWED = 2 + }; + + uint8_t cancellationFlags = 0; + // When both flags are set, the cancellation process will begin. + + kj::Own> cancelFulfiller; + // Fulfilled when cancellation has been both requested and permitted. The fulfilled promise is + // exclusive-joined with the outermost promise waiting on the call return, so fulfilling it + // cancels that promise. + + kj::UnwindDetector unwindDetector; + + // ----------------------------------------------------- + + bool isFirstResponder() { + if (responseSent) { + return false; + } else { + responseSent = true; + return true; + } + } + + void cleanupAnswerTable(kj::Array resultExports, bool shouldFreePipeline) { + // We need to remove the `callContext` pointer -- which points back to us -- from the + // answer table. Or we might even be responsible for removing the entire answer table + // entry. + + if (cancellationFlags & CANCEL_REQUESTED) { + // Already received `Finish` so it's our job to erase the table entry. We shouldn't have + // sent results if canceled, so we shouldn't have an export list to deal with. + KJ_ASSERT(resultExports.size() == 0); + connectionState->answers.erase(answerId); + } else { + // We just have to null out callContext and set the exports. + auto& answer = connectionState->answers[answerId]; + answer.callContext = nullptr; + answer.resultExports = kj::mv(resultExports); + + if (shouldFreePipeline) { + // We can free the pipeline early, because we know all pipeline calls are invalid (e.g. + // because there are no caps in the result to receive pipeline requests). + KJ_ASSERT(resultExports.size() == 0); + answer.pipeline = nullptr; + } + } + + // Also, this is the right time to stop counting the call against the flow limit. + connectionState->callWordsInFlight -= requestSize; + connectionState->maybeUnblockFlow(); + } + }; + + // ===================================================================================== + // Message handling + + void maybeUnblockFlow() { + if (callWordsInFlight < flowLimit) { + KJ_IF_MAYBE(w, flowWaiter) { + w->get()->fulfill(); + flowWaiter = nullptr; + } + } + } + + kj::Promise messageLoop() { + if (!connection.is()) { + return kj::READY_NOW; + } + + if (callWordsInFlight > flowLimit) { + auto paf = kj::newPromiseAndFulfiller(); + flowWaiter = kj::mv(paf.fulfiller); + return paf.promise.then([this]() { + return messageLoop(); + }); + } + + return connection.get()->receiveIncomingMessage().then( + [this](kj::Maybe>&& message) { + KJ_IF_MAYBE(m, message) { + handleMessage(kj::mv(*m)); + return true; + } else { + disconnect(KJ_EXCEPTION(DISCONNECTED, "Peer disconnected.")); + return false; + } + }).then([this](bool keepGoing) { + // No exceptions; continue loop. + // + // (We do this in a separate continuation to handle the case where exceptions are + // disabled.) + if (keepGoing) tasks.add(messageLoop()); + }); + } + + void handleMessage(kj::Own message) { + auto reader = message->getBody().getAs(); + + switch (reader.which()) { + case rpc::Message::UNIMPLEMENTED: + handleUnimplemented(reader.getUnimplemented()); + break; + + case rpc::Message::ABORT: + handleAbort(reader.getAbort()); + break; + + case rpc::Message::BOOTSTRAP: + handleBootstrap(kj::mv(message), reader.getBootstrap()); + break; + + case rpc::Message::CALL: + handleCall(kj::mv(message), reader.getCall()); + break; + + case rpc::Message::RETURN: + handleReturn(kj::mv(message), reader.getReturn()); + break; + + case rpc::Message::FINISH: + handleFinish(reader.getFinish()); + break; + + case rpc::Message::RESOLVE: + handleResolve(reader.getResolve()); + break; + + case rpc::Message::RELEASE: + handleRelease(reader.getRelease()); + break; + + case rpc::Message::DISEMBARGO: + handleDisembargo(reader.getDisembargo()); + break; + + default: { + if (connection.is()) { + auto message = connection.get()->newOutgoingMessage( + firstSegmentSize(reader.totalSize(), messageSizeHint())); + message->getBody().initAs().setUnimplemented(reader); + message->send(); + } + break; + } + } + } + + void handleUnimplemented(const rpc::Message::Reader& message) { + switch (message.which()) { + case rpc::Message::RESOLVE: { + auto resolve = message.getResolve(); + switch (resolve.which()) { + case rpc::Resolve::CAP: { + auto cap = resolve.getCap(); + switch (cap.which()) { + case rpc::CapDescriptor::NONE: + // Nothing to do (but this ought never to happen). + break; + case rpc::CapDescriptor::SENDER_HOSTED: + releaseExport(cap.getSenderHosted(), 1); + break; + case rpc::CapDescriptor::SENDER_PROMISE: + releaseExport(cap.getSenderPromise(), 1); + break; + case rpc::CapDescriptor::RECEIVER_ANSWER: + case rpc::CapDescriptor::RECEIVER_HOSTED: + // Nothing to do. + break; + case rpc::CapDescriptor::THIRD_PARTY_HOSTED: + releaseExport(cap.getThirdPartyHosted().getVineId(), 1); + break; + } + break; + } + case rpc::Resolve::EXCEPTION: + // Nothing to do. + break; + } + break; + } + + default: + KJ_FAIL_ASSERT("Peer did not implement required RPC message type.", (uint)message.which()); + break; + } + } + + void handleAbort(const rpc::Exception::Reader& exception) { + kj::throwRecoverableException(toException(exception)); + } + + // --------------------------------------------------------------------------- + // Level 0 + + class SingleCapPipeline: public PipelineHook, public kj::Refcounted { + public: + SingleCapPipeline(kj::Own&& cap) + : cap(kj::mv(cap)) {} + + kj::Own addRef() override { + return kj::addRef(*this); + } + + kj::Own getPipelinedCap(kj::ArrayPtr ops) override { + if (ops.size() == 0) { + return cap->addRef(); + } else { + return newBrokenCap("Invalid pipeline transform."); + } + } + + private: + kj::Own cap; + }; + + void handleBootstrap(kj::Own&& message, + const rpc::Bootstrap::Reader& bootstrap) { + AnswerId answerId = bootstrap.getQuestionId(); + + if (!connection.is()) { + // Disconnected; ignore. + return; + } + + VatNetworkBase::Connection& conn = *connection.get(); + auto response = conn.newOutgoingMessage( + messageSizeHint() + sizeInWords() + 32); + + rpc::Return::Builder ret = response->getBody().getAs().initReturn(); + ret.setAnswerId(answerId); + + kj::Own capHook; + kj::Array resultExports; + KJ_DEFER(releaseExports(resultExports)); // in case something goes wrong + + // Call the restorer and initialize the answer. + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + Capability::Client cap = nullptr; + + if (bootstrap.hasDeprecatedObjectId()) { + KJ_IF_MAYBE(r, restorer) { + cap = r->baseRestore(bootstrap.getDeprecatedObjectId()); + } else { + KJ_FAIL_REQUIRE("This vat only supports a bootstrap interface, not the old " + "Cap'n-Proto-0.4-style named exports.") { return; } + } + } else { + cap = bootstrapFactory.baseCreateFor(conn.baseGetPeerVatId()); + } + + BuilderCapabilityTable capTable; + auto payload = ret.initResults(); + capTable.imbue(payload.getContent()).setAs(kj::mv(cap)); + + auto capTableArray = capTable.getTable(); + KJ_DASSERT(capTableArray.size() == 1); + resultExports = writeDescriptors(capTableArray, payload); + capHook = KJ_ASSERT_NONNULL(capTableArray[0])->addRef(); + })) { + fromException(*exception, ret.initException()); + capHook = newBrokenCap(kj::mv(*exception)); + } + + message = nullptr; + + // Add the answer to the answer table for pipelining and send the response. + auto& answer = answers[answerId]; + KJ_REQUIRE(!answer.active, "questionId is already in use", answerId) { + return; + } + + answer.resultExports = kj::mv(resultExports); + answer.active = true; + answer.pipeline = kj::Own(kj::refcounted(kj::mv(capHook))); + + response->send(); + } + + void handleCall(kj::Own&& message, const rpc::Call::Reader& call) { + kj::Own capability; + + KJ_IF_MAYBE(t, getMessageTarget(call.getTarget())) { + capability = kj::mv(*t); + } else { + // Exception already reported. + return; + } + + bool redirectResults; + switch (call.getSendResultsTo().which()) { + case rpc::Call::SendResultsTo::CALLER: + redirectResults = false; + break; + case rpc::Call::SendResultsTo::YOURSELF: + redirectResults = true; + break; + default: + KJ_FAIL_REQUIRE("Unsupported `Call.sendResultsTo`.") { return; } + } + + auto payload = call.getParams(); + auto capTableArray = receiveCaps(payload.getCapTable()); + auto cancelPaf = kj::newPromiseAndFulfiller(); + + AnswerId answerId = call.getQuestionId(); + + auto context = kj::refcounted( + *this, answerId, kj::mv(message), kj::mv(capTableArray), payload.getContent(), + redirectResults, kj::mv(cancelPaf.fulfiller), + call.getInterfaceId(), call.getMethodId()); + + // No more using `call` after this point, as it now belongs to the context. + + { + auto& answer = answers[answerId]; + + KJ_REQUIRE(!answer.active, "questionId is already in use") { + return; + } + + answer.active = true; + answer.callContext = *context; + } + + auto promiseAndPipeline = startCall( + call.getInterfaceId(), call.getMethodId(), kj::mv(capability), context->addRef()); + + // Things may have changed -- in particular if startCall() immediately called + // context->directTailCall(). + + { + auto& answer = answers[answerId]; + + answer.pipeline = kj::mv(promiseAndPipeline.pipeline); + + if (redirectResults) { + auto resultsPromise = promiseAndPipeline.promise.then( + kj::mvCapture(context, [](kj::Own&& context) { + return context->consumeRedirectedResponse(); + })); + + // If the call that later picks up `redirectedResults` decides to discard it, we need to + // make sure our call is not itself canceled unless it has called allowCancellation(). + // So we fork the promise and join one branch with the cancellation promise, in order to + // hold on to it. + auto forked = resultsPromise.fork(); + answer.redirectedResults = forked.addBranch(); + + cancelPaf.promise + .exclusiveJoin(forked.addBranch().then([](kj::Own&&){})) + .detach([](kj::Exception&&) {}); + } else { + // Hack: Both the success and error continuations need to use the context. We could + // refcount, but both will be destroyed at the same time anyway. + RpcCallContext* contextPtr = context; + + promiseAndPipeline.promise.then( + [contextPtr]() { + contextPtr->sendReturn(); + }, [contextPtr](kj::Exception&& exception) { + contextPtr->sendErrorReturn(kj::mv(exception)); + }).catch_([&](kj::Exception&& exception) { + // Handle exceptions that occur in sendReturn()/sendErrorReturn(). + taskFailed(kj::mv(exception)); + }).attach(kj::mv(context)) + .exclusiveJoin(kj::mv(cancelPaf.promise)) + .detach([](kj::Exception&&) {}); + } + } + } + + ClientHook::VoidPromiseAndPipeline startCall( + uint64_t interfaceId, uint64_t methodId, + kj::Own&& capability, kj::Own&& context) { + if (interfaceId == typeId>() && methodId == 0) { + KJ_IF_MAYBE(g, gateway) { + // Wait, this is a call to Persistent.save() and we need to translate it through our + // gateway. + + KJ_IF_MAYBE(resolvedPromise, capability->whenMoreResolved()) { + // The plot thickens: We're looking at a promise capability. It could end up resolving + // to a capability outside the gateway, in which case we don't want to translate at all. + + auto promises = resolvedPromise->then(kj::mvCapture(context, + [this,interfaceId,methodId](kj::Own&& context, + kj::Own resolvedCap) { + auto vpap = startCall(interfaceId, methodId, kj::mv(resolvedCap), kj::mv(context)); + return kj::tuple(kj::mv(vpap.promise), kj::mv(vpap.pipeline)); + })).attach(addRef(*this)).split(); + + return { + kj::mv(kj::get<0>(promises)), + newLocalPromisePipeline(kj::mv(kj::get<1>(promises))), + }; + } + + if (capability->getBrand() == this) { + // This capability is one of our own, pointing back out over the network. That means + // that it would be inappropriate to apply the gateway transformation. We just want to + // reflect the call back. + return kj::downcast(*capability) + .callNoIntercept(interfaceId, methodId, kj::mv(context)); + } + + auto params = context->getParams().getAs::SaveParams>(); + + auto requestSize = params.totalSize(); + ++requestSize.capCount; + requestSize.wordCount += sizeInWords::ExportParams>(); + + auto request = g->exportRequest(requestSize); + request.setCap(Persistent<>::Client(capability->addRef())); + request.setParams(params); + + context->allowCancellation(); + context->releaseParams(); + return context->directTailCall(RequestHook::from(kj::mv(request))); + } + } + + return capability->call(interfaceId, methodId, kj::mv(context)); + } + + kj::Maybe> getMessageTarget(const rpc::MessageTarget::Reader& target) { + switch (target.which()) { + case rpc::MessageTarget::IMPORTED_CAP: { + KJ_IF_MAYBE(exp, exports.find(target.getImportedCap())) { + return exp->clientHook->addRef(); + } else { + KJ_FAIL_REQUIRE("Message target is not a current export ID.") { + return nullptr; + } + } + break; + } + + case rpc::MessageTarget::PROMISED_ANSWER: { + auto promisedAnswer = target.getPromisedAnswer(); + kj::Own pipeline; + + auto& base = answers[promisedAnswer.getQuestionId()]; + KJ_REQUIRE(base.active, "PromisedAnswer.questionId is not a current question.") { + return nullptr; + } + KJ_IF_MAYBE(p, base.pipeline) { + pipeline = p->get()->addRef(); + } else { + pipeline = newBrokenPipeline(KJ_EXCEPTION(FAILED, + "Pipeline call on a request that returned no capabilities or was already closed.")); + } + + KJ_IF_MAYBE(ops, toPipelineOps(promisedAnswer.getTransform())) { + return pipeline->getPipelinedCap(*ops); + } else { + // Exception already thrown. + return nullptr; + } + } + + default: + KJ_FAIL_REQUIRE("Unknown message target type.", target) { + return nullptr; + } + } + + KJ_UNREACHABLE; + } + + void handleReturn(kj::Own&& message, const rpc::Return::Reader& ret) { + // Transitive destructors can end up manipulating the question table and invalidating our + // pointer into it, so make sure these destructors run later. + kj::Array exportsToRelease; + KJ_DEFER(releaseExports(exportsToRelease)); + kj::Maybe>> promiseToRelease; + + KJ_IF_MAYBE(question, questions.find(ret.getAnswerId())) { + KJ_REQUIRE(question->isAwaitingReturn, "Duplicate Return.") { return; } + question->isAwaitingReturn = false; + + if (ret.getReleaseParamCaps()) { + exportsToRelease = kj::mv(question->paramExports); + } else { + question->paramExports = nullptr; + } + + KJ_IF_MAYBE(questionRef, question->selfRef) { + switch (ret.which()) { + case rpc::Return::RESULTS: { + KJ_REQUIRE(!question->isTailCall, + "Tail call `Return` must set `resultsSentElsewhere`, not `results`.") { + return; + } + + auto payload = ret.getResults(); + auto capTableArray = receiveCaps(payload.getCapTable()); + questionRef->fulfill(kj::refcounted( + *this, kj::addRef(*questionRef), kj::mv(message), + kj::mv(capTableArray), payload.getContent())); + break; + } + + case rpc::Return::EXCEPTION: + KJ_REQUIRE(!question->isTailCall, + "Tail call `Return` must set `resultsSentElsewhere`, not `exception`.") { + return; + } + + questionRef->reject(toException(ret.getException())); + break; + + case rpc::Return::CANCELED: + KJ_FAIL_REQUIRE("Return message falsely claims call was canceled.") { return; } + break; + + case rpc::Return::RESULTS_SENT_ELSEWHERE: + KJ_REQUIRE(question->isTailCall, + "`Return` had `resultsSentElsewhere` but this was not a tail call.") { + return; + } + + // Tail calls are fulfilled with a null pointer. + questionRef->fulfill(kj::Own()); + break; + + case rpc::Return::TAKE_FROM_OTHER_QUESTION: + KJ_IF_MAYBE(answer, answers.find(ret.getTakeFromOtherQuestion())) { + KJ_IF_MAYBE(response, answer->redirectedResults) { + questionRef->fulfill(kj::mv(*response)); + } else { + KJ_FAIL_REQUIRE("`Return.takeFromOtherQuestion` referenced a call that did not " + "use `sendResultsTo.yourself`.") { return; } + } + } else { + KJ_FAIL_REQUIRE("`Return.takeFromOtherQuestion` had invalid answer ID.") { return; } + } + + break; + + default: + KJ_FAIL_REQUIRE("Unknown 'Return' type.") { return; } + } + } else { + if (ret.isTakeFromOtherQuestion()) { + // Be sure to release the tail call's promise. + KJ_IF_MAYBE(answer, answers.find(ret.getTakeFromOtherQuestion())) { + promiseToRelease = kj::mv(answer->redirectedResults); + } + } + + // Looks like this question was canceled earlier, so `Finish` was already sent, with + // `releaseResultCaps` set true so that we don't have to release them here. We can go + // ahead and delete it from the table. + questions.erase(ret.getAnswerId(), *question); + } + + } else { + KJ_FAIL_REQUIRE("Invalid question ID in Return message.") { return; } + } + } + + void handleFinish(const rpc::Finish::Reader& finish) { + // Delay release of these things until return so that transitive destructors don't accidentally + // modify the answer table and invalidate our pointer into it. + kj::Array exportsToRelease; + KJ_DEFER(releaseExports(exportsToRelease)); + Answer answerToRelease; + kj::Maybe> pipelineToRelease; + + KJ_IF_MAYBE(answer, answers.find(finish.getQuestionId())) { + KJ_REQUIRE(answer->active, "'Finish' for invalid question ID.") { return; } + + if (finish.getReleaseResultCaps()) { + exportsToRelease = kj::mv(answer->resultExports); + } else { + answer->resultExports = nullptr; + } + + pipelineToRelease = kj::mv(answer->pipeline); + + // If the call isn't actually done yet, cancel it. Otherwise, we can go ahead and erase the + // question from the table. + KJ_IF_MAYBE(context, answer->callContext) { + context->requestCancel(); + } else { + answerToRelease = answers.erase(finish.getQuestionId()); + } + } else { + KJ_REQUIRE(answer->active, "'Finish' for invalid question ID.") { return; } + } + } + + // --------------------------------------------------------------------------- + // Level 1 + + void handleResolve(const rpc::Resolve::Reader& resolve) { + kj::Own replacement; + kj::Maybe exception; + + // Extract the replacement capability. + switch (resolve.which()) { + case rpc::Resolve::CAP: + KJ_IF_MAYBE(cap, receiveCap(resolve.getCap())) { + replacement = kj::mv(*cap); + } else { + KJ_FAIL_REQUIRE("'Resolve' contained 'CapDescriptor.none'.") { return; } + } + break; + + case rpc::Resolve::EXCEPTION: + // We can't set `replacement` to a new broken cap here because this will confuse + // PromiseClient::Resolve() into thinking that the remote promise resolved to a local + // capability and therefore a Disembargo is needed. We must actually reject the promise. + exception = toException(resolve.getException()); + break; + + default: + KJ_FAIL_REQUIRE("Unknown 'Resolve' type.") { return; } + } + + // If the import is on the table, fulfill it. + KJ_IF_MAYBE(import, imports.find(resolve.getPromiseId())) { + KJ_IF_MAYBE(fulfiller, import->promiseFulfiller) { + // OK, this is in fact an unfulfilled promise! + KJ_IF_MAYBE(e, exception) { + fulfiller->get()->reject(kj::mv(*e)); + } else { + fulfiller->get()->fulfill(kj::mv(replacement)); + } + } else if (import->importClient != nullptr) { + // It appears this is a valid entry on the import table, but was not expected to be a + // promise. + KJ_FAIL_REQUIRE("Got 'Resolve' for a non-promise import.") { break; } + } + } + } + + void handleRelease(const rpc::Release::Reader& release) { + releaseExport(release.getId(), release.getReferenceCount()); + } + + void releaseExport(ExportId id, uint refcount) { + KJ_IF_MAYBE(exp, exports.find(id)) { + KJ_REQUIRE(refcount <= exp->refcount, "Tried to drop export's refcount below zero.") { + return; + } + + exp->refcount -= refcount; + if (exp->refcount == 0) { + exportsByCap.erase(exp->clientHook); + exports.erase(id, *exp); + } + } else { + KJ_FAIL_REQUIRE("Tried to release invalid export ID.") { + return; + } + } + } + + void releaseExports(kj::ArrayPtr exports) { + for (auto exportId: exports) { + releaseExport(exportId, 1); + } + } + + void handleDisembargo(const rpc::Disembargo::Reader& disembargo) { + auto context = disembargo.getContext(); + switch (context.which()) { + case rpc::Disembargo::Context::SENDER_LOOPBACK: { + kj::Own target; + + KJ_IF_MAYBE(t, getMessageTarget(disembargo.getTarget())) { + target = kj::mv(*t); + } else { + // Exception already reported. + return; + } + + for (;;) { + KJ_IF_MAYBE(r, target->getResolved()) { + target = r->addRef(); + } else { + break; + } + } + + KJ_REQUIRE(target->getBrand() == this, + "'Disembargo' of type 'senderLoopback' sent to an object that does not point " + "back to the sender.") { + return; + } + + EmbargoId embargoId = context.getSenderLoopback(); + + // We need to insert an evalLater() here to make sure that any pending calls towards this + // cap have had time to find their way through the event loop. + tasks.add(kj::evalLater(kj::mvCapture( + target, [this,embargoId](kj::Own&& target) { + if (!connection.is()) { + return; + } + + RpcClient& downcasted = kj::downcast(*target); + + auto message = connection.get()->newOutgoingMessage( + messageSizeHint() + MESSAGE_TARGET_SIZE_HINT); + auto builder = message->getBody().initAs().initDisembargo(); + + { + auto redirect = downcasted.writeTarget(builder.initTarget()); + + // Disembargoes should only be sent to capabilities that were previously the subject of + // a `Resolve` message. But `writeTarget` only ever returns non-null when called on + // a PromiseClient. The code which sends `Resolve` and `Return` should have replaced + // any promise with a direct node in order to solve the Tribble 4-way race condition. + // See the documentation of Disembargo in rpc.capnp for more. + KJ_REQUIRE(redirect == nullptr, + "'Disembargo' of type 'senderLoopback' sent to an object that does not " + "appear to have been the subject of a previous 'Resolve' message.") { + return; + } + } + + builder.getContext().setReceiverLoopback(embargoId); + + message->send(); + }))); + + break; + } + + case rpc::Disembargo::Context::RECEIVER_LOOPBACK: { + KJ_IF_MAYBE(embargo, embargoes.find(context.getReceiverLoopback())) { + KJ_ASSERT_NONNULL(embargo->fulfiller)->fulfill(); + embargoes.erase(context.getReceiverLoopback(), *embargo); + } else { + KJ_FAIL_REQUIRE("Invalid embargo ID in 'Disembargo.context.receiverLoopback'.") { + return; + } + } + break; + } + + default: + KJ_FAIL_REQUIRE("Unimplemented Disembargo type.", disembargo) { return; } + } + } + + // --------------------------------------------------------------------------- + // Level 2 +}; + +} // namespace + +class RpcSystemBase::Impl final: private BootstrapFactoryBase, private kj::TaskSet::ErrorHandler { +public: + Impl(VatNetworkBase& network, kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway) + : network(network), bootstrapInterface(kj::mv(bootstrapInterface)), + bootstrapFactory(*this), gateway(kj::mv(gateway)), tasks(*this) { + tasks.add(acceptLoop()); + } + Impl(VatNetworkBase& network, BootstrapFactoryBase& bootstrapFactory, + kj::Maybe::Client> gateway) + : network(network), bootstrapFactory(bootstrapFactory), + gateway(kj::mv(gateway)), tasks(*this) { + tasks.add(acceptLoop()); + } + Impl(VatNetworkBase& network, SturdyRefRestorerBase& restorer) + : network(network), bootstrapFactory(*this), restorer(restorer), tasks(*this) { + tasks.add(acceptLoop()); + } + + ~Impl() noexcept(false) { + unwindDetector.catchExceptionsIfUnwinding([&]() { + // std::unordered_map doesn't like it when elements' destructors throw, so carefully + // disassemble it. + if (!connections.empty()) { + kj::Vector> deleteMe(connections.size()); + kj::Exception shutdownException = KJ_EXCEPTION(FAILED, "RpcSystem was destroyed."); + for (auto& entry: connections) { + entry.second->disconnect(kj::cp(shutdownException)); + deleteMe.add(kj::mv(entry.second)); + } + } + }); + } + + Capability::Client bootstrap(AnyStruct::Reader vatId) { + // For now we delegate to restore() since it's equivalent, but eventually we'll remove restore() + // and implement bootstrap() directly. + return restore(vatId, AnyPointer::Reader()); + } + + Capability::Client restore(AnyStruct::Reader vatId, AnyPointer::Reader objectId) { + KJ_IF_MAYBE(connection, network.baseConnect(vatId)) { + auto& state = getConnectionState(kj::mv(*connection)); + return Capability::Client(state.restore(objectId)); + } else KJ_IF_MAYBE(r, restorer) { + return r->baseRestore(objectId); + } else { + return Capability::Client(newBrokenCap( + "SturdyRef referred to a local object but there is no local SturdyRef restorer.")); + } + } + + void setFlowLimit(size_t words) { + flowLimit = words; + + for (auto& conn: connections) { + conn.second->setFlowLimit(words); + } + } + +private: + VatNetworkBase& network; + kj::Maybe bootstrapInterface; + BootstrapFactoryBase& bootstrapFactory; + kj::Maybe::Client> gateway; + kj::Maybe restorer; + size_t flowLimit = kj::maxValue; + kj::TaskSet tasks; + + typedef std::unordered_map> + ConnectionMap; + ConnectionMap connections; + + kj::UnwindDetector unwindDetector; + + RpcConnectionState& getConnectionState(kj::Own&& connection) { + auto iter = connections.find(connection); + if (iter == connections.end()) { + VatNetworkBase::Connection* connectionPtr = connection; + auto onDisconnect = kj::newPromiseAndFulfiller(); + tasks.add(onDisconnect.promise + .then([this,connectionPtr](RpcConnectionState::DisconnectInfo info) { + connections.erase(connectionPtr); + tasks.add(kj::mv(info.shutdownPromise)); + })); + auto newState = kj::refcounted( + bootstrapFactory, gateway, restorer, kj::mv(connection), + kj::mv(onDisconnect.fulfiller), flowLimit); + RpcConnectionState& result = *newState; + connections.insert(std::make_pair(connectionPtr, kj::mv(newState))); + return result; + } else { + return *iter->second; + } + } + + kj::Promise acceptLoop() { + auto receive = network.baseAccept().then( + [this](kj::Own&& connection) { + getConnectionState(kj::mv(connection)); + }); + return receive.then([this]() { + // No exceptions; continue loop. + // + // (We do this in a separate continuation to handle the case where exceptions are + // disabled.) + tasks.add(acceptLoop()); + }); + } + + Capability::Client baseCreateFor(AnyStruct::Reader clientId) override { + // Implements BootstrapFactory::baseCreateFor() in terms of `bootstrapInterface` or `restorer`, + // for use when we were given one of those instead of an actual `bootstrapFactory`. + + KJ_IF_MAYBE(cap, bootstrapInterface) { + return *cap; + } else KJ_IF_MAYBE(r, restorer) { + return r->baseRestore(AnyPointer::Reader()); + } else { + return KJ_EXCEPTION(FAILED, "This vat does not expose any public/bootstrap interfaces."); + } + } + + void taskFailed(kj::Exception&& exception) override { + KJ_LOG(ERROR, exception); + } +}; + +RpcSystemBase::RpcSystemBase(VatNetworkBase& network, + kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway) + : impl(kj::heap(network, kj::mv(bootstrapInterface), kj::mv(gateway))) {} +RpcSystemBase::RpcSystemBase(VatNetworkBase& network, + BootstrapFactoryBase& bootstrapFactory, + kj::Maybe::Client> gateway) + : impl(kj::heap(network, bootstrapFactory, kj::mv(gateway))) {} +RpcSystemBase::RpcSystemBase(VatNetworkBase& network, SturdyRefRestorerBase& restorer) + : impl(kj::heap(network, restorer)) {} +RpcSystemBase::RpcSystemBase(RpcSystemBase&& other) noexcept = default; +RpcSystemBase::~RpcSystemBase() noexcept(false) {} + +Capability::Client RpcSystemBase::baseBootstrap(AnyStruct::Reader vatId) { + return impl->bootstrap(vatId); +} + +Capability::Client RpcSystemBase::baseRestore( + AnyStruct::Reader hostId, AnyPointer::Reader objectId) { + return impl->restore(hostId, objectId); +} + +void RpcSystemBase::baseSetFlowLimit(size_t words) { + return impl->setFlowLimit(words); +} + +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1399 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xb312981b2552a250; +# Recall that Cap'n Proto RPC allows messages to contain references to remote objects that +# implement interfaces. These references are called "capabilities", because they both designate +# the remote object to use and confer permission to use it. +# +# Recall also that Cap'n Proto RPC has the feature that when a method call itself returns a +# capability, the caller can begin calling methods on that capability _before the first call has +# returned_. The caller essentially sends a message saying "Hey server, as soon as you finish +# that previous call, do this with the result!". Cap'n Proto's RPC protocol makes this possible. +# +# The protocol is significantly more complicated than most RPC protocols. However, this is +# implementation complexity that underlies an easy-to-grasp higher-level model of object oriented +# programming. That is, just like TCP is a surprisingly complicated protocol that implements a +# conceptually-simple byte stream abstraction, Cap'n Proto is a surprisingly complicated protocol +# that implements a conceptually-simple object abstraction. +# +# Cap'n Proto RPC is based heavily on CapTP, the object-capability protocol used by the E +# programming language: +# http://www.erights.org/elib/distrib/captp/index.html +# +# Cap'n Proto RPC takes place between "vats". A vat hosts some set of objects and talks to other +# vats through direct bilateral connections. Typically, there is a 1:1 correspondence between vats +# and processes (in the unix sense of the word), although this is not strictly always true (one +# process could run multiple vats, or a distributed virtual vat might live across many processes). +# +# Cap'n Proto does not distinguish between "clients" and "servers" -- this is up to the application. +# Either end of any connection can potentially hold capabilities pointing to the other end, and +# can call methods on those capabilities. In the doc comments below, we use the words "sender" +# and "receiver". These refer to the sender and receiver of an instance of the struct or field +# being documented. Sometimes we refer to a "third-party" that is neither the sender nor the +# receiver. Documentation is generally written from the point of view of the sender. +# +# It is generally up to the vat network implementation to securely verify that connections are made +# to the intended vat as well as to encrypt transmitted data for privacy and integrity. See the +# `VatNetwork` example interface near the end of this file. +# +# When a new connection is formed, the only interesting things that can be done are to send a +# `Bootstrap` (level 0) or `Accept` (level 3) message. +# +# Unless otherwise specified, messages must be delivered to the receiving application in the same +# order in which they were initiated by the sending application. The goal is to support "E-Order", +# which states that two calls made on the same reference must be delivered in the order which they +# were made: +# http://erights.org/elib/concurrency/partial-order.html +# +# Since the full protocol is complicated, we define multiple levels of support that an +# implementation may target. For many applications, level 1 support will be sufficient. +# Comments in this file indicate which level requires the corresponding feature to be +# implemented. +# +# * **Level 0:** The implementation does not support object references. Only the bootstrap interface +# can be called. At this level, the implementation does not support object-oriented protocols and +# is similar in complexity to JSON-RPC or Protobuf services. This level should be considered only +# a temporary stepping-stone toward level 1 as the lack of object references drastically changes +# how protocols are designed. Applications _should not_ attempt to design their protocols around +# the limitations of level 0 implementations. +# +# * **Level 1:** The implementation supports simple bilateral interaction with object references +# and promise pipelining, but interactions between three or more parties are supported only via +# proxying of objects. E.g. if Alice (in Vat A) wants to send Bob (in Vat B) a capability +# pointing to Carol (in Vat C), Alice must create a proxy of Carol within Vat A and send Bob a +# reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do +# not support checking if two capabilities received from different vats actually point to the +# same object ("join"), although they should be able to do this check on capabilities received +# from the same vat. +# +# * **Level 2:** The implementation supports saving persistent capabilities -- i.e. capabilities +# that remain valid even after disconnect, and can be restored on a future connection. When a +# capability is saved, the requester receives a `SturdyRef`, which is a token that can be used +# to restore the capability later. +# +# * **Level 3:** The implementation supports three-way interactions. That is, if Alice (in Vat A) +# sends Bob (in Vat B) a capability pointing to Carol (in Vat C), then Vat B will automatically +# form a direct connection to Vat C rather than have requests be proxied through Vat A. +# +# * **Level 4:** The entire protocol is implemented, including joins (checking if two capabilities +# are equivalent). +# +# Note that an implementation must also support specific networks (transports), as described in +# the "Network-specific Parameters" section below. An implementation might have different levels +# depending on the network used. +# +# New implementations of Cap'n Proto should start out targeting the simplistic two-party network +# type as defined in `rpc-twoparty.capnp`. With this network type, level 3 is irrelevant and +# levels 2 and 4 are much easier than usual to implement. When such an implementation is paired +# with a container proxy, the contained app effectively gets to make full use of the proxy's +# network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to +# bother implementing any other vat network protocol -- just use the correct container type and get +# it for free. + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("capnp::rpc"); + +# ======================================================================================== +# The Four Tables +# +# Cap'n Proto RPC connections are stateful (although an application built on Cap'n Proto could +# export a stateless interface). As in CapTP, for each open connection, a vat maintains four state +# tables: questions, answers, imports, and exports. See the diagram at: +# http://www.erights.org/elib/distrib/captp/4tables.html +# +# The question table corresponds to the other end's answer table, and the imports table corresponds +# to the other end's exports table. +# +# The entries in each table are identified by ID numbers (defined below as 32-bit integers). These +# numbers are always specific to the connection; a newly-established connection starts with no +# valid IDs. Since low-numbered IDs will pack better, it is suggested that IDs be assigned like +# Unix file descriptors -- prefer the lowest-number ID that is currently available. +# +# IDs in the questions/answers tables are chosen by the questioner and generally represent method +# calls that are in progress. +# +# IDs in the imports/exports tables are chosen by the exporter and generally represent objects on +# which methods may be called. Exports may be "settled", meaning the exported object is an actual +# object living in the exporter's vat, or they may be "promises", meaning the exported object is +# the as-yet-unknown result of an ongoing operation and will eventually be resolved to some other +# object once that operation completes. Calls made to a promise will be forwarded to the eventual +# target once it is known. The eventual replacement object does *not* get the same ID as the +# promise, as it may turn out to be an object that is already exported (so already has an ID) or +# may even live in a completely different vat (and so won't get an ID on the same export table +# at all). +# +# IDs can be reused over time. To make this safe, we carefully define the lifetime of IDs. Since +# messages using the ID could be traveling in both directions simultaneously, we must define the +# end of life of each ID _in each direction_. The ID is only safe to reuse once it has been +# released by both sides. +# +# When a Cap'n Proto connection is lost, everything on the four tables is lost. All questions are +# canceled and throw exceptions. All imports become broken (all future calls to them throw +# exceptions). All exports and answers are implicitly released. The only things not lost are +# persistent capabilities (`SturdyRef`s). The application must plan for this and should respond by +# establishing a new connection and restoring from these persistent capabilities. + +using QuestionId = UInt32; +# **(level 0)** +# +# Identifies a question in the sender's question table (which corresponds to the receiver's answer +# table). The questioner (caller) chooses an ID when making a call. The ID remains valid in +# caller -> callee messages until a Finish message is sent, and remains valid in callee -> caller +# messages until a Return message is sent. + +using AnswerId = QuestionId; +# **(level 0)** +# +# Identifies an answer in the sender's answer table (which corresponds to the receiver's question +# table). +# +# AnswerId is physically equivalent to QuestionId, since the question and answer tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. + +using ExportId = UInt32; +# **(level 1)** +# +# Identifies an exported capability or promise in the sender's export table (which corresponds +# to the receiver's import table). The exporter chooses an ID before sending a capability over the +# wire. If the capability is already in the table, the exporter should reuse the same ID. If the +# ID is a promise (as opposed to a settled capability), this must be indicated at the time the ID +# is introduced (e.g. by using `senderPromise` instead of `senderHosted` in `CapDescriptor`); in +# this case, the importer shall expect a later `Resolve` message that replaces the promise. +# +# ExportId/ImportIds are subject to reference counting. Whenever an `ExportId` is sent over the +# wire (from the exporter to the importer), the export's reference count is incremented (unless +# otherwise specified). The reference count is later decremented by a `Release` message. Since +# the `Release` message can specify an arbitrary number by which to reduce the reference count, the +# importer should usually batch reference decrements and only send a `Release` when it believes the +# reference count has hit zero. Of course, it is possible that a new reference to the export is +# in-flight at the time that the `Release` message is sent, so it is necessary for the exporter to +# keep track of the reference count on its end as well to avoid race conditions. +# +# When a connection is lost, all exports are implicitly released. It is not possible to restore +# a connection state after disconnect (although a transport layer could implement a concept of +# persistent connections if it is transparent to the RPC layer). + +using ImportId = ExportId; +# **(level 1)** +# +# Identifies an imported capability or promise in the sender's import table (which corresponds to +# the receiver's export table). +# +# ImportId is physically equivalent to ExportId, since the export and import tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. +# +# An `ImportId` remains valid in importer -> exporter messages until the importer has sent +# `Release` messages that (it believes) have reduced the reference count to zero. + +# ======================================================================================== +# Messages + +struct Message { + # An RPC connection is a bi-directional stream of Messages. + + union { + unimplemented @0 :Message; + # The sender previously received this message from the peer but didn't understand it or doesn't + # yet implement the functionality that was requested. So, the sender is echoing the message + # back. In some cases, the receiver may be able to recover from this by pretending the sender + # had taken some appropriate "null" action. + # + # For example, say `resolve` is received by a level 0 implementation (because a previous call + # or return happened to contain a promise). The level 0 implementation will echo it back as + # `unimplemented`. The original sender can then simply release the cap to which the promise + # had resolved, thus avoiding a leak. + # + # For any message type that introduces a question, if the message comes back unimplemented, + # the original sender may simply treat it as if the question failed with an exception. + # + # In cases where there is no sensible way to react to an `unimplemented` message (without + # resource leaks or other serious problems), the connection may need to be aborted. This is + # a gray area; different implementations may take different approaches. + + abort @1 :Exception; + # Sent when a connection is being aborted due to an unrecoverable error. This could be e.g. + # because the sender received an invalid or nonsensical message (`isCallersFault` is true) or + # because the sender had an internal error (`isCallersFault` is false). The sender will shut + # down the outgoing half of the connection after `abort` and will completely close the + # connection shortly thereafter (it's up to the sender how much of a time buffer they want to + # offer for the client to receive the `abort` before the connection is reset). + + # Level 0 features ----------------------------------------------- + + bootstrap @8 :Bootstrap; # Request the peer's bootstrap interface. + call @2 :Call; # Begin a method call. + return @3 :Return; # Complete a method call. + finish @4 :Finish; # Release a returned answer / cancel a call. + + # Level 1 features ----------------------------------------------- + + resolve @5 :Resolve; # Resolve a previously-sent promise. + release @6 :Release; # Release a capability so that the remote object can be deallocated. + disembargo @13 :Disembargo; # Lift an embargo used to enforce E-order over promise resolution. + + # Level 2 features ----------------------------------------------- + + obsoleteSave @7 :AnyPointer; + # Obsolete request to save a capability, resulting in a SturdyRef. This has been replaced + # by the `Persistent` interface defined in `persistent.capnp`. This operation was never + # implemented. + + obsoleteDelete @9 :AnyPointer; + # Obsolete way to delete a SturdyRef. This operation was never implemented. + + # Level 3 features ----------------------------------------------- + + provide @10 :Provide; # Provide a capability to a third party. + accept @11 :Accept; # Accept a capability provided by a third party. + + # Level 4 features ----------------------------------------------- + + join @12 :Join; # Directly connect to the common root of two or more proxied caps. + } +} + +# Level 0 message types ---------------------------------------------- + +struct Bootstrap { + # **(level 0)** + # + # Get the "bootstrap" interface exported by the remote vat. + # + # For level 0, 1, and 2 implementations, the "bootstrap" interface is simply the main interface + # exported by a vat. If the vat acts as a server fielding connections from clients, then the + # bootstrap interface defines the basic functionality available to a client when it connects. + # The exact interface definition obviously depends on the application. + # + # We call this a "bootstrap" because in an ideal Cap'n Proto world, bootstrap interfaces would + # never be used. In such a world, any time you connect to a new vat, you do so because you + # received an introduction from some other vat (see `ThirdPartyCapId`). Thus, the first message + # you send is `Accept`, and further communications derive from there. `Bootstrap` is not used. + # + # In such an ideal world, DNS itself would support Cap'n Proto -- performing a DNS lookup would + # actually return a new Cap'n Proto capability, thus introducing you to the target system via + # level 3 RPC. Applications would receive the capability to talk to DNS in the first place as + # an initial endowment or part of a Powerbox interaction. Therefore, an app can form arbitrary + # connections without ever using `Bootstrap`. + # + # Of course, in the real world, DNS is not Cap'n-Proto-based, and we don't want Cap'n Proto to + # require a whole new internet infrastructure to be useful. Therefore, we offer bootstrap + # interfaces as a way to get up and running without a level 3 introduction. Thus, bootstrap + # interfaces are used to "bootstrap" from other, non-Cap'n-Proto-based means of service discovery, + # such as legacy DNS. + # + # Note that a vat need not provide a bootstrap interface, and in fact many vats (especially those + # acting as clients) do not. In this case, the vat should either reply to `Bootstrap` with a + # `Return` indicating an exception, or should return a dummy capability with no methods. + + questionId @0 :QuestionId; + # A new question ID identifying this request, which will eventually receive a Return message + # containing the restored capability. + + deprecatedObjectId @1 :AnyPointer; + # ** DEPRECATED ** + # + # A Vat may export multiple bootstrap interfaces. In this case, `deprecatedObjectId` specifies + # which one to return. If this pointer is null, then the default bootstrap interface is returned. + # + # As of verison 0.5, use of this field is deprecated. If a service wants to export multiple + # bootstrap interfaces, it should instead define a single bootstarp interface that has methods + # that return each of the other interfaces. + # + # **History** + # + # In the first version of Cap'n Proto RPC (0.4.x) the `Bootstrap` message was called `Restore`. + # At the time, it was thought that this would eventually serve as the way to restore SturdyRefs + # (level 2). Meanwhile, an application could offer its "main" interface on a well-known + # (non-secret) SturdyRef. + # + # Since level 2 RPC was not implemented at the time, the `Restore` message was in practice only + # used to obtain the main interface. Since most applications had only one main interface that + # they wanted to restore, they tended to designate this with a null `objectId`. + # + # Unfortunately, the earliest version of the EZ RPC interfaces set a precedent of exporting + # multiple main interfaces by allowing them to be exported under string names. In this case, + # `objectId` was a Text value specifying the name. + # + # All of this proved problematic for several reasons: + # + # - The arrangement assumed that a client wishing to restore a SturdyRef would know exactly what + # machine to connect to and would be able to immediately restore a SturdyRef on connection. + # However, in practice, the ability to restore SturdyRefs is itself a capability that may + # require going through an authentication process to obtain. Thus, it makes more sense to + # define a "restorer service" as a full Cap'n Proto interface. If this restorer interface is + # offered as the vat's bootstrap interface, then this is equivalent to the old arrangement. + # + # - Overloading "Restore" for the purpose of obtaining well-known capabilities encouraged the + # practice of exporting singleton services with string names. If singleton services are desired, + # it is better to have one main interface that has methods that can be used to obtain each + # service, in order to get all the usual benefits of schemas and type checking. + # + # - Overloading "Restore" also had a security problem: Often, "main" or "well-known" + # capabilities exported by a vat are in fact not public: they are intended to be accessed only + # by clients who are capable of forming a connection to the vat. This can lead to trouble if + # the client itself has other clients and wishes to foward some `Restore` requests from those + # external clients -- it has to be very careful not to allow through `Restore` requests + # addressing the default capability. + # + # For example, consider the case of a sandboxed Sandstorm application and its supervisor. The + # application exports a default capability to its supervisor that provides access to + # functionality that only the supervisor is supposed to access. Meanwhile, though, applications + # may publish other capabilities that may be persistent, in which case the application needs + # to field `Restore` requests that could come from anywhere. These requests of course have to + # pass through the supervisor, as all communications with the outside world must. But, the + # supervisor has to be careful not to honor an external request addressing the application's + # default capability, since this capability is privileged. Unfortunately, the default + # capability cannot be given an unguessable name, because then the supervisor itself would not + # be able to address it! + # + # As of Cap'n Proto 0.5, `Restore` has been renamed to `Bootstrap` and is no longer planned for + # use in restoring SturdyRefs. + # + # Note that 0.4 also defined a message type called `Delete` that, like `Restore`, addressed a + # SturdyRef, but indicated that the client would not restore the ref again in the future. This + # operation was never implemented, so it was removed entirely. If a "delete" operation is desired, + # it should exist as a method on the same interface that handles restoring SturdyRefs. However, + # the utility of such an operation is questionable. You wouldn't be able to rely on it for + # garbage collection since a client could always disappear permanently without remembering to + # delete all its SturdyRefs, thus leaving them dangling forever. Therefore, it is advisable to + # design systems such that SturdyRefs never represent "owned" pointers. + # + # For example, say a SturdyRef points to an image file hosted on some server. That image file + # should also live inside a collection (a gallery, perhaps) hosted on the same server, owned by + # a user who can delete the image at any time. If the user deletes the image, the SturdyRef + # stops working. On the other hand, if the SturdyRef is discarded, this has no effect on the + # existence of the image in its collection. +} + +struct Call { + # **(level 0)** + # + # Message type initiating a method call on a capability. + + questionId @0 :QuestionId; + # A number, chosen by the caller, that identifies this call in future messages. This number + # must be different from all other calls originating from the same end of the connection (but + # may overlap with question IDs originating from the opposite end). A fine strategy is to use + # sequential question IDs, but the recipient should not assume this. + # + # A question ID can be reused once both: + # - A matching Return has been received from the callee. + # - A matching Finish has been sent from the caller. + + target @1 :MessageTarget; + # The object that should receive this call. + + interfaceId @2 :UInt64; + # The type ID of the interface being called. Each capability may implement multiple interfaces. + + methodId @3 :UInt16; + # The ordinal number of the method to call within the requested interface. + + allowThirdPartyTailCall @8 :Bool = false; + # Indicates whether or not the receiver is allowed to send a `Return` containing + # `acceptFromThirdParty`. Level 3 implementations should set this true. Otherwise, the callee + # will have to proxy the return in the case of a tail call to a third-party vat. + + params @4 :Payload; + # The call parameters. `params.content` is a struct whose fields correspond to the parameters of + # the method. + + sendResultsTo :union { + # Where should the return message be sent? + + caller @5 :Void; + # Send the return message back to the caller (the usual). + + yourself @6 :Void; + # **(level 1)** + # + # Don't actually return the results to the sender. Instead, hold on to them and await + # instructions from the sender regarding what to do with them. In particular, the sender + # may subsequently send a `Return` for some other call (which the receiver had previously made + # to the sender) with `takeFromOtherQuestion` set. The results from this call are then used + # as the results of the other call. + # + # When `yourself` is used, the receiver must still send a `Return` for the call, but sets the + # field `resultsSentElsewhere` in that `Return` rather than including the results. + # + # This feature can be used to implement tail calls in which a call from Vat A to Vat B ends up + # returning the result of a call from Vat B back to Vat A. + # + # In particular, the most common use case for this feature is when Vat A makes a call to a + # promise in Vat B, and then that promise ends up resolving to a capability back in Vat A. + # Vat B must forward all the queued calls on that promise back to Vat A, but can set `yourself` + # in the calls so that the results need not pass back through Vat B. + # + # For example: + # - Alice, in Vat A, call foo() on Bob in Vat B. + # - Alice makes a pipelined call bar() on the promise returned by foo(). + # - Later on, Bob resolves the promise from foo() to point at Carol, who lives in Vat A (next + # to Alice). + # - Vat B dutifully forwards the bar() call to Carol. Let us call this forwarded call bar'(). + # Notice that bar() and bar'() are travelling in opposite directions on the same network + # link. + # - The `Call` for bar'() has `sendResultsTo` set to `yourself`, with the value being the + # question ID originally assigned to the bar() call. + # - Vat A receives bar'() and delivers it to Carol. + # - When bar'() returns, Vat A immediately takes the results and returns them from bar(). + # - Meanwhile, Vat A sends a `Return` for bar'() to Vat B, with `resultsSentElsewhere` set in + # place of results. + # - Vat A sends a `Finish` for that call to Vat B. + # - Vat B receives the `Return` for bar'() and sends a `Return` for bar(), with + # `receivedFromYourself` set in place of the results. + # - Vat B receives the `Finish` for bar() and sends a `Finish` to bar'(). + + thirdParty @7 :RecipientId; + # **(level 3)** + # + # The call's result should be returned to a different vat. The receiver (the callee) expects + # to receive an `Accept` message from the indicated vat, and should return the call's result + # to it, rather than to the sender of the `Call`. + # + # This operates much like `yourself`, above, except that Carol is in a separate Vat C. `Call` + # messages are sent from Vat A -> Vat B and Vat B -> Vat C. A `Return` message is sent from + # Vat B -> Vat A that contains `acceptFromThirdParty` in place of results. When Vat A sends + # an `Accept` to Vat C, it receives back a `Return` containing the call's actual result. Vat C + # also sends a `Return` to Vat B with `resultsSentElsewhere`. + } +} + +struct Return { + # **(level 0)** + # + # Message type sent from callee to caller indicating that the call has completed. + + answerId @0 :AnswerId; + # Equal to the QuestionId of the corresponding `Call` message. + + releaseParamCaps @1 :Bool = true; + # If true, all capabilities that were in the params should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # to set it to false they'll quickly get errors. + + union { + results @2 :Payload; + # The result. + # + # For regular method calls, `results.content` points to the result struct. + # + # For a `Return` in response to an `Accept`, `results` contains a single capability (rather + # than a struct), and `results.content` is just a capability pointer with index 0. A `Finish` + # is still required in this case. + + exception @3 :Exception; + # Indicates that the call failed and explains why. + + canceled @4 :Void; + # Indicates that the call was canceled due to the caller sending a Finish message + # before the call had completed. + + resultsSentElsewhere @5 :Void; + # This is set when returning from a `Call` that had `sendResultsTo` set to something other + # than `caller`. + + takeFromOtherQuestion @6 :QuestionId; + # The sender has also sent (before this message) a `Call` with the given question ID and with + # `sendResultsTo.yourself` set, and the results of that other call should be used as the + # results here. + + acceptFromThirdParty @7 :ThirdPartyCapId; + # **(level 3)** + # + # The caller should contact a third-party vat to pick up the results. An `Accept` message + # sent to the vat will return the result. This pairs with `Call.sendResultsTo.thirdParty`. + # It should only be used if the corresponding `Call` had `allowThirdPartyTailCall` set. + } +} + +struct Finish { + # **(level 0)** + # + # Message type sent from the caller to the callee to indicate: + # 1) The questionId will no longer be used in any messages sent by the callee (no further + # pipelined requests). + # 2) If the call has not returned yet, the caller no longer cares about the result. If nothing + # else cares about the result either (e.g. there are no other outstanding calls pipelined on + # the result of this one) then the callee may wish to immediately cancel the operation and + # send back a Return message with "canceled" set. However, implementations are not required + # to support premature cancellation -- instead, the implementation may wait until the call + # actually completes and send a normal `Return` message. + # + # TODO(someday): Should we separate (1) and implicitly releasing result capabilities? It would be + # possible and useful to notify the server that it doesn't need to keep around the response to + # service pipeline requests even though the caller still wants to receive it / hasn't yet + # finished processing it. It could also be useful to notify the server that it need not marshal + # the results because the caller doesn't want them anyway, even if the caller is still sending + # pipelined calls, although this seems less useful (just saving some bytes on the wire). + + questionId @0 :QuestionId; + # ID of the call whose result is to be released. + + releaseResultCaps @1 :Bool = true; + # If true, all capabilities that were in the results should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # set it false they'll quickly get errors. +} + +# Level 1 message types ---------------------------------------------- + +struct Resolve { + # **(level 1)** + # + # Message type sent to indicate that a previously-sent promise has now been resolved to some other + # object (possibly another promise) -- or broken, or canceled. + # + # Keep in mind that it's possible for a `Resolve` to be sent to a level 0 implementation that + # doesn't implement it. For example, a method call or return might contain a capability in the + # payload. Normally this is fine even if the receiver is level 0, because they will implicitly + # release all such capabilities on return / finish. But if the cap happens to be a promise, then + # a follow-up `Resolve` may be sent regardless of this release. The level 0 receiver will reply + # with an `unimplemented` message, and the sender (of the `Resolve`) can respond to this as if the + # receiver had immediately released any capability to which the promise resolved. + # + # When implementing promise resolution, it's important to understand how embargos work and the + # tricky case of the Tribble 4-way race condition. See the comments for the Disembargo message, + # below. + + promiseId @0 :ExportId; + # The ID of the promise to be resolved. + # + # Unlike all other instances of `ExportId` sent from the exporter, the `Resolve` message does + # _not_ increase the reference count of `promiseId`. In fact, it is expected that the receiver + # will release the export soon after receiving `Resolve`, and the sender will not send this + # `ExportId` again until it has been released and recycled. + # + # When an export ID sent over the wire (e.g. in a `CapDescriptor`) is indicated to be a promise, + # this indicates that the sender will follow up at some point with a `Resolve` message. If the + # same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the + # same ID is sent again later _after_ a `Resolve`, it can only be because the export's + # reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore + # this later promise does _not_ correspond to the earlier `Resolve`. + # + # If a promise ID's reference count reaches zero before a `Resolve` is sent, the `Resolve` + # message may or may not still be sent (the `Resolve` may have already been in-flight when + # `Release` was sent, but if the `Release` is received before `Resolve` then there is no longer + # any reason to send a `Resolve`). Thus a `Resolve` may be received for a promise of which + # the receiver has no knowledge, because it already released it earlier. In this case, the + # receiver should simply release the capability to which the promise resolved. + + union { + cap @1 :CapDescriptor; + # The object to which the promise resolved. + # + # The sender promises that from this point forth, until `promiseId` is released, it shall + # simply forward all messages to the capability designated by `cap`. This is true even if + # `cap` itself happens to desigate another promise, and that other promise later resolves -- + # messages sent to `promiseId` shall still go to that other promise, not to its resolution. + # This is important in the case that the receiver of the `Resolve` ends up sending a + # `Disembargo` message towards `promiseId` in order to control message ordering -- that + # `Disembargo` really needs to reflect back to exactly the object designated by `cap` even + # if that object is itself a promise. + + exception @2 :Exception; + # Indicates that the promise was broken. + } +} + +struct Release { + # **(level 1)** + # + # Message type sent to indicate that the sender is done with the given capability and the receiver + # can free resources allocated to it. + + id @0 :ImportId; + # What to release. + + referenceCount @1 :UInt32; + # The amount by which to decrement the reference count. The export is only actually released + # when the reference count reaches zero. +} + +struct Disembargo { + # **(level 1)** + # + # Message sent to indicate that an embargo on a recently-resolved promise may now be lifted. + # + # Embargos are used to enforce E-order in the presence of promise resolution. That is, if an + # application makes two calls foo() and bar() on the same capability reference, in that order, + # the calls should be delivered in the order in which they were made. But if foo() is called + # on a promise, and that promise happens to resolve before bar() is called, then the two calls + # may travel different paths over the network, and thus could arrive in the wrong order. In + # this case, the call to `bar()` must be embargoed, and a `Disembargo` message must be sent along + # the same path as `foo()` to ensure that the `Disembargo` arrives after `foo()`. Once the + # `Disembargo` arrives, `bar()` can then be delivered. + # + # There are two particular cases where embargos are important. Consider object Alice, in Vat A, + # who holds a promise P, pointing towards Vat B, that eventually resolves to Carol. The two + # cases are: + # - Carol lives in Vat A, i.e. next to Alice. In this case, Vat A needs to send a `Disembargo` + # message that echos through Vat B and back, to ensure that all pipelined calls on the promise + # have been delivered. + # - Carol lives in a different Vat C. When the promise resolves, a three-party handoff occurs + # (see `Provide` and `Accept`, which constitute level 3 of the protocol). In this case, we + # piggyback on the state that has already been set up to handle the handoff: the `Accept` + # message (from Vat A to Vat C) is embargoed, as are all pipelined messages sent to it, while + # a `Disembargo` message is sent from Vat A through Vat B to Vat C. See `Accept.embargo` for + # an example. + # + # Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise + # already pointed at), no embargo is needed, because the pipelined calls are delivered over the + # same path as the later direct calls. + # + # Keep in mind that promise resolution happens both in the form of Resolve messages as well as + # Return messages (which resolve PromisedAnswers). Embargos apply in both cases. + # + # An alternative strategy for enforcing E-order over promise resolution could be for Vat A to + # implement the embargo internally. When Vat A is notified of promise resolution, it could + # send a dummy no-op call to promise P and wait for it to complete. Until that call completes, + # all calls to the capability are queued locally. This strategy works, but is pessimistic: + # in the three-party case, it requires an A -> B -> C -> B -> A round trip before calls can start + # being delivered directly to from Vat A to Vat C. The `Disembargo` message allows latency to be + # reduced. (In the two-party loopback case, the `Disembargo` message is just a more explicit way + # of accomplishing the same thing as a no-op call, but isn't any faster.) + # + # *The Tribble 4-way Race Condition* + # + # Any implementation of promise resolution and embargos must be aware of what we call the + # "Tribble 4-way race condition", after Dean Tribble, who explained the problem in a lively + # Friam meeting. + # + # Embargos are designed to work in the case where a two-hop path is being shortened to one hop. + # But sometimes there are more hops. Imagine that Alice has a reference to a remote promise P1 + # that eventually resolves to _another_ remote promise P2 (in a third vat), which _at the same + # time_ happens to resolve to Bob (in a fourth vat). In this case, we're shortening from a 3-hop + # path (with four parties) to a 1-hop path (Alice -> Bob). + # + # Extending the embargo/disembargo protocol to be able to shorted multiple hops at once seems + # difficult. Instead, we make a rule that prevents this case from coming up: + # + # One a promise P has been resolved to a remove object reference R, then all further messages + # received addressed to P will be forwarded strictly to R. Even if it turns out later that R is + # itself a promise, and has resolved to some other object Q, messages sent to P will still be + # forwarded to R, not directly to Q (R will of course further forward the messages to Q). + # + # This rule does not cause a significant performance burden because once P has resolved to R, it + # is expected that people sending messages to P will shortly start sending them to R instead and + # drop P. P is at end-of-life anyway, so it doesn't matter if it ignores chances to further + # optimize its path. + + target @0 :MessageTarget; + # What is to be disembargoed. + + using EmbargoId = UInt32; + # Used in `senderLoopback` and `receiverLoopback`, below. + + context :union { + senderLoopback @1 :EmbargoId; + # The sender is requesting a disembargo on a promise that is known to resolve back to a + # capability hosted by the sender. As soon as the receiver has echoed back all pipelined calls + # on this promise, it will deliver the Disembargo back to the sender with `receiverLoopback` + # set to the same value as `senderLoopback`. This value is chosen by the sender, and since + # it is also consumed be the sender, the sender can use whatever strategy it wants to make sure + # the value is unambiguous. + # + # The receiver must verify that the target capability actually resolves back to the sender's + # vat. Otherwise, the sender has committed a protocol error and should be disconnected. + + receiverLoopback @2 :EmbargoId; + # The receiver previously sent a `senderLoopback` Disembargo towards a promise resolving to + # this capability, and that Disembargo is now being echoed back. + + accept @3 :Void; + # **(level 3)** + # + # The sender is requesting a disembargo on a promise that is known to resolve to a third-party + # capability that the sender is currently in the process of accepting (using `Accept`). + # The receiver of this `Disembargo` has an outstanding `Provide` on said capability. The + # receiver should now send a `Disembargo` with `provide` set to the question ID of that + # `Provide` message. + # + # See `Accept.embargo` for an example. + + provide @4 :QuestionId; + # **(level 3)** + # + # The sender is requesting a disembargo on a capability currently being provided to a third + # party. The question ID identifies the `Provide` message previously sent by the sender to + # this capability. On receipt, the receiver (the capability host) shall release the embargo + # on the `Accept` message that it has received from the third party. See `Accept.embargo` for + # an example. + } +} + +# Level 2 message types ---------------------------------------------- + +# See persistent.capnp. + +# Level 3 message types ---------------------------------------------- + +struct Provide { + # **(level 3)** + # + # Message type sent to indicate that the sender wishes to make a particular capability implemented + # by the receiver available to a third party for direct access (without the need for the third + # party to proxy through the sender). + # + # (In CapTP, `Provide` and `Accept` are methods of the global `NonceLocator` object exported by + # every vat. In Cap'n Proto, we bake this into the core protocol.) + + questionId @0 :QuestionId; + # Question ID to be held open until the recipient has received the capability. A result will be + # returned once the third party has successfully received the capability. The sender must at some + # point send a `Finish` message as with any other call, and that message can be used to cancel the + # whole operation. + + target @1 :MessageTarget; + # What is to be provided to the third party. + + recipient @2 :RecipientId; + # Identity of the third party that is expected to pick up the capability. +} + +struct Accept { + # **(level 3)** + # + # Message type sent to pick up a capability hosted by the receiving vat and provided by a third + # party. The third party previously designated the capability using `Provide`. + # + # This message is also used to pick up a redirected return -- see `Return.redirect`. + + questionId @0 :QuestionId; + # A new question ID identifying this accept message, which will eventually receive a Return + # message containing the provided capability (or the call result in the case of a redirected + # return). + + provision @1 :ProvisionId; + # Identifies the provided object to be picked up. + + embargo @2 :Bool; + # If true, this accept shall be temporarily embargoed. The resulting `Return` will not be sent, + # and any pipelined calls will not be delivered, until the embargo is released. The receiver + # (the capability host) will expect the provider (the vat that sent the `Provide` message) to + # eventually send a `Disembargo` message with the field `context.provide` set to the question ID + # of the original `Provide` message. At that point, the embargo is released and the queued + # messages are delivered. + # + # For example: + # - Alice, in Vat A, holds a promise P, which currently points toward Vat B. + # - Alice calls foo() on P. The `Call` message is sent to Vat B. + # - The promise P in Vat B ends up resolving to Carol, in Vat C. + # - Vat B sends a `Provide` message to Vat C, identifying Vat A as the recipient. + # - Vat B sends a `Resolve` message to Vat A, indicating that the promise has resolved to a + # `ThirdPartyCapId` identifying Carol in Vat C. + # - Vat A sends an `Accept` message to Vat C to pick up the capability. Since Vat A knows that + # it has an outstanding call to the promise, it sets `embargo` to `true` in the `Accept` + # message. + # - Vat A sends a `Disembargo` message to Vat B on promise P, with `context.accept` set. + # - Alice makes a call bar() to promise P, which is now pointing towards Vat C. Alice doesn't + # know anything about the mechanics of promise resolution happening under the hood, but she + # expects that bar() will be delivered after foo() because that is the order in which she + # initiated the calls. + # - Vat A sends the bar() call to Vat C, as a pipelined call on the result of the `Accept` (which + # hasn't returned yet, due to the embargo). Since calls to the newly-accepted capability + # are embargoed, Vat C does not deliver the call yet. + # - At some point, Vat B forwards the foo() call from the beginning of this example on to Vat C. + # - Vat B forwards the `Disembargo` from Vat A on to vat C. It sets `context.provide` to the + # question ID of the `Provide` message it had sent previously. + # - Vat C receives foo() before `Disembargo`, thus allowing it to correctly deliver foo() + # before delivering bar(). + # - Vat C receives `Disembargo` from Vat B. It can now send a `Return` for the `Accept` from + # Vat A, as well as deliver bar(). +} + +# Level 4 message types ---------------------------------------------- + +struct Join { + # **(level 4)** + # + # Message type sent to implement E.join(), which, given a number of capabilities that are + # expected to be equivalent, finds the underlying object upon which they all agree and forms a + # direct connection to it, skipping any proxies that may have been constructed by other vats + # while transmitting the capability. See: + # http://erights.org/elib/equality/index.html + # + # Note that this should only serve to bypass fully-transparent proxies -- proxies that were + # created merely for convenience, without any intention of hiding the underlying object. + # + # For example, say Bob holds two capabilities hosted by Alice and Carol, but he expects that both + # are simply proxies for a capability hosted elsewhere. He then issues a join request, which + # operates as follows: + # - Bob issues Join requests on both Alice and Carol. Each request contains a different piece + # of the JoinKey. + # - Alice is proxying a capability hosted by Dana, so forwards the request to Dana's cap. + # - Dana receives the first request and sees that the JoinKeyPart is one of two. She notes that + # she doesn't have the other part yet, so she records the request and responds with a + # JoinResult. + # - Alice relays the JoinAswer back to Bob. + # - Carol is also proxying a capability from Dana, and so forwards her Join request to Dana as + # well. + # - Dana receives Carol's request and notes that she now has both parts of a JoinKey. She + # combines them in order to form information needed to form a secure connection to Bob. She + # also responds with another JoinResult. + # - Bob receives the responses from Alice and Carol. He uses the returned JoinResults to + # determine how to connect to Dana and attempts to form the connection. Since Bob and Dana now + # agree on a secret key that neither Alice nor Carol ever saw, this connection can be made + # securely even if Alice or Carol is conspiring against the other. (If Alice and Carol are + # conspiring _together_, they can obviously reproduce the key, but this doesn't matter because + # the whole point of the join is to verify that Alice and Carol agree on what capability they + # are proxying.) + # + # If the two capabilities aren't actually proxies of the same object, then the join requests + # will come back with conflicting `hostId`s and the join will fail before attempting to form any + # connection. + + questionId @0 :QuestionId; + # Question ID used to respond to this Join. (Note that this ID only identifies one part of the + # request for one hop; each part has a different ID and relayed copies of the request have + # (probably) different IDs still.) + # + # The receiver will reply with a `Return` whose `results` is a JoinResult. This `JoinResult` + # is relayed from the joined object's host, possibly with transformation applied as needed + # by the network. + # + # Like any return, the result must be released using a `Finish`. However, this release + # should not occur until the joiner has either successfully connected to the joined object. + # Vats relaying a `Join` message similarly must not release the result they receive until the + # return they relayed back towards the joiner has itself been released. This allows the + # joined object's host to detect when the Join operation is canceled before completing -- if + # it receives a `Finish` for one of the join results before the joiner successfully + # connects. It can then free any resources it had allocated as part of the join. + + target @1 :MessageTarget; + # The capability to join. + + keyPart @2 :JoinKeyPart; + # A part of the join key. These combine to form the complete join key, which is used to establish + # a direct connection. + + # TODO(before implementing): Change this so that multiple parts can be sent in a single Join + # message, so that if multiple join parts are going to cross the same connection they can be sent + # together, so that the receive can potentially optimize its handling of them. In the case where + # all parts are bundled together, should the recipient be expected to simply return a cap, so + # that the caller can immediately start pipelining to it? +} + +# ======================================================================================== +# Common structures used in messages + +struct MessageTarget { + # The target of a `Call` or other messages that target a capability. + + union { + importedCap @0 :ImportId; + # This message is to a capability or promise previously imported by the caller (exported by + # the receiver). + + promisedAnswer @1 :PromisedAnswer; + # This message is to a capability that is expected to be returned by another call that has not + # yet been completed. + # + # At level 0, this is supported only for addressing the result of a previous `Bootstrap`, so + # that initial startup doesn't require a round trip. + } +} + +struct Payload { + # Represents some data structure that might contain capabilities. + + content @0 :AnyPointer; + # Some Cap'n Proto data structure. Capability pointers embedded in this structure index into + # `capTable`. + + capTable @1 :List(CapDescriptor); + # Descriptors corresponding to the cap pointers in `content`. +} + +struct CapDescriptor { + # **(level 1)** + # + # When an application-defined type contains an interface pointer, that pointer contains an index + # into the message's capability table -- i.e. the `capTable` part of the `Payload`. Each + # capability in the table is represented as a `CapDescriptor`. The runtime API should not reveal + # the CapDescriptor directly to the application, but should instead wrap it in some kind of + # callable object with methods corresponding to the interface that the capability implements. + # + # Keep in mind that `ExportIds` in a `CapDescriptor` are subject to reference counting. See the + # description of `ExportId`. + + union { + none @0 :Void; + # There is no capability here. This `CapDescriptor` should not appear in the payload content. + # A `none` CapDescriptor can be generated when an application inserts a capability into a + # message and then later changes its mind and removes it -- rewriting all of the other + # capability pointers may be hard, so instead a tombstone is left, similar to the way a removed + # struct or list instance is zeroed out of the message but the space is not reclaimed. + # Hopefully this is unusual. + + senderHosted @1 :ExportId; + # A capability newly exported by the sender. This is the ID of the new capability in the + # sender's export table (receiver's import table). + + senderPromise @2 :ExportId; + # A promise that the sender will resolve later. The sender will send exactly one Resolve + # message at a future point in time to replace this promise. Note that even if the same + # `senderPromise` is received multiple times, only one `Resolve` is sent to cover all of + # them. If `senderPromise` is released before the `Resolve` is sent, the sender (of this + # `CapDescriptor`) may choose not to send the `Resolve` at all. + + receiverHosted @3 :ImportId; + # A capability (or promise) previously exported by the receiver (imported by the sender). + + receiverAnswer @4 :PromisedAnswer; + # A capability expected to be returned in the results of a currently-outstanding call posed + # by the sender. + + thirdPartyHosted @5 :ThirdPartyCapDescriptor; + # **(level 3)** + # + # A capability that lives in neither the sender's nor the receiver's vat. The sender needs + # to form a direct connection to a third party to pick up the capability. + # + # Level 1 and 2 implementations that receive a `thirdPartyHosted` may simply send calls to its + # `vine` instead. + } +} + +struct PromisedAnswer { + # **(mostly level 1)** + # + # Specifies how to derive a promise from an unanswered question, by specifying the path of fields + # to follow from the root of the eventual result struct to get to the desired capability. Used + # to address method calls to a not-yet-returned capability or to pass such a capability as an + # input to some other method call. + # + # Level 0 implementations must support `PromisedAnswer` only for the case where the answer is + # to a `Bootstrap` message. In this case, `path` is always empty since `Bootstrap` always returns + # a raw capability. + + questionId @0 :QuestionId; + # ID of the question (in the sender's question table / receiver's answer table) whose answer is + # expected to contain the capability. + + transform @1 :List(Op); + # Operations / transformations to apply to the result in order to get the capability actually + # being addressed. E.g. if the result is a struct and you want to call a method on a capability + # pointed to by a field of the struct, you need a `getPointerField` op. + + struct Op { + union { + noop @0 :Void; + # Does nothing. This member is mostly defined so that we can make `Op` a union even + # though (as of this writing) only one real operation is defined. + + getPointerField @1 :UInt16; + # Get a pointer field within a struct. The number is an index into the pointer section, NOT + # a field ordinal, so that the receiver does not need to understand the schema. + + # TODO(someday): We could add: + # - For lists, the ability to address every member of the list, or a slice of the list, the + # result of which would be another list. This is useful for implementing the equivalent of + # a SQL table join (not to be confused with the `Join` message type). + # - Maybe some ability to test a union. + # - Probably not a good idea: the ability to specify an arbitrary script to run on the + # result. We could define a little stack-based language where `Op` specifies one + # "instruction" or transformation to apply. Although this is not a good idea + # (over-engineered), any narrower additions to `Op` should be designed as if this + # were the eventual goal. + } + } +} + +struct ThirdPartyCapDescriptor { + # **(level 3)** + # + # Identifies a capability in a third-party vat that the sender wants the receiver to pick up. + + id @0 :ThirdPartyCapId; + # Identifies the third-party host and the specific capability to accept from it. + + vineId @1 :ExportId; + # A proxy for the third-party object exported by the sender. In CapTP terminology this is called + # a "vine", because it is an indirect reference to the third-party object that snakes through the + # sender vat. This serves two purposes: + # + # * Level 1 and 2 implementations that don't understand how to connect to a third party may + # simply send calls to the vine. Such calls will be forwarded to the third-party by the + # sender. + # + # * Level 3 implementations must release the vine once they have successfully picked up the + # object from the third party. This ensures that the capability is not released by the sender + # prematurely. + # + # The sender will close the `Provide` request that it has sent to the third party as soon as + # it receives either a `Call` or a `Release` message directed at the vine. +} + +struct Exception { + # **(level 0)** + # + # Describes an arbitrary error that prevented an operation (e.g. a call) from completing. + # + # Cap'n Proto exceptions always indicate that something went wrong. In other words, in a fantasy + # world where everything always works as expected, no exceptions would ever be thrown. Clients + # should only ever catch exceptions as a means to implement fault-tolerance, where "fault" can + # mean: + # - Bugs. + # - Invalid input. + # - Configuration errors. + # - Network problems. + # - Insufficient resources. + # - Version skew (unimplemented functionality). + # - Other logistical problems. + # + # Exceptions should NOT be used to flag application-specific conditions that a client is expected + # to handle in an application-specific way. Put another way, in the Cap'n Proto world, + # "checked exceptions" (where an interface explicitly defines the exceptions it throws and + # clients are forced by the type system to handle those exceptions) do NOT make sense. + + reason @0 :Text; + # Human-readable failure description. + + type @3 :Type; + # The type of the error. The purpose of this enum is not to describe the error itself, but + # rather to describe how the client might want to respond to the error. + + enum Type { + failed @0; + # A generic problem occurred, and it is believed that if the operation were repeated without + # any change in the state of the world, the problem would occur again. + # + # A client might respond to this error by logging it for investigation by the developer and/or + # displaying it to the user. + + overloaded @1; + # The request was rejected due to a temporary lack of resources. + # + # Examples include: + # - There's not enough CPU time to keep up with incoming requests, so some are rejected. + # - The server ran out of RAM or disk space during the request. + # - The operation timed out (took significantly longer than it should have). + # + # A client might respond to this error by scheduling to retry the operation much later. The + # client should NOT retry again immediately since this would likely exacerbate the problem. + + disconnected @2; + # The method failed because a connection to some necessary capability was lost. + # + # Examples include: + # - The client introduced the server to a third-party capability, the connection to that third + # party was subsequently lost, and then the client requested that the server use the dead + # capability for something. + # - The client previously requested that the server obtain a capability from some third party. + # The server returned a capability to an object wrapping the third-party capability. Later, + # the server's connection to the third party was lost. + # - The capability has been revoked. Revocation does not necessarily mean that the client is + # no longer authorized to use the capability; it is often used simply as a way to force the + # client to repeat the setup process, perhaps to efficiently move them to a new back-end or + # get them to recognize some other change that has occurred. + # + # A client should normally respond to this error by releasing all capabilities it is currently + # holding related to the one it called and then re-creating them by restoring SturdyRefs and/or + # repeating the method calls used to create them originally. In other words, disconnect and + # start over. This should in turn cause the server to obtain a new copy of the capability that + # it lost, thus making everything work. + # + # If the client receives another `disconnencted` error in the process of rebuilding the + # capability and retrying the call, it should treat this as an `overloaded` error: the network + # is currently unreliable, possibly due to load or other temporary issues. + + unimplemented @3; + # The server doesn't implement the requested method. If there is some other method that the + # client could call (perhaps an older and/or slower interface), it should try that instead. + # Otherwise, this should be treated like `failed`. + } + + obsoleteIsCallersFault @1 :Bool; + # OBSOLETE. Ignore. + + obsoleteDurability @2 :UInt16; + # OBSOLETE. See `type` instead. +} + +# ======================================================================================== +# Network-specific Parameters +# +# Some parts of the Cap'n Proto RPC protocol are not specified here because different vat networks +# may wish to use different approaches to solving them. For example, on the public internet, you +# may want to authenticate vats using public-key cryptography, but on a local intranet with trusted +# infrastructure, you may be happy to authenticate based on network address only, or some other +# lightweight mechanism. +# +# To accommodate this, we specify several "parameter" types. Each type is defined here as an +# alias for `AnyPointer`, but a specific network will want to define a specific set of types to use. +# All vats in a vat network must agree on these parameters in order to be able to communicate. +# Inter-network communication can be accomplished through "gateways" that perform translation +# between the primitives used on each network; these gateways may need to be deeply stateful, +# depending on the translations they perform. +# +# For interaction over the global internet between parties with no other prior arrangement, a +# particular set of bindings for these types is defined elsewhere. (TODO(someday): Specify where +# these common definitions live.) +# +# Another common network type is the two-party network, in which one of the parties typically +# interacts with the outside world entirely through the other party. In such a connection between +# Alice and Bob, all objects that exist on Bob's other networks appear to Alice as if they were +# hosted by Bob himself, and similarly all objects on Alice's network (if she even has one) appear +# to Bob as if they were hosted by Alice. This network type is interesting because from the point +# of view of a simple application that communicates with only one other party via the two-party +# protocol, there are no three-party interactions at all, and joins are unusually simple to +# implement, so implementing at level 4 is barely more complicated than implementing at level 1. +# Moreover, if you pair an app implementing the two-party network with a container that implements +# some other network, the app can then participate on the container's network just as if it +# implemented that network directly. The types used by the two-party network are defined in +# `rpc-twoparty.capnp`. +# +# The things that we need to parameterize are: +# - How to store capabilities long-term without holding a connection open (mostly level 2). +# - How to authenticate vats in three-party introductions (level 3). +# - How to implement `Join` (level 4). +# +# Persistent references +# --------------------- +# +# **(mostly level 2)** +# +# We want to allow some capabilities to be stored long-term, even if a connection is lost and later +# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't +# help here. We need a way to specify long-term identifiers, as well as a strategy for +# reconnecting to a referenced capability later. +# +# Three-party interactions +# ------------------------ +# +# **(level 3)** +# +# In cases where more than two vats are interacting, we have situations where VatA holds a +# capability hosted by VatB and wants to send that capability to VatC. This can be accomplished +# by VatA proxying requests on the new capability, but doing so has two big problems: +# - It's inefficient, requiring an extra network hop. +# - If VatC receives another capability to the same object from VatD, it is difficult for VatC to +# detect that the two capabilities are really the same and to implement the E "join" operation, +# which is necessary for certain four-or-more-party interactions, such as the escrow pattern. +# See: http://www.erights.org/elib/equality/grant-matcher/index.html +# +# Instead, we want a way for VatC to form a direct, authenticated connection to VatB. +# +# Join +# ---- +# +# **(level 4)** +# +# The `Join` message type and corresponding operation arranges for a direct connection to be formed +# between the joiner and the host of the joined object, and this connection must be authenticated. +# Thus, the details are network-dependent. + +using SturdyRef = AnyPointer; +# **(level 2)** +# +# Identifies a persisted capability that can be restored in the future. How exactly a SturdyRef +# is restored to a live object is specified along with the SturdyRef definition (i.e. not by +# rpc.capnp). +# +# Generally a SturdyRef needs to specify three things: +# - How to reach the vat that can restore the ref (e.g. a hostname or IP address). +# - How to authenticate the vat after connecting (e.g. a public key fingerprint). +# - The identity of a specific object hosted by the vat. Generally, this is an opaque pointer whose +# format is defined by the specific vat -- the client has no need to inspect the object ID. +# It is important that the objec ID be unguessable if the object is not public (and objects +# should almost never be public). +# +# The above are only suggestions. Some networks might work differently. For example, a private +# network might employ a special restorer service whose sole purpose is to restore SturdyRefs. +# In this case, the entire contents of SturdyRef might be opaque, because they are intended only +# to be forwarded to the restorer service. + +using ProvisionId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in an `Accept` message to identify the object being accepted. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the provider vat along with the question ID used in the `Provide` message sent from +# that provider. + +using RecipientId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in a `Provide` message to identify the recipient of the +# capability. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the recipient. (CapTP also calls for a nonce to identify the object. In our +# case, the `Provide` message's `questionId` can serve as the nonce.) + +using ThirdPartyCapId = AnyPointer; +# **(level 3)** +# +# The information needed to connect to a third party and accept a capability from it. +# +# In a network where each vat has a public/private key pair, this could be a combination of the +# third party's public key fingerprint, hints on how to connect to the third party (e.g. an IP +# address), and the question ID used in the corresponding `Provide` message sent to that third party +# (used to identify which capability to pick up). + +using JoinKeyPart = AnyPointer; +# **(level 4)** +# +# A piece of a secret key. One piece is sent along each path that is expected to lead to the same +# place. Once the pieces are combined, a direct connection may be formed between the sender and +# the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type. +# +# The motivation for Joins is discussed under "Supporting Equality" in the "Unibus" protocol +# sketch: http://www.erights.org/elib/distrib/captp/unibus.html +# +# In a network where each vat has a public/private key pair and each vat forms no more than one +# connection to each other vat, Joins will rarely -- perhaps never -- be needed, as objects never +# need to be transparently proxied and references to the same object sent over the same connection +# have the same export ID. Thus, a successful join requires only checking that the two objects +# come from the same connection and have the same ID, and then completes immediately. +# +# However, in networks where two vats may form more than one connection between each other, or +# where proxying of objects occurs, joins are necessary. +# +# Typically, each JoinKeyPart would include a fixed-length data value such that all value parts +# XOR'd together forms a shared secret that can be used to form an encrypted connection between +# the joiner and the joined object's host. Each JoinKeyPart should also include an indication of +# how many parts to expect and a hash of the shared secret (used to match up parts). + +using JoinResult = AnyPointer; +# **(level 4)** +# +# Information returned as the result to a `Join` message, needed by the joiner in order to form a +# direct connection to a joined object. This might simply be the address of the joined object's +# host vat, since the `JoinKey` has already been communicated so the two vats already have a shared +# secret to use to authenticate each other. +# +# The `JoinResult` should also contain information that can be used to detect when the Join +# requests ended up reaching different objects, so that this situation can be detected easily. +# This could be a simple matter of including a sequence number -- if the joiner receives two +# `JoinResult`s with sequence number 0, then they must have come from different objects and the +# whole join is a failure. + +# ======================================================================================== +# Network interface sketch +# +# The interfaces below are meant to be pseudo-code to illustrate how the details of a particular +# vat network might be abstracted away. They are written like Cap'n Proto interfaces, but in +# practice you'd probably define these interfaces manually in the target programming language. A +# Cap'n Proto RPC implementation should be able to use these interfaces without knowing the +# definitions of the various network-specific parameters defined above. + +# interface VatNetwork { +# # Represents a vat network, with the ability to connect to particular vats and receive +# # connections from vats. +# # +# # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the +# # caller is expected to find and share state with existing users of the connection. +# +# # Level 0 features ----------------------------------------------- +# +# connect(vatId :VatId) :Connection; +# # Connect to the given vat. The transport should return a promise that does not +# # resolve until authentication has completed, but allows messages to be pipelined in before +# # that; the transport either queues these messages until authenticated, or sends them encrypted +# # such that only the authentic vat would be able to decrypt them. The latter approach avoids a +# # round trip for authentication. +# +# accept() :Connection; +# # Wait for the next incoming connection and return it. Only connections formed by +# # connect() are returned by this method. +# +# # Level 4 features ----------------------------------------------- +# +# newJoiner(count :UInt32) :NewJoinerResponse; +# # Prepare a new Join operation, which will eventually lead to forming a new direct connection +# # to the host of the joined capability. `count` is the number of capabilities to join. +# +# struct NewJoinerResponse { +# joinKeyParts :List(JoinKeyPart); +# # Key parts to send in Join messages to each capability. +# +# joiner :Joiner; +# # Used to establish the final connection. +# } +# +# interface Joiner { +# addJoinResult(result :JoinResult) :Void; +# # Add a JoinResult received in response to one of the `Join` messages. All `JoinResult`s +# # returned from all paths must be added before trying to connect. +# +# connect() :ConnectionAndProvisionId; +# # Try to form a connection to the joined capability's host, verifying that it has received +# # all of the JoinKeyParts. Once the connection is formed, the caller should send an `Accept` +# # message on it with the specified `ProvisionId` in order to receive the final capability. +# } +# +# acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath)) +# :ConnectionAndProvisionId; +# # Called on a joined capability's host to receive the connection from the joiner, once all +# # key parts have arrived. The caller should expect to receive an `Accept` message over the +# # connection with the given ProvisionId. +# } +# +# interface Connection { +# # Level 0 features ----------------------------------------------- +# +# send(message :Message) :Void; +# # Send the message. Returns successfully when the message (and all preceding messages) has +# # been acknowledged by the recipient. +# +# receive() :Message; +# # Receive the next message, and acknowledges receipt to the sender. Messages are received in +# # the order in which they are sent. +# +# # Level 3 features ----------------------------------------------- +# +# introduceTo(recipient :Connection) :IntroductionInfo; +# # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on +# # this connection and a `ThirdPartyCapId` is to be sent to `recipient`. +# +# struct IntroductionInfo { +# sendToRecipient :ThirdPartyCapId; +# sendToTarget :RecipientId; +# } +# +# connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId; +# # Given a ThirdPartyCapId received over this connection, connect to the third party. The +# # caller should then send an `Accept` message over the new connection. +# +# acceptIntroducedConnection(recipientId :RecipientId) :Connection; +# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the +# # recipient to connect, and return the connection formed. Usually, the first message received +# # on the new connection will be an `Accept` message. +# } +# +# struct ConnectionAndProvisionId { +# # **(level 3)** +# +# connection :Connection; +# # Connection on which to issue `Accept` message. +# +# provision :ProvisionId; +# # `ProvisionId` to send in the `Accept` message. +# } diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,2055 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc.capnp + +#include "rpc.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<232> b_91b79f1f808db032 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 50, 176, 141, 128, 31, 159, 183, 145, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 23, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 77, 101, 115, 115, 97, 103, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 56, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 120, 1, 0, 0, 3, 0, 1, 0, + 132, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 129, 1, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 124, 1, 0, 0, 3, 0, 1, 0, + 136, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 253, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 1, 0, 0, 3, 0, 1, 0, + 140, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 137, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 1, 0, 0, 3, 0, 1, 0, + 144, 1, 0, 0, 2, 0, 1, 0, + 5, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 136, 1, 0, 0, 3, 0, 1, 0, + 148, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 145, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 140, 1, 0, 0, 3, 0, 1, 0, + 152, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 249, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 149, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 144, 1, 0, 0, 3, 0, 1, 0, + 156, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 248, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 152, 1, 0, 0, 3, 0, 1, 0, + 164, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 247, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 161, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 1, 0, 0, 3, 0, 1, 0, + 172, 1, 0, 0, 2, 0, 1, 0, + 10, 0, 246, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 169, 1, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 1, 0, 0, 3, 0, 1, 0, + 180, 1, 0, 0, 2, 0, 1, 0, + 11, 0, 245, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 172, 1, 0, 0, 3, 0, 1, 0, + 184, 1, 0, 0, 2, 0, 1, 0, + 12, 0, 244, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 1, 0, 0, 3, 0, 1, 0, + 188, 1, 0, 0, 2, 0, 1, 0, + 13, 0, 243, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 1, 0, 0, 3, 0, 1, 0, + 192, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 242, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 188, 1, 0, 0, 3, 0, 1, 0, + 200, 1, 0, 0, 2, 0, 1, 0, + 117, 110, 105, 109, 112, 108, 101, 109, + 101, 110, 116, 101, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 50, 176, 141, 128, 31, 159, 183, 145, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 98, 111, 114, 116, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 26, 105, 207, 58, 6, 183, 37, 214, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 108, 108, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 212, 76, 157, 120, 206, 83, 106, 131, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 116, 117, 114, 110, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 58, 87, 179, 61, 141, 178, 25, 158, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 110, 105, 115, 104, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 99, 14, 248, 194, 178, 46, 125, 211, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 111, 108, 118, 101, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 110, 8, 137, 250, 85, 150, 194, 187, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 108, 101, 97, 115, 101, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 151, 116, 208, 125, 13, 108, 26, 173, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 98, 115, 111, 108, 101, 116, 101, + 83, 97, 118, 101, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 111, 111, 116, 115, 116, 114, 97, + 112, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 196, 110, 23, 49, 128, 207, 76, 233, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 98, 115, 111, 108, 101, 116, 101, + 68, 101, 108, 101, 116, 101, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 114, 111, 118, 105, 100, 101, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 90, 172, 193, 251, 107, 4, 106, 156, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 99, 99, 101, 112, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 22, 64, 85, 144, 98, 181, 201, 212, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 106, 111, 105, 110, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 175, 1, 224, 144, 4, 152, 225, 251, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 101, 109, 98, 97, 114, + 103, 111, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 17, 55, 189, 15, 139, 54, 100, 249, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_91b79f1f808db032 = b_91b79f1f808db032.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_91b79f1f808db032[] = { + &s_836a53ce789d4cd4, + &s_91b79f1f808db032, + &s_9c6a046bfbc1ac5a, + &s_9e19b28d3db3573a, + &s_ad1a6c0d7dd07497, + &s_bbc29655fa89086e, + &s_d37d2eb2c2f80e63, + &s_d4c9b56290554016, + &s_d625b7063acf691a, + &s_e94ccf8031176ec4, + &s_f964368b0fbd3711, + &s_fbe1980490e001af, +}; +static const uint16_t m_91b79f1f808db032[] = {1, 11, 8, 2, 13, 4, 12, 9, 7, 10, 6, 5, 3, 0}; +static const uint16_t i_91b79f1f808db032[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; +const ::capnp::_::RawSchema s_91b79f1f808db032 = { + 0x91b79f1f808db032, b_91b79f1f808db032.words, 232, d_91b79f1f808db032, m_91b79f1f808db032, + 12, 14, i_91b79f1f808db032, nullptr, nullptr, { &s_91b79f1f808db032, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<51> b_e94ccf8031176ec4 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 196, 110, 23, 49, 128, 207, 76, 233, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 210, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 66, 111, 111, 116, 115, 116, 114, 97, + 112, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 154, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 3, 0, 1, 0, + 64, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 101, 112, 114, 101, 99, 97, 116, + 101, 100, 79, 98, 106, 101, 99, 116, + 73, 100, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e94ccf8031176ec4 = b_e94ccf8031176ec4.words; +#if !CAPNP_LITE +static const uint16_t m_e94ccf8031176ec4[] = {1, 0}; +static const uint16_t i_e94ccf8031176ec4[] = {0, 1}; +const ::capnp::_::RawSchema s_e94ccf8031176ec4 = { + 0xe94ccf8031176ec4, b_e94ccf8031176ec4.words, 51, nullptr, m_e94ccf8031176ec4, + 0, 2, i_e94ccf8031176ec4, nullptr, nullptr, { &s_e94ccf8031176ec4, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<121> b_836a53ce789d4cd4 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 212, 76, 157, 120, 206, 83, 106, 131, + 16, 0, 0, 0, 1, 0, 3, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 3, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 170, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 143, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 67, 97, 108, 108, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 28, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 0, 0, 0, 3, 0, 1, 0, + 192, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 0, 0, 0, 3, 0, 1, 0, + 196, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 3, 0, 1, 0, + 204, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 201, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 200, 0, 0, 0, 3, 0, 1, 0, + 212, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 209, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 204, 0, 0, 0, 3, 0, 1, 0, + 216, 0, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 153, 95, 171, 26, 246, 176, 232, 218, + 213, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 128, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 193, 0, 0, 0, 194, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 3, 0, 1, 0, + 208, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 193, 251, 19, 88, 84, 20, 188, 149, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 73, 100, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 109, 101, 116, 104, 111, 100, 73, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 115, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 59, 116, 150, 61, 34, 97, 14, 154, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 101, 110, 100, 82, 101, 115, 117, + 108, 116, 115, 84, 111, 0, 0, 0, + 97, 108, 108, 111, 119, 84, 104, 105, + 114, 100, 80, 97, 114, 116, 121, 84, + 97, 105, 108, 67, 97, 108, 108, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_836a53ce789d4cd4 = b_836a53ce789d4cd4.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_836a53ce789d4cd4[] = { + &s_95bc14545813fbc1, + &s_9a0e61223d96743b, + &s_dae8b0f61aab5f99, +}; +static const uint16_t m_836a53ce789d4cd4[] = {6, 2, 3, 4, 0, 5, 1}; +static const uint16_t i_836a53ce789d4cd4[] = {0, 1, 2, 3, 4, 5, 6}; +const ::capnp::_::RawSchema s_836a53ce789d4cd4 = { + 0x836a53ce789d4cd4, b_836a53ce789d4cd4.words, 121, d_836a53ce789d4cd4, m_836a53ce789d4cd4, + 3, 7, i_836a53ce789d4cd4, nullptr, nullptr, { &s_836a53ce789d4cd4, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<65> b_dae8b0f61aab5f99 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 153, 95, 171, 26, 246, 176, 232, 218, + 21, 0, 0, 0, 1, 0, 3, 0, + 212, 76, 157, 120, 206, 83, 106, 131, + 3, 0, 7, 0, 1, 0, 3, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 26, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 67, 97, 108, 108, 46, 115, 101, 110, + 100, 82, 101, 115, 117, 108, 116, 115, + 84, 111, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 2, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 3, 0, 1, 0, + 92, 0, 0, 0, 2, 0, 1, 0, + 99, 97, 108, 108, 101, 114, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 111, 117, 114, 115, 101, 108, 102, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 104, 105, 114, 100, 80, 97, 114, + 116, 121, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_dae8b0f61aab5f99 = b_dae8b0f61aab5f99.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_dae8b0f61aab5f99[] = { + &s_836a53ce789d4cd4, +}; +static const uint16_t m_dae8b0f61aab5f99[] = {0, 2, 1}; +static const uint16_t i_dae8b0f61aab5f99[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_dae8b0f61aab5f99 = { + 0xdae8b0f61aab5f99, b_dae8b0f61aab5f99.words, 65, d_dae8b0f61aab5f99, m_dae8b0f61aab5f99, + 1, 3, i_dae8b0f61aab5f99, nullptr, nullptr, { &s_dae8b0f61aab5f99, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<148> b_9e19b28d3db3573a = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 58, 87, 179, 61, 141, 178, 25, 158, + 16, 0, 0, 0, 1, 0, 2, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 6, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 186, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 199, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 82, 101, 116, 117, 114, 110, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 32, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 209, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 208, 0, 0, 0, 3, 0, 1, 0, + 220, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 217, 0, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 3, 0, 1, 0, + 232, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 229, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 3, 0, 1, 0, + 236, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 233, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 232, 0, 0, 0, 3, 0, 1, 0, + 244, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 253, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 241, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 3, 0, 1, 0, + 252, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 249, 0, 0, 0, 170, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 252, 0, 0, 0, 3, 0, 1, 0, + 8, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 251, 255, 2, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 1, 0, 0, 178, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 1, 0, 0, 3, 0, 1, 0, + 20, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 1, 0, 0, 170, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 1, 0, 0, 3, 0, 1, 0, + 32, 1, 0, 0, 2, 0, 1, 0, + 97, 110, 115, 119, 101, 114, 73, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 108, 101, 97, 115, 101, 80, + 97, 114, 97, 109, 67, 97, 112, 115, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 117, 108, 116, 115, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 59, 116, 150, 61, 34, 97, 14, 154, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 120, 99, 101, 112, 116, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 26, 105, 207, 58, 6, 183, 37, 214, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 110, 99, 101, 108, 101, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 117, 108, 116, 115, 83, + 101, 110, 116, 69, 108, 115, 101, 119, + 104, 101, 114, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 107, 101, 70, 114, 111, 109, + 79, 116, 104, 101, 114, 81, 117, 101, + 115, 116, 105, 111, 110, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 99, 99, 101, 112, 116, 70, 114, + 111, 109, 84, 104, 105, 114, 100, 80, + 97, 114, 116, 121, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9e19b28d3db3573a = b_9e19b28d3db3573a.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9e19b28d3db3573a[] = { + &s_9a0e61223d96743b, + &s_d625b7063acf691a, +}; +static const uint16_t m_9e19b28d3db3573a[] = {7, 0, 4, 3, 1, 2, 5, 6}; +static const uint16_t i_9e19b28d3db3573a[] = {2, 3, 4, 5, 6, 7, 0, 1}; +const ::capnp::_::RawSchema s_9e19b28d3db3573a = { + 0x9e19b28d3db3573a, b_9e19b28d3db3573a.words, 148, d_9e19b28d3db3573a, m_9e19b28d3db3573a, + 2, 8, i_9e19b28d3db3573a, nullptr, nullptr, { &s_9e19b28d3db3573a, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<50> b_d37d2eb2c2f80e63 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 99, 14, 248, 194, 178, 46, 125, 211, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 186, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 70, 105, 110, 105, 115, 104, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 3, 0, 1, 0, + 64, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 108, 101, 97, 115, 101, 82, + 101, 115, 117, 108, 116, 67, 97, 112, + 115, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d37d2eb2c2f80e63 = b_d37d2eb2c2f80e63.words; +#if !CAPNP_LITE +static const uint16_t m_d37d2eb2c2f80e63[] = {0, 1}; +static const uint16_t i_d37d2eb2c2f80e63[] = {0, 1}; +const ::capnp::_::RawSchema s_d37d2eb2c2f80e63 = { + 0xd37d2eb2c2f80e63, b_d37d2eb2c2f80e63.words, 50, nullptr, m_d37d2eb2c2f80e63, + 0, 2, i_d37d2eb2c2f80e63, nullptr, nullptr, { &s_d37d2eb2c2f80e63, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<64> b_bbc29655fa89086e = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 110, 8, 137, 250, 85, 150, 194, 187, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 2, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 82, 101, 115, 111, 108, 118, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 3, 0, 1, 0, + 92, 0, 0, 0, 2, 0, 1, 0, + 112, 114, 111, 109, 105, 115, 101, 73, + 100, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 176, 184, 134, 11, 196, 221, 35, 133, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 120, 99, 101, 112, 116, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 26, 105, 207, 58, 6, 183, 37, 214, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_bbc29655fa89086e = b_bbc29655fa89086e.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_bbc29655fa89086e[] = { + &s_8523ddc40b86b8b0, + &s_d625b7063acf691a, +}; +static const uint16_t m_bbc29655fa89086e[] = {1, 2, 0}; +static const uint16_t i_bbc29655fa89086e[] = {1, 2, 0}; +const ::capnp::_::RawSchema s_bbc29655fa89086e = { + 0xbbc29655fa89086e, b_bbc29655fa89086e.words, 64, d_bbc29655fa89086e, m_bbc29655fa89086e, + 2, 3, i_bbc29655fa89086e, nullptr, nullptr, { &s_bbc29655fa89086e, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<48> b_ad1a6c0d7dd07497 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 151, 116, 208, 125, 13, 108, 26, 173, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 82, 101, 108, 101, 97, 115, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 56, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 102, 101, 114, 101, 110, 99, + 101, 67, 111, 117, 110, 116, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ad1a6c0d7dd07497 = b_ad1a6c0d7dd07497.words; +#if !CAPNP_LITE +static const uint16_t m_ad1a6c0d7dd07497[] = {0, 1}; +static const uint16_t i_ad1a6c0d7dd07497[] = {0, 1}; +const ::capnp::_::RawSchema s_ad1a6c0d7dd07497 = { + 0xad1a6c0d7dd07497, b_ad1a6c0d7dd07497.words, 48, nullptr, m_ad1a6c0d7dd07497, + 0, 2, i_ad1a6c0d7dd07497, nullptr, nullptr, { &s_ad1a6c0d7dd07497, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<41> b_f964368b0fbd3711 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 17, 55, 189, 15, 139, 54, 100, 249, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 218, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 68, 105, 115, 101, 109, 98, 97, 114, + 103, 111, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 77, 221, 91, 101, 223, 180, 98, 213, + 45, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 193, 251, 19, 88, 84, 20, 188, 149, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 111, 110, 116, 101, 120, 116, 0, } +}; +::capnp::word const* const bp_f964368b0fbd3711 = b_f964368b0fbd3711.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_f964368b0fbd3711[] = { + &s_95bc14545813fbc1, + &s_d562b4df655bdd4d, +}; +static const uint16_t m_f964368b0fbd3711[] = {1, 0}; +static const uint16_t i_f964368b0fbd3711[] = {0, 1}; +const ::capnp::_::RawSchema s_f964368b0fbd3711 = { + 0xf964368b0fbd3711, b_f964368b0fbd3711.words, 41, d_f964368b0fbd3711, m_f964368b0fbd3711, + 2, 2, i_f964368b0fbd3711, nullptr, nullptr, { &s_f964368b0fbd3711, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<81> b_d562b4df655bdd4d = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 77, 221, 91, 101, 223, 180, 98, 213, + 27, 0, 0, 0, 1, 0, 1, 0, + 17, 55, 189, 15, 139, 54, 100, 249, + 1, 0, 7, 0, 1, 0, 4, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 26, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 68, 105, 115, 101, 109, 98, 97, 114, + 103, 111, 46, 99, 111, 110, 116, 101, + 120, 116, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 3, 0, 1, 0, + 108, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 0, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 0, 0, 0, 3, 0, 1, 0, + 120, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 0, 0, 0, 3, 0, 1, 0, + 124, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 0, 0, 0, 3, 0, 1, 0, + 128, 0, 0, 0, 2, 0, 1, 0, + 115, 101, 110, 100, 101, 114, 76, 111, + 111, 112, 98, 97, 99, 107, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 99, 101, 105, 118, 101, 114, + 76, 111, 111, 112, 98, 97, 99, 107, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 99, 99, 101, 112, 116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 114, 111, 118, 105, 100, 101, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d562b4df655bdd4d = b_d562b4df655bdd4d.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d562b4df655bdd4d[] = { + &s_f964368b0fbd3711, +}; +static const uint16_t m_d562b4df655bdd4d[] = {2, 3, 1, 0}; +static const uint16_t i_d562b4df655bdd4d[] = {0, 1, 2, 3}; +const ::capnp::_::RawSchema s_d562b4df655bdd4d = { + 0xd562b4df655bdd4d, b_d562b4df655bdd4d.words, 81, d_d562b4df655bdd4d, m_d562b4df655bdd4d, + 1, 4, i_d562b4df655bdd4d, nullptr, nullptr, { &s_d562b4df655bdd4d, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<64> b_9c6a046bfbc1ac5a = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 90, 172, 193, 251, 107, 4, 106, 156, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 80, 114, 111, 118, 105, 100, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 3, 0, 1, 0, + 92, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 193, 251, 19, 88, 84, 20, 188, 149, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 99, 105, 112, 105, 101, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9c6a046bfbc1ac5a = b_9c6a046bfbc1ac5a.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9c6a046bfbc1ac5a[] = { + &s_95bc14545813fbc1, +}; +static const uint16_t m_9c6a046bfbc1ac5a[] = {0, 2, 1}; +static const uint16_t i_9c6a046bfbc1ac5a[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_9c6a046bfbc1ac5a = { + 0x9c6a046bfbc1ac5a, b_9c6a046bfbc1ac5a.words, 64, d_9c6a046bfbc1ac5a, m_9c6a046bfbc1ac5a, + 1, 3, i_9c6a046bfbc1ac5a, nullptr, nullptr, { &s_9c6a046bfbc1ac5a, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<64> b_d4c9b56290554016 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 22, 64, 85, 144, 98, 181, 201, 212, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 186, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 65, 99, 99, 101, 112, 116, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 3, 0, 1, 0, + 92, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 114, 111, 118, 105, 115, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 109, 98, 97, 114, 103, 111, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d4c9b56290554016 = b_d4c9b56290554016.words; +#if !CAPNP_LITE +static const uint16_t m_d4c9b56290554016[] = {2, 1, 0}; +static const uint16_t i_d4c9b56290554016[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_d4c9b56290554016 = { + 0xd4c9b56290554016, b_d4c9b56290554016.words, 64, nullptr, m_d4c9b56290554016, + 0, 3, i_d4c9b56290554016, nullptr, nullptr, { &s_d4c9b56290554016, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<63> b_fbe1980490e001af = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 175, 1, 224, 144, 4, 152, 225, 251, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 170, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 74, 111, 105, 110, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 193, 251, 19, 88, 84, 20, 188, 149, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 107, 101, 121, 80, 97, 114, 116, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_fbe1980490e001af = b_fbe1980490e001af.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_fbe1980490e001af[] = { + &s_95bc14545813fbc1, +}; +static const uint16_t m_fbe1980490e001af[] = {2, 0, 1}; +static const uint16_t i_fbe1980490e001af[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_fbe1980490e001af = { + 0xfbe1980490e001af, b_fbe1980490e001af.words, 63, d_fbe1980490e001af, m_fbe1980490e001af, + 1, 3, i_fbe1980490e001af, nullptr, nullptr, { &s_fbe1980490e001af, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<50> b_95bc14545813fbc1 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 193, 251, 19, 88, 84, 20, 188, 149, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 2, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 77, 101, 115, 115, 97, 103, 101, 84, + 97, 114, 103, 101, 116, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 0, 3, 0, 1, 0, + 60, 0, 0, 0, 2, 0, 1, 0, + 105, 109, 112, 111, 114, 116, 101, 100, + 67, 97, 112, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 114, 111, 109, 105, 115, 101, 100, + 65, 110, 115, 119, 101, 114, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 160, 28, 111, 205, 214, 177, 0, 216, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_95bc14545813fbc1 = b_95bc14545813fbc1.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_95bc14545813fbc1[] = { + &s_d800b1d6cd6f1ca0, +}; +static const uint16_t m_95bc14545813fbc1[] = {0, 1}; +static const uint16_t i_95bc14545813fbc1[] = {0, 1}; +const ::capnp::_::RawSchema s_95bc14545813fbc1 = { + 0x95bc14545813fbc1, b_95bc14545813fbc1.words, 50, d_95bc14545813fbc1, m_95bc14545813fbc1, + 1, 2, i_95bc14545813fbc1, nullptr, nullptr, { &s_95bc14545813fbc1, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<52> b_9a0e61223d96743b = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 59, 116, 150, 61, 34, 97, 14, 154, + 16, 0, 0, 0, 1, 0, 0, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 80, 97, 121, 108, 111, 97, 100, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 72, 0, 0, 0, 2, 0, 1, 0, + 99, 111, 110, 116, 101, 110, 116, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 84, 97, 98, 108, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 176, 184, 134, 11, 196, 221, 35, 133, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9a0e61223d96743b = b_9a0e61223d96743b.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9a0e61223d96743b[] = { + &s_8523ddc40b86b8b0, +}; +static const uint16_t m_9a0e61223d96743b[] = {1, 0}; +static const uint16_t i_9a0e61223d96743b[] = {0, 1}; +const ::capnp::_::RawSchema s_9a0e61223d96743b = { + 0x9a0e61223d96743b, b_9a0e61223d96743b.words, 52, d_9a0e61223d96743b, m_9a0e61223d96743b, + 1, 2, i_9a0e61223d96743b, nullptr, nullptr, { &s_9a0e61223d96743b, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<114> b_8523ddc40b86b8b0 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 176, 184, 134, 11, 196, 221, 35, 133, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 87, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 67, 97, 112, 68, 101, 115, 99, 114, + 105, 112, 116, 111, 114, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 24, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 153, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 0, 0, 0, 3, 0, 1, 0, + 160, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 157, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 156, 0, 0, 0, 3, 0, 1, 0, + 168, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 164, 0, 0, 0, 3, 0, 1, 0, + 176, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 173, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 172, 0, 0, 0, 3, 0, 1, 0, + 184, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 0, 0, 0, 3, 0, 1, 0, + 192, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 0, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 3, 0, 1, 0, + 204, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 110, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 101, 110, 100, 101, 114, 72, 111, + 115, 116, 101, 100, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 101, 110, 100, 101, 114, 80, 114, + 111, 109, 105, 115, 101, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 99, 101, 105, 118, 101, 114, + 72, 111, 115, 116, 101, 100, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 99, 101, 105, 118, 101, 114, + 65, 110, 115, 119, 101, 114, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 160, 28, 111, 205, 214, 177, 0, 216, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 104, 105, 114, 100, 80, 97, 114, + 116, 121, 72, 111, 115, 116, 101, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 125, 2, 240, 225, 253, 7, 112, 211, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_8523ddc40b86b8b0 = b_8523ddc40b86b8b0.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_8523ddc40b86b8b0[] = { + &s_d37007fde1f0027d, + &s_d800b1d6cd6f1ca0, +}; +static const uint16_t m_8523ddc40b86b8b0[] = {0, 4, 3, 1, 2, 5}; +static const uint16_t i_8523ddc40b86b8b0[] = {0, 1, 2, 3, 4, 5}; +const ::capnp::_::RawSchema s_8523ddc40b86b8b0 = { + 0x8523ddc40b86b8b0, b_8523ddc40b86b8b0.words, 114, d_8523ddc40b86b8b0, m_8523ddc40b86b8b0, + 2, 6, i_8523ddc40b86b8b0, nullptr, nullptr, { &s_8523ddc40b86b8b0, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<57> b_d800b1d6cd6f1ca0 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 160, 28, 111, 205, 214, 177, 0, 216, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 33, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 80, 114, 111, 109, 105, 115, 101, 100, + 65, 110, 115, 119, 101, 114, 0, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 129, 144, 86, 21, 68, 148, 22, 243, + 1, 0, 0, 0, 26, 0, 0, 0, + 79, 112, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 113, 117, 101, 115, 116, 105, 111, 110, + 73, 100, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 114, 97, 110, 115, 102, 111, 114, + 109, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 129, 144, 86, 21, 68, 148, 22, 243, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d800b1d6cd6f1ca0 = b_d800b1d6cd6f1ca0.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d800b1d6cd6f1ca0[] = { + &s_f316944415569081, +}; +static const uint16_t m_d800b1d6cd6f1ca0[] = {0, 1}; +static const uint16_t i_d800b1d6cd6f1ca0[] = {0, 1}; +const ::capnp::_::RawSchema s_d800b1d6cd6f1ca0 = { + 0xd800b1d6cd6f1ca0, b_d800b1d6cd6f1ca0.words, 57, d_d800b1d6cd6f1ca0, m_d800b1d6cd6f1ca0, + 1, 2, i_d800b1d6cd6f1ca0, nullptr, nullptr, { &s_d800b1d6cd6f1ca0, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<50> b_f316944415569081 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 129, 144, 86, 21, 68, 148, 22, 243, + 31, 0, 0, 0, 1, 0, 1, 0, + 160, 28, 111, 205, 214, 177, 0, 216, + 0, 0, 7, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 80, 114, 111, 109, 105, 115, 101, 100, + 65, 110, 115, 119, 101, 114, 46, 79, + 112, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 56, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 111, 112, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 103, 101, 116, 80, 111, 105, 110, 116, + 101, 114, 70, 105, 101, 108, 100, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f316944415569081 = b_f316944415569081.words; +#if !CAPNP_LITE +static const uint16_t m_f316944415569081[] = {1, 0}; +static const uint16_t i_f316944415569081[] = {0, 1}; +const ::capnp::_::RawSchema s_f316944415569081 = { + 0xf316944415569081, b_f316944415569081.words, 50, nullptr, m_f316944415569081, + 0, 2, i_f316944415569081, nullptr, nullptr, { &s_f316944415569081, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_d37007fde1f0027d = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 125, 2, 240, 225, 253, 7, 112, 211, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 84, 104, 105, 114, 100, 80, 97, 114, + 116, 121, 67, 97, 112, 68, 101, 115, + 99, 114, 105, 112, 116, 111, 114, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 105, 110, 101, 73, 100, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d37007fde1f0027d = b_d37007fde1f0027d.words; +#if !CAPNP_LITE +static const uint16_t m_d37007fde1f0027d[] = {0, 1}; +static const uint16_t i_d37007fde1f0027d[] = {0, 1}; +const ::capnp::_::RawSchema s_d37007fde1f0027d = { + 0xd37007fde1f0027d, b_d37007fde1f0027d.words, 49, nullptr, m_d37007fde1f0027d, + 0, 2, i_d37007fde1f0027d, nullptr, nullptr, { &s_d37007fde1f0027d, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<85> b_d625b7063acf691a = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 26, 105, 207, 58, 6, 183, 37, 214, + 16, 0, 0, 0, 1, 0, 1, 0, + 80, 162, 82, 37, 27, 152, 18, 179, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 210, 0, 0, 0, + 33, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 69, 120, 99, 101, 112, 116, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 88, 189, 76, 63, 226, 150, 140, 178, + 1, 0, 0, 0, 42, 0, 0, 0, + 84, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 3, 0, 1, 0, + 104, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 0, 0, 0, 186, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 0, 0, 0, 3, 0, 1, 0, + 116, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 0, 0, 0, 154, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 0, 0, 0, 3, 0, 1, 0, + 128, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 125, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 120, 0, 0, 0, 3, 0, 1, 0, + 132, 0, 0, 0, 2, 0, 1, 0, + 114, 101, 97, 115, 111, 110, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 98, 115, 111, 108, 101, 116, 101, + 73, 115, 67, 97, 108, 108, 101, 114, + 115, 70, 97, 117, 108, 116, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 111, 98, 115, 111, 108, 101, 116, 101, + 68, 117, 114, 97, 98, 105, 108, 105, + 116, 121, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 88, 189, 76, 63, 226, 150, 140, 178, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d625b7063acf691a = b_d625b7063acf691a.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d625b7063acf691a[] = { + &s_b28c96e23f4cbd58, +}; +static const uint16_t m_d625b7063acf691a[] = {2, 1, 0, 3}; +static const uint16_t i_d625b7063acf691a[] = {0, 1, 2, 3}; +const ::capnp::_::RawSchema s_d625b7063acf691a = { + 0xd625b7063acf691a, b_d625b7063acf691a.words, 85, d_d625b7063acf691a, m_d625b7063acf691a, + 1, 4, i_d625b7063acf691a, nullptr, nullptr, { &s_d625b7063acf691a, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<37> b_b28c96e23f4cbd58 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 88, 189, 76, 63, 226, 150, 140, 178, + 26, 0, 0, 0, 2, 0, 0, 0, + 26, 105, 207, 58, 6, 183, 37, 214, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 103, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 114, 112, + 99, 46, 99, 97, 112, 110, 112, 58, + 69, 120, 99, 101, 112, 116, 105, 111, + 110, 46, 84, 121, 112, 101, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 16, 0, 0, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 97, 105, 108, 101, 100, 0, 0, + 111, 118, 101, 114, 108, 111, 97, 100, + 101, 100, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 99, 111, 110, 110, 101, + 99, 116, 101, 100, 0, 0, 0, 0, + 117, 110, 105, 109, 112, 108, 101, 109, + 101, 110, 116, 101, 100, 0, 0, 0, } +}; +::capnp::word const* const bp_b28c96e23f4cbd58 = b_b28c96e23f4cbd58.words; +#if !CAPNP_LITE +static const uint16_t m_b28c96e23f4cbd58[] = {2, 0, 1, 3}; +const ::capnp::_::RawSchema s_b28c96e23f4cbd58 = { + 0xb28c96e23f4cbd58, b_b28c96e23f4cbd58.words, 37, nullptr, m_b28c96e23f4cbd58, + 0, 4, nullptr, nullptr, nullptr, { &s_b28c96e23f4cbd58, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +CAPNP_DEFINE_ENUM(Type_b28c96e23f4cbd58, b28c96e23f4cbd58); +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { +namespace rpc { + +// Message +constexpr uint16_t Message::_capnpPrivate::dataWordSize; +constexpr uint16_t Message::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Message::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Message::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Bootstrap +constexpr uint16_t Bootstrap::_capnpPrivate::dataWordSize; +constexpr uint16_t Bootstrap::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Bootstrap::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Bootstrap::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Call +constexpr uint16_t Call::_capnpPrivate::dataWordSize; +constexpr uint16_t Call::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Call::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Call::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Call::SendResultsTo +constexpr uint16_t Call::SendResultsTo::_capnpPrivate::dataWordSize; +constexpr uint16_t Call::SendResultsTo::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Call::SendResultsTo::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Call::SendResultsTo::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Return +constexpr uint16_t Return::_capnpPrivate::dataWordSize; +constexpr uint16_t Return::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Return::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Return::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Finish +constexpr uint16_t Finish::_capnpPrivate::dataWordSize; +constexpr uint16_t Finish::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Finish::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Finish::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Resolve +constexpr uint16_t Resolve::_capnpPrivate::dataWordSize; +constexpr uint16_t Resolve::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Resolve::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Resolve::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Release +constexpr uint16_t Release::_capnpPrivate::dataWordSize; +constexpr uint16_t Release::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Release::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Release::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Disembargo +constexpr uint16_t Disembargo::_capnpPrivate::dataWordSize; +constexpr uint16_t Disembargo::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Disembargo::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Disembargo::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Disembargo::Context +constexpr uint16_t Disembargo::Context::_capnpPrivate::dataWordSize; +constexpr uint16_t Disembargo::Context::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Disembargo::Context::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Disembargo::Context::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Provide +constexpr uint16_t Provide::_capnpPrivate::dataWordSize; +constexpr uint16_t Provide::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Provide::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Provide::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Accept +constexpr uint16_t Accept::_capnpPrivate::dataWordSize; +constexpr uint16_t Accept::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Accept::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Accept::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Join +constexpr uint16_t Join::_capnpPrivate::dataWordSize; +constexpr uint16_t Join::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Join::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Join::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// MessageTarget +constexpr uint16_t MessageTarget::_capnpPrivate::dataWordSize; +constexpr uint16_t MessageTarget::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind MessageTarget::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* MessageTarget::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Payload +constexpr uint16_t Payload::_capnpPrivate::dataWordSize; +constexpr uint16_t Payload::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Payload::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Payload::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// CapDescriptor +constexpr uint16_t CapDescriptor::_capnpPrivate::dataWordSize; +constexpr uint16_t CapDescriptor::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind CapDescriptor::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* CapDescriptor::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// PromisedAnswer +constexpr uint16_t PromisedAnswer::_capnpPrivate::dataWordSize; +constexpr uint16_t PromisedAnswer::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind PromisedAnswer::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* PromisedAnswer::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// PromisedAnswer::Op +constexpr uint16_t PromisedAnswer::Op::_capnpPrivate::dataWordSize; +constexpr uint16_t PromisedAnswer::Op::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind PromisedAnswer::Op::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* PromisedAnswer::Op::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// ThirdPartyCapDescriptor +constexpr uint16_t ThirdPartyCapDescriptor::_capnpPrivate::dataWordSize; +constexpr uint16_t ThirdPartyCapDescriptor::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind ThirdPartyCapDescriptor::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* ThirdPartyCapDescriptor::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Exception +constexpr uint16_t Exception::_capnpPrivate::dataWordSize; +constexpr uint16_t Exception::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Exception::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Exception::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,4898 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: rpc.capnp + +#ifndef CAPNP_INCLUDED_b312981b2552a250_ +#define CAPNP_INCLUDED_b312981b2552a250_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(91b79f1f808db032); +CAPNP_DECLARE_SCHEMA(e94ccf8031176ec4); +CAPNP_DECLARE_SCHEMA(836a53ce789d4cd4); +CAPNP_DECLARE_SCHEMA(dae8b0f61aab5f99); +CAPNP_DECLARE_SCHEMA(9e19b28d3db3573a); +CAPNP_DECLARE_SCHEMA(d37d2eb2c2f80e63); +CAPNP_DECLARE_SCHEMA(bbc29655fa89086e); +CAPNP_DECLARE_SCHEMA(ad1a6c0d7dd07497); +CAPNP_DECLARE_SCHEMA(f964368b0fbd3711); +CAPNP_DECLARE_SCHEMA(d562b4df655bdd4d); +CAPNP_DECLARE_SCHEMA(9c6a046bfbc1ac5a); +CAPNP_DECLARE_SCHEMA(d4c9b56290554016); +CAPNP_DECLARE_SCHEMA(fbe1980490e001af); +CAPNP_DECLARE_SCHEMA(95bc14545813fbc1); +CAPNP_DECLARE_SCHEMA(9a0e61223d96743b); +CAPNP_DECLARE_SCHEMA(8523ddc40b86b8b0); +CAPNP_DECLARE_SCHEMA(d800b1d6cd6f1ca0); +CAPNP_DECLARE_SCHEMA(f316944415569081); +CAPNP_DECLARE_SCHEMA(d37007fde1f0027d); +CAPNP_DECLARE_SCHEMA(d625b7063acf691a); +CAPNP_DECLARE_SCHEMA(b28c96e23f4cbd58); +enum class Type_b28c96e23f4cbd58: uint16_t { + FAILED, + OVERLOADED, + DISCONNECTED, + UNIMPLEMENTED, +}; +CAPNP_DECLARE_ENUM(Type, b28c96e23f4cbd58); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace rpc { + +struct Message { + Message() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNIMPLEMENTED, + ABORT, + CALL, + RETURN, + FINISH, + RESOLVE, + RELEASE, + OBSOLETE_SAVE, + BOOTSTRAP, + OBSOLETE_DELETE, + PROVIDE, + ACCEPT, + JOIN, + DISEMBARGO, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(91b79f1f808db032, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Bootstrap { + Bootstrap() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e94ccf8031176ec4, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Call { + Call() = delete; + + class Reader; + class Builder; + class Pipeline; + struct SendResultsTo; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(836a53ce789d4cd4, 3, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Call::SendResultsTo { + SendResultsTo() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + CALLER, + YOURSELF, + THIRD_PARTY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(dae8b0f61aab5f99, 3, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Return { + Return() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + RESULTS, + EXCEPTION, + CANCELED, + RESULTS_SENT_ELSEWHERE, + TAKE_FROM_OTHER_QUESTION, + ACCEPT_FROM_THIRD_PARTY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9e19b28d3db3573a, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Finish { + Finish() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d37d2eb2c2f80e63, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Resolve { + Resolve() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + CAP, + EXCEPTION, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bbc29655fa89086e, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Release { + Release() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ad1a6c0d7dd07497, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Disembargo { + Disembargo() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Context; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f964368b0fbd3711, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Disembargo::Context { + Context() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + SENDER_LOOPBACK, + RECEIVER_LOOPBACK, + ACCEPT, + PROVIDE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d562b4df655bdd4d, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Provide { + Provide() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9c6a046bfbc1ac5a, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Accept { + Accept() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d4c9b56290554016, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Join { + Join() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(fbe1980490e001af, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct MessageTarget { + MessageTarget() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + IMPORTED_CAP, + PROMISED_ANSWER, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(95bc14545813fbc1, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Payload { + Payload() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9a0e61223d96743b, 0, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CapDescriptor { + CapDescriptor() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NONE, + SENDER_HOSTED, + SENDER_PROMISE, + RECEIVER_HOSTED, + RECEIVER_ANSWER, + THIRD_PARTY_HOSTED, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8523ddc40b86b8b0, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct PromisedAnswer { + PromisedAnswer() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Op; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d800b1d6cd6f1ca0, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct PromisedAnswer::Op { + Op() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + NOOP, + GET_POINTER_FIELD, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f316944415569081, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct ThirdPartyCapDescriptor { + ThirdPartyCapDescriptor() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d37007fde1f0027d, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Exception { + Exception() = delete; + + class Reader; + class Builder; + class Pipeline; + typedef ::capnp::schemas::Type_b28c96e23f4cbd58 Type; + + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d625b7063acf691a, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class Message::Reader { +public: + typedef Message Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnimplemented() const; + inline bool hasUnimplemented() const; + inline ::capnp::rpc::Message::Reader getUnimplemented() const; + + inline bool isAbort() const; + inline bool hasAbort() const; + inline ::capnp::rpc::Exception::Reader getAbort() const; + + inline bool isCall() const; + inline bool hasCall() const; + inline ::capnp::rpc::Call::Reader getCall() const; + + inline bool isReturn() const; + inline bool hasReturn() const; + inline ::capnp::rpc::Return::Reader getReturn() const; + + inline bool isFinish() const; + inline bool hasFinish() const; + inline ::capnp::rpc::Finish::Reader getFinish() const; + + inline bool isResolve() const; + inline bool hasResolve() const; + inline ::capnp::rpc::Resolve::Reader getResolve() const; + + inline bool isRelease() const; + inline bool hasRelease() const; + inline ::capnp::rpc::Release::Reader getRelease() const; + + inline bool isObsoleteSave() const; + inline bool hasObsoleteSave() const; + inline ::capnp::AnyPointer::Reader getObsoleteSave() const; + + inline bool isBootstrap() const; + inline bool hasBootstrap() const; + inline ::capnp::rpc::Bootstrap::Reader getBootstrap() const; + + inline bool isObsoleteDelete() const; + inline bool hasObsoleteDelete() const; + inline ::capnp::AnyPointer::Reader getObsoleteDelete() const; + + inline bool isProvide() const; + inline bool hasProvide() const; + inline ::capnp::rpc::Provide::Reader getProvide() const; + + inline bool isAccept() const; + inline bool hasAccept() const; + inline ::capnp::rpc::Accept::Reader getAccept() const; + + inline bool isJoin() const; + inline bool hasJoin() const; + inline ::capnp::rpc::Join::Reader getJoin() const; + + inline bool isDisembargo() const; + inline bool hasDisembargo() const; + inline ::capnp::rpc::Disembargo::Reader getDisembargo() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Message::Builder { +public: + typedef Message Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnimplemented(); + inline bool hasUnimplemented(); + inline ::capnp::rpc::Message::Builder getUnimplemented(); + inline void setUnimplemented( ::capnp::rpc::Message::Reader value); + inline ::capnp::rpc::Message::Builder initUnimplemented(); + inline void adoptUnimplemented(::capnp::Orphan< ::capnp::rpc::Message>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Message> disownUnimplemented(); + + inline bool isAbort(); + inline bool hasAbort(); + inline ::capnp::rpc::Exception::Builder getAbort(); + inline void setAbort( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initAbort(); + inline void adoptAbort(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownAbort(); + + inline bool isCall(); + inline bool hasCall(); + inline ::capnp::rpc::Call::Builder getCall(); + inline void setCall( ::capnp::rpc::Call::Reader value); + inline ::capnp::rpc::Call::Builder initCall(); + inline void adoptCall(::capnp::Orphan< ::capnp::rpc::Call>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Call> disownCall(); + + inline bool isReturn(); + inline bool hasReturn(); + inline ::capnp::rpc::Return::Builder getReturn(); + inline void setReturn( ::capnp::rpc::Return::Reader value); + inline ::capnp::rpc::Return::Builder initReturn(); + inline void adoptReturn(::capnp::Orphan< ::capnp::rpc::Return>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Return> disownReturn(); + + inline bool isFinish(); + inline bool hasFinish(); + inline ::capnp::rpc::Finish::Builder getFinish(); + inline void setFinish( ::capnp::rpc::Finish::Reader value); + inline ::capnp::rpc::Finish::Builder initFinish(); + inline void adoptFinish(::capnp::Orphan< ::capnp::rpc::Finish>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Finish> disownFinish(); + + inline bool isResolve(); + inline bool hasResolve(); + inline ::capnp::rpc::Resolve::Builder getResolve(); + inline void setResolve( ::capnp::rpc::Resolve::Reader value); + inline ::capnp::rpc::Resolve::Builder initResolve(); + inline void adoptResolve(::capnp::Orphan< ::capnp::rpc::Resolve>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Resolve> disownResolve(); + + inline bool isRelease(); + inline bool hasRelease(); + inline ::capnp::rpc::Release::Builder getRelease(); + inline void setRelease( ::capnp::rpc::Release::Reader value); + inline ::capnp::rpc::Release::Builder initRelease(); + inline void adoptRelease(::capnp::Orphan< ::capnp::rpc::Release>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Release> disownRelease(); + + inline bool isObsoleteSave(); + inline bool hasObsoleteSave(); + inline ::capnp::AnyPointer::Builder getObsoleteSave(); + inline ::capnp::AnyPointer::Builder initObsoleteSave(); + + inline bool isBootstrap(); + inline bool hasBootstrap(); + inline ::capnp::rpc::Bootstrap::Builder getBootstrap(); + inline void setBootstrap( ::capnp::rpc::Bootstrap::Reader value); + inline ::capnp::rpc::Bootstrap::Builder initBootstrap(); + inline void adoptBootstrap(::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> disownBootstrap(); + + inline bool isObsoleteDelete(); + inline bool hasObsoleteDelete(); + inline ::capnp::AnyPointer::Builder getObsoleteDelete(); + inline ::capnp::AnyPointer::Builder initObsoleteDelete(); + + inline bool isProvide(); + inline bool hasProvide(); + inline ::capnp::rpc::Provide::Builder getProvide(); + inline void setProvide( ::capnp::rpc::Provide::Reader value); + inline ::capnp::rpc::Provide::Builder initProvide(); + inline void adoptProvide(::capnp::Orphan< ::capnp::rpc::Provide>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Provide> disownProvide(); + + inline bool isAccept(); + inline bool hasAccept(); + inline ::capnp::rpc::Accept::Builder getAccept(); + inline void setAccept( ::capnp::rpc::Accept::Reader value); + inline ::capnp::rpc::Accept::Builder initAccept(); + inline void adoptAccept(::capnp::Orphan< ::capnp::rpc::Accept>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Accept> disownAccept(); + + inline bool isJoin(); + inline bool hasJoin(); + inline ::capnp::rpc::Join::Builder getJoin(); + inline void setJoin( ::capnp::rpc::Join::Reader value); + inline ::capnp::rpc::Join::Builder initJoin(); + inline void adoptJoin(::capnp::Orphan< ::capnp::rpc::Join>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Join> disownJoin(); + + inline bool isDisembargo(); + inline bool hasDisembargo(); + inline ::capnp::rpc::Disembargo::Builder getDisembargo(); + inline void setDisembargo( ::capnp::rpc::Disembargo::Reader value); + inline ::capnp::rpc::Disembargo::Builder initDisembargo(); + inline void adoptDisembargo(::capnp::Orphan< ::capnp::rpc::Disembargo>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Disembargo> disownDisembargo(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Message::Pipeline { +public: + typedef Message Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Bootstrap::Reader { +public: + typedef Bootstrap Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasDeprecatedObjectId() const; + inline ::capnp::AnyPointer::Reader getDeprecatedObjectId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Bootstrap::Builder { +public: + typedef Bootstrap Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasDeprecatedObjectId(); + inline ::capnp::AnyPointer::Builder getDeprecatedObjectId(); + inline ::capnp::AnyPointer::Builder initDeprecatedObjectId(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Bootstrap::Pipeline { +public: + typedef Bootstrap Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Call::Reader { +public: + typedef Call Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline ::uint64_t getInterfaceId() const; + + inline ::uint16_t getMethodId() const; + + inline bool hasParams() const; + inline ::capnp::rpc::Payload::Reader getParams() const; + + inline typename SendResultsTo::Reader getSendResultsTo() const; + + inline bool getAllowThirdPartyTailCall() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Call::Builder { +public: + typedef Call Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline ::uint64_t getInterfaceId(); + inline void setInterfaceId( ::uint64_t value); + + inline ::uint16_t getMethodId(); + inline void setMethodId( ::uint16_t value); + + inline bool hasParams(); + inline ::capnp::rpc::Payload::Builder getParams(); + inline void setParams( ::capnp::rpc::Payload::Reader value); + inline ::capnp::rpc::Payload::Builder initParams(); + inline void adoptParams(::capnp::Orphan< ::capnp::rpc::Payload>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Payload> disownParams(); + + inline typename SendResultsTo::Builder getSendResultsTo(); + inline typename SendResultsTo::Builder initSendResultsTo(); + + inline bool getAllowThirdPartyTailCall(); + inline void setAllowThirdPartyTailCall(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Call::Pipeline { +public: + typedef Call Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); + inline ::capnp::rpc::Payload::Pipeline getParams(); + inline typename SendResultsTo::Pipeline getSendResultsTo(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Call::SendResultsTo::Reader { +public: + typedef SendResultsTo Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isCaller() const; + inline ::capnp::Void getCaller() const; + + inline bool isYourself() const; + inline ::capnp::Void getYourself() const; + + inline bool isThirdParty() const; + inline bool hasThirdParty() const; + inline ::capnp::AnyPointer::Reader getThirdParty() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Call::SendResultsTo::Builder { +public: + typedef SendResultsTo Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isCaller(); + inline ::capnp::Void getCaller(); + inline void setCaller( ::capnp::Void value = ::capnp::VOID); + + inline bool isYourself(); + inline ::capnp::Void getYourself(); + inline void setYourself( ::capnp::Void value = ::capnp::VOID); + + inline bool isThirdParty(); + inline bool hasThirdParty(); + inline ::capnp::AnyPointer::Builder getThirdParty(); + inline ::capnp::AnyPointer::Builder initThirdParty(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Call::SendResultsTo::Pipeline { +public: + typedef SendResultsTo Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Return::Reader { +public: + typedef Return Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint32_t getAnswerId() const; + + inline bool getReleaseParamCaps() const; + + inline bool isResults() const; + inline bool hasResults() const; + inline ::capnp::rpc::Payload::Reader getResults() const; + + inline bool isException() const; + inline bool hasException() const; + inline ::capnp::rpc::Exception::Reader getException() const; + + inline bool isCanceled() const; + inline ::capnp::Void getCanceled() const; + + inline bool isResultsSentElsewhere() const; + inline ::capnp::Void getResultsSentElsewhere() const; + + inline bool isTakeFromOtherQuestion() const; + inline ::uint32_t getTakeFromOtherQuestion() const; + + inline bool isAcceptFromThirdParty() const; + inline bool hasAcceptFromThirdParty() const; + inline ::capnp::AnyPointer::Reader getAcceptFromThirdParty() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Return::Builder { +public: + typedef Return Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint32_t getAnswerId(); + inline void setAnswerId( ::uint32_t value); + + inline bool getReleaseParamCaps(); + inline void setReleaseParamCaps(bool value); + + inline bool isResults(); + inline bool hasResults(); + inline ::capnp::rpc::Payload::Builder getResults(); + inline void setResults( ::capnp::rpc::Payload::Reader value); + inline ::capnp::rpc::Payload::Builder initResults(); + inline void adoptResults(::capnp::Orphan< ::capnp::rpc::Payload>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Payload> disownResults(); + + inline bool isException(); + inline bool hasException(); + inline ::capnp::rpc::Exception::Builder getException(); + inline void setException( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initException(); + inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); + + inline bool isCanceled(); + inline ::capnp::Void getCanceled(); + inline void setCanceled( ::capnp::Void value = ::capnp::VOID); + + inline bool isResultsSentElsewhere(); + inline ::capnp::Void getResultsSentElsewhere(); + inline void setResultsSentElsewhere( ::capnp::Void value = ::capnp::VOID); + + inline bool isTakeFromOtherQuestion(); + inline ::uint32_t getTakeFromOtherQuestion(); + inline void setTakeFromOtherQuestion( ::uint32_t value); + + inline bool isAcceptFromThirdParty(); + inline bool hasAcceptFromThirdParty(); + inline ::capnp::AnyPointer::Builder getAcceptFromThirdParty(); + inline ::capnp::AnyPointer::Builder initAcceptFromThirdParty(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Return::Pipeline { +public: + typedef Return Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Finish::Reader { +public: + typedef Finish Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool getReleaseResultCaps() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Finish::Builder { +public: + typedef Finish Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool getReleaseResultCaps(); + inline void setReleaseResultCaps(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Finish::Pipeline { +public: + typedef Finish Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Resolve::Reader { +public: + typedef Resolve Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint32_t getPromiseId() const; + + inline bool isCap() const; + inline bool hasCap() const; + inline ::capnp::rpc::CapDescriptor::Reader getCap() const; + + inline bool isException() const; + inline bool hasException() const; + inline ::capnp::rpc::Exception::Reader getException() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Resolve::Builder { +public: + typedef Resolve Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint32_t getPromiseId(); + inline void setPromiseId( ::uint32_t value); + + inline bool isCap(); + inline bool hasCap(); + inline ::capnp::rpc::CapDescriptor::Builder getCap(); + inline void setCap( ::capnp::rpc::CapDescriptor::Reader value); + inline ::capnp::rpc::CapDescriptor::Builder initCap(); + inline void adoptCap(::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value); + inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> disownCap(); + + inline bool isException(); + inline bool hasException(); + inline ::capnp::rpc::Exception::Builder getException(); + inline void setException( ::capnp::rpc::Exception::Reader value); + inline ::capnp::rpc::Exception::Builder initException(); + inline void adoptException(::capnp::Orphan< ::capnp::rpc::Exception>&& value); + inline ::capnp::Orphan< ::capnp::rpc::Exception> disownException(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Resolve::Pipeline { +public: + typedef Resolve Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Release::Reader { +public: + typedef Release Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getId() const; + + inline ::uint32_t getReferenceCount() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Release::Builder { +public: + typedef Release Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getId(); + inline void setId( ::uint32_t value); + + inline ::uint32_t getReferenceCount(); + inline void setReferenceCount( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Release::Pipeline { +public: + typedef Release Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Disembargo::Reader { +public: + typedef Disembargo Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline typename Context::Reader getContext() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Disembargo::Builder { +public: + typedef Disembargo Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline typename Context::Builder getContext(); + inline typename Context::Builder initContext(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Disembargo::Pipeline { +public: + typedef Disembargo Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); + inline typename Context::Pipeline getContext(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Disembargo::Context::Reader { +public: + typedef Context Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isSenderLoopback() const; + inline ::uint32_t getSenderLoopback() const; + + inline bool isReceiverLoopback() const; + inline ::uint32_t getReceiverLoopback() const; + + inline bool isAccept() const; + inline ::capnp::Void getAccept() const; + + inline bool isProvide() const; + inline ::uint32_t getProvide() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Disembargo::Context::Builder { +public: + typedef Context Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isSenderLoopback(); + inline ::uint32_t getSenderLoopback(); + inline void setSenderLoopback( ::uint32_t value); + + inline bool isReceiverLoopback(); + inline ::uint32_t getReceiverLoopback(); + inline void setReceiverLoopback( ::uint32_t value); + + inline bool isAccept(); + inline ::capnp::Void getAccept(); + inline void setAccept( ::capnp::Void value = ::capnp::VOID); + + inline bool isProvide(); + inline ::uint32_t getProvide(); + inline void setProvide( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Disembargo::Context::Pipeline { +public: + typedef Context Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Provide::Reader { +public: + typedef Provide Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline bool hasRecipient() const; + inline ::capnp::AnyPointer::Reader getRecipient() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Provide::Builder { +public: + typedef Provide Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline bool hasRecipient(); + inline ::capnp::AnyPointer::Builder getRecipient(); + inline ::capnp::AnyPointer::Builder initRecipient(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Provide::Pipeline { +public: + typedef Provide Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Accept::Reader { +public: + typedef Accept Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasProvision() const; + inline ::capnp::AnyPointer::Reader getProvision() const; + + inline bool getEmbargo() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Accept::Builder { +public: + typedef Accept Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasProvision(); + inline ::capnp::AnyPointer::Builder getProvision(); + inline ::capnp::AnyPointer::Builder initProvision(); + + inline bool getEmbargo(); + inline void setEmbargo(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Accept::Pipeline { +public: + typedef Accept Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Join::Reader { +public: + typedef Join Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTarget() const; + inline ::capnp::rpc::MessageTarget::Reader getTarget() const; + + inline bool hasKeyPart() const; + inline ::capnp::AnyPointer::Reader getKeyPart() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Join::Builder { +public: + typedef Join Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTarget(); + inline ::capnp::rpc::MessageTarget::Builder getTarget(); + inline void setTarget( ::capnp::rpc::MessageTarget::Reader value); + inline ::capnp::rpc::MessageTarget::Builder initTarget(); + inline void adoptTarget(::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value); + inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> disownTarget(); + + inline bool hasKeyPart(); + inline ::capnp::AnyPointer::Builder getKeyPart(); + inline ::capnp::AnyPointer::Builder initKeyPart(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Join::Pipeline { +public: + typedef Join Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::rpc::MessageTarget::Pipeline getTarget(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class MessageTarget::Reader { +public: + typedef MessageTarget Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isImportedCap() const; + inline ::uint32_t getImportedCap() const; + + inline bool isPromisedAnswer() const; + inline bool hasPromisedAnswer() const; + inline ::capnp::rpc::PromisedAnswer::Reader getPromisedAnswer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class MessageTarget::Builder { +public: + typedef MessageTarget Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isImportedCap(); + inline ::uint32_t getImportedCap(); + inline void setImportedCap( ::uint32_t value); + + inline bool isPromisedAnswer(); + inline bool hasPromisedAnswer(); + inline ::capnp::rpc::PromisedAnswer::Builder getPromisedAnswer(); + inline void setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value); + inline ::capnp::rpc::PromisedAnswer::Builder initPromisedAnswer(); + inline void adoptPromisedAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); + inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownPromisedAnswer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class MessageTarget::Pipeline { +public: + typedef MessageTarget Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Payload::Reader { +public: + typedef Payload Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasContent() const; + inline ::capnp::AnyPointer::Reader getContent() const; + + inline bool hasCapTable() const; + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader getCapTable() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Payload::Builder { +public: + typedef Payload Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasContent(); + inline ::capnp::AnyPointer::Builder getContent(); + inline ::capnp::AnyPointer::Builder initContent(); + + inline bool hasCapTable(); + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder getCapTable(); + inline void setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value); + inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder initCapTable(unsigned int size); + inline void adoptCapTable(::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> disownCapTable(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Payload::Pipeline { +public: + typedef Payload Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CapDescriptor::Reader { +public: + typedef CapDescriptor Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNone() const; + inline ::capnp::Void getNone() const; + + inline bool isSenderHosted() const; + inline ::uint32_t getSenderHosted() const; + + inline bool isSenderPromise() const; + inline ::uint32_t getSenderPromise() const; + + inline bool isReceiverHosted() const; + inline ::uint32_t getReceiverHosted() const; + + inline bool isReceiverAnswer() const; + inline bool hasReceiverAnswer() const; + inline ::capnp::rpc::PromisedAnswer::Reader getReceiverAnswer() const; + + inline bool isThirdPartyHosted() const; + inline bool hasThirdPartyHosted() const; + inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader getThirdPartyHosted() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CapDescriptor::Builder { +public: + typedef CapDescriptor Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNone(); + inline ::capnp::Void getNone(); + inline void setNone( ::capnp::Void value = ::capnp::VOID); + + inline bool isSenderHosted(); + inline ::uint32_t getSenderHosted(); + inline void setSenderHosted( ::uint32_t value); + + inline bool isSenderPromise(); + inline ::uint32_t getSenderPromise(); + inline void setSenderPromise( ::uint32_t value); + + inline bool isReceiverHosted(); + inline ::uint32_t getReceiverHosted(); + inline void setReceiverHosted( ::uint32_t value); + + inline bool isReceiverAnswer(); + inline bool hasReceiverAnswer(); + inline ::capnp::rpc::PromisedAnswer::Builder getReceiverAnswer(); + inline void setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value); + inline ::capnp::rpc::PromisedAnswer::Builder initReceiverAnswer(); + inline void adoptReceiverAnswer(::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value); + inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> disownReceiverAnswer(); + + inline bool isThirdPartyHosted(); + inline bool hasThirdPartyHosted(); + inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder getThirdPartyHosted(); + inline void setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value); + inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder initThirdPartyHosted(); + inline void adoptThirdPartyHosted(::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value); + inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> disownThirdPartyHosted(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CapDescriptor::Pipeline { +public: + typedef CapDescriptor Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class PromisedAnswer::Reader { +public: + typedef PromisedAnswer Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId() const; + + inline bool hasTransform() const; + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader getTransform() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class PromisedAnswer::Builder { +public: + typedef PromisedAnswer Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getQuestionId(); + inline void setQuestionId( ::uint32_t value); + + inline bool hasTransform(); + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder getTransform(); + inline void setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value); + inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder initTransform(unsigned int size); + inline void adoptTransform(::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> disownTransform(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class PromisedAnswer::Pipeline { +public: + typedef PromisedAnswer Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class PromisedAnswer::Op::Reader { +public: + typedef Op Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isNoop() const; + inline ::capnp::Void getNoop() const; + + inline bool isGetPointerField() const; + inline ::uint16_t getGetPointerField() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class PromisedAnswer::Op::Builder { +public: + typedef Op Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isNoop(); + inline ::capnp::Void getNoop(); + inline void setNoop( ::capnp::Void value = ::capnp::VOID); + + inline bool isGetPointerField(); + inline ::uint16_t getGetPointerField(); + inline void setGetPointerField( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class PromisedAnswer::Op::Pipeline { +public: + typedef Op Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class ThirdPartyCapDescriptor::Reader { +public: + typedef ThirdPartyCapDescriptor Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasId() const; + inline ::capnp::AnyPointer::Reader getId() const; + + inline ::uint32_t getVineId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class ThirdPartyCapDescriptor::Builder { +public: + typedef ThirdPartyCapDescriptor Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasId(); + inline ::capnp::AnyPointer::Builder getId(); + inline ::capnp::AnyPointer::Builder initId(); + + inline ::uint32_t getVineId(); + inline void setVineId( ::uint32_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class ThirdPartyCapDescriptor::Pipeline { +public: + typedef ThirdPartyCapDescriptor Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Exception::Reader { +public: + typedef Exception Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasReason() const; + inline ::capnp::Text::Reader getReason() const; + + inline bool getObsoleteIsCallersFault() const; + + inline ::uint16_t getObsoleteDurability() const; + + inline ::capnp::rpc::Exception::Type getType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Exception::Builder { +public: + typedef Exception Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasReason(); + inline ::capnp::Text::Builder getReason(); + inline void setReason( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initReason(unsigned int size); + inline void adoptReason(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownReason(); + + inline bool getObsoleteIsCallersFault(); + inline void setObsoleteIsCallersFault(bool value); + + inline ::uint16_t getObsoleteDurability(); + inline void setObsoleteDurability( ::uint16_t value); + + inline ::capnp::rpc::Exception::Type getType(); + inline void setType( ::capnp::rpc::Exception::Type value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Exception::Pipeline { +public: + typedef Exception Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::rpc::Message::Which Message::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Message::Which Message::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Message::Reader::isUnimplemented() const { + return which() == Message::UNIMPLEMENTED; +} +inline bool Message::Builder::isUnimplemented() { + return which() == Message::UNIMPLEMENTED; +} +inline bool Message::Reader::hasUnimplemented() const { + if (which() != Message::UNIMPLEMENTED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasUnimplemented() { + if (which() != Message::UNIMPLEMENTED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Message::Reader Message::Reader::getUnimplemented() const { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Message::Builder Message::Builder::getUnimplemented() { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setUnimplemented( ::capnp::rpc::Message::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Message::Builder Message::Builder::initUnimplemented() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptUnimplemented( + ::capnp::Orphan< ::capnp::rpc::Message>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::UNIMPLEMENTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Message> Message::Builder::disownUnimplemented() { + KJ_IREQUIRE((which() == Message::UNIMPLEMENTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Message>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isAbort() const { + return which() == Message::ABORT; +} +inline bool Message::Builder::isAbort() { + return which() == Message::ABORT; +} +inline bool Message::Reader::hasAbort() const { + if (which() != Message::ABORT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasAbort() { + if (which() != Message::ABORT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Message::Reader::getAbort() const { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Message::Builder::getAbort() { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setAbort( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Message::Builder::initAbort() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptAbort( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ABORT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Message::Builder::disownAbort() { + KJ_IREQUIRE((which() == Message::ABORT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isCall() const { + return which() == Message::CALL; +} +inline bool Message::Builder::isCall() { + return which() == Message::CALL; +} +inline bool Message::Reader::hasCall() const { + if (which() != Message::CALL) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasCall() { + if (which() != Message::CALL) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Call::Reader Message::Reader::getCall() const { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Call::Builder Message::Builder::getCall() { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setCall( ::capnp::rpc::Call::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Call::Builder Message::Builder::initCall() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptCall( + ::capnp::Orphan< ::capnp::rpc::Call>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::CALL); + ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Call> Message::Builder::disownCall() { + KJ_IREQUIRE((which() == Message::CALL), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Call>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isReturn() const { + return which() == Message::RETURN; +} +inline bool Message::Builder::isReturn() { + return which() == Message::RETURN; +} +inline bool Message::Reader::hasReturn() const { + if (which() != Message::RETURN) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasReturn() { + if (which() != Message::RETURN) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Return::Reader Message::Reader::getReturn() const { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Return::Builder Message::Builder::getReturn() { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setReturn( ::capnp::rpc::Return::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Return::Builder Message::Builder::initReturn() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptReturn( + ::capnp::Orphan< ::capnp::rpc::Return>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RETURN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Return> Message::Builder::disownReturn() { + KJ_IREQUIRE((which() == Message::RETURN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Return>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isFinish() const { + return which() == Message::FINISH; +} +inline bool Message::Builder::isFinish() { + return which() == Message::FINISH; +} +inline bool Message::Reader::hasFinish() const { + if (which() != Message::FINISH) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasFinish() { + if (which() != Message::FINISH) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Finish::Reader Message::Reader::getFinish() const { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Finish::Builder Message::Builder::getFinish() { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setFinish( ::capnp::rpc::Finish::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Finish::Builder Message::Builder::initFinish() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptFinish( + ::capnp::Orphan< ::capnp::rpc::Finish>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::FINISH); + ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Finish> Message::Builder::disownFinish() { + KJ_IREQUIRE((which() == Message::FINISH), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Finish>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isResolve() const { + return which() == Message::RESOLVE; +} +inline bool Message::Builder::isResolve() { + return which() == Message::RESOLVE; +} +inline bool Message::Reader::hasResolve() const { + if (which() != Message::RESOLVE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasResolve() { + if (which() != Message::RESOLVE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Resolve::Reader Message::Reader::getResolve() const { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Resolve::Builder Message::Builder::getResolve() { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setResolve( ::capnp::rpc::Resolve::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Resolve::Builder Message::Builder::initResolve() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptResolve( + ::capnp::Orphan< ::capnp::rpc::Resolve>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RESOLVE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Resolve> Message::Builder::disownResolve() { + KJ_IREQUIRE((which() == Message::RESOLVE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Resolve>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isRelease() const { + return which() == Message::RELEASE; +} +inline bool Message::Builder::isRelease() { + return which() == Message::RELEASE; +} +inline bool Message::Reader::hasRelease() const { + if (which() != Message::RELEASE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasRelease() { + if (which() != Message::RELEASE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Release::Reader Message::Reader::getRelease() const { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Release::Builder Message::Builder::getRelease() { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setRelease( ::capnp::rpc::Release::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Release::Builder Message::Builder::initRelease() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptRelease( + ::capnp::Orphan< ::capnp::rpc::Release>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::RELEASE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Release> Message::Builder::disownRelease() { + KJ_IREQUIRE((which() == Message::RELEASE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Release>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isObsoleteSave() const { + return which() == Message::OBSOLETE_SAVE; +} +inline bool Message::Builder::isObsoleteSave() { + return which() == Message::OBSOLETE_SAVE; +} +inline bool Message::Reader::hasObsoleteSave() const { + if (which() != Message::OBSOLETE_SAVE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasObsoleteSave() { + if (which() != Message::OBSOLETE_SAVE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteSave() const { + KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteSave() { + KJ_IREQUIRE((which() == Message::OBSOLETE_SAVE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteSave() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::OBSOLETE_SAVE); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Message::Reader::isBootstrap() const { + return which() == Message::BOOTSTRAP; +} +inline bool Message::Builder::isBootstrap() { + return which() == Message::BOOTSTRAP; +} +inline bool Message::Reader::hasBootstrap() const { + if (which() != Message::BOOTSTRAP) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasBootstrap() { + if (which() != Message::BOOTSTRAP) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Bootstrap::Reader Message::Reader::getBootstrap() const { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Bootstrap::Builder Message::Builder::getBootstrap() { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setBootstrap( ::capnp::rpc::Bootstrap::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Bootstrap::Builder Message::Builder::initBootstrap() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptBootstrap( + ::capnp::Orphan< ::capnp::rpc::Bootstrap>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::BOOTSTRAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Bootstrap> Message::Builder::disownBootstrap() { + KJ_IREQUIRE((which() == Message::BOOTSTRAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Bootstrap>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isObsoleteDelete() const { + return which() == Message::OBSOLETE_DELETE; +} +inline bool Message::Builder::isObsoleteDelete() { + return which() == Message::OBSOLETE_DELETE; +} +inline bool Message::Reader::hasObsoleteDelete() const { + if (which() != Message::OBSOLETE_DELETE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasObsoleteDelete() { + if (which() != Message::OBSOLETE_DELETE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Message::Reader::getObsoleteDelete() const { + KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::getObsoleteDelete() { + KJ_IREQUIRE((which() == Message::OBSOLETE_DELETE), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Message::Builder::initObsoleteDelete() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::OBSOLETE_DELETE); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Message::Reader::isProvide() const { + return which() == Message::PROVIDE; +} +inline bool Message::Builder::isProvide() { + return which() == Message::PROVIDE; +} +inline bool Message::Reader::hasProvide() const { + if (which() != Message::PROVIDE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasProvide() { + if (which() != Message::PROVIDE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Provide::Reader Message::Reader::getProvide() const { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Provide::Builder Message::Builder::getProvide() { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setProvide( ::capnp::rpc::Provide::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Provide::Builder Message::Builder::initProvide() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptProvide( + ::capnp::Orphan< ::capnp::rpc::Provide>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::PROVIDE); + ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Provide> Message::Builder::disownProvide() { + KJ_IREQUIRE((which() == Message::PROVIDE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Provide>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isAccept() const { + return which() == Message::ACCEPT; +} +inline bool Message::Builder::isAccept() { + return which() == Message::ACCEPT; +} +inline bool Message::Reader::hasAccept() const { + if (which() != Message::ACCEPT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasAccept() { + if (which() != Message::ACCEPT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Accept::Reader Message::Reader::getAccept() const { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Accept::Builder Message::Builder::getAccept() { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setAccept( ::capnp::rpc::Accept::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Accept::Builder Message::Builder::initAccept() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptAccept( + ::capnp::Orphan< ::capnp::rpc::Accept>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::ACCEPT); + ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Accept> Message::Builder::disownAccept() { + KJ_IREQUIRE((which() == Message::ACCEPT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Accept>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isJoin() const { + return which() == Message::JOIN; +} +inline bool Message::Builder::isJoin() { + return which() == Message::JOIN; +} +inline bool Message::Reader::hasJoin() const { + if (which() != Message::JOIN) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasJoin() { + if (which() != Message::JOIN) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Join::Reader Message::Reader::getJoin() const { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Join::Builder Message::Builder::getJoin() { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setJoin( ::capnp::rpc::Join::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Join::Builder Message::Builder::initJoin() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptJoin( + ::capnp::Orphan< ::capnp::rpc::Join>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::JOIN); + ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Join> Message::Builder::disownJoin() { + KJ_IREQUIRE((which() == Message::JOIN), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Join>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Message::Reader::isDisembargo() const { + return which() == Message::DISEMBARGO; +} +inline bool Message::Builder::isDisembargo() { + return which() == Message::DISEMBARGO; +} +inline bool Message::Reader::hasDisembargo() const { + if (which() != Message::DISEMBARGO) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Message::Builder::hasDisembargo() { + if (which() != Message::DISEMBARGO) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Disembargo::Reader Message::Reader::getDisembargo() const { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Disembargo::Builder Message::Builder::getDisembargo() { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::setDisembargo( ::capnp::rpc::Disembargo::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Disembargo::Builder Message::Builder::initDisembargo() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Message::Builder::adoptDisembargo( + ::capnp::Orphan< ::capnp::rpc::Disembargo>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Message::DISEMBARGO); + ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Disembargo> Message::Builder::disownDisembargo() { + KJ_IREQUIRE((which() == Message::DISEMBARGO), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Disembargo>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Bootstrap::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Bootstrap::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Bootstrap::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Bootstrap::Reader::hasDeprecatedObjectId() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Bootstrap::Builder::hasDeprecatedObjectId() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Bootstrap::Reader::getDeprecatedObjectId() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Bootstrap::Builder::getDeprecatedObjectId() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Bootstrap::Builder::initDeprecatedObjectId() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Call::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Call::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Call::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Call::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Call::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Call::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Call::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Call::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Call::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Call::Reader::getInterfaceId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Call::Builder::getInterfaceId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setInterfaceId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Call::Reader::getMethodId() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Call::Builder::getMethodId() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setMethodId( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::Reader::hasParams() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::Builder::hasParams() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Payload::Reader Call::Reader::getParams() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Payload::Builder Call::Builder::getParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::Payload::Pipeline Call::Pipeline::getParams() { + return ::capnp::rpc::Payload::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Call::Builder::setParams( ::capnp::rpc::Payload::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Payload::Builder Call::Builder::initParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Call::Builder::adoptParams( + ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Payload> Call::Builder::disownParams() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline typename Call::SendResultsTo::Reader Call::Reader::getSendResultsTo() const { + return typename Call::SendResultsTo::Reader(_reader); +} +inline typename Call::SendResultsTo::Builder Call::Builder::getSendResultsTo() { + return typename Call::SendResultsTo::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Call::SendResultsTo::Pipeline Call::Pipeline::getSendResultsTo() { + return typename Call::SendResultsTo::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Call::SendResultsTo::Builder Call::Builder::initSendResultsTo() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<3>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<2>() * ::capnp::POINTERS).clear(); + return typename Call::SendResultsTo::Builder(_builder); +} +inline bool Call::Reader::getAllowThirdPartyTailCall() const { + return _reader.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} + +inline bool Call::Builder::getAllowThirdPartyTailCall() { + return _builder.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} +inline void Call::Builder::setAllowThirdPartyTailCall(bool value) { + _builder.setDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Call::SendResultsTo::Which Call::SendResultsTo::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline bool Call::SendResultsTo::Reader::isCaller() const { + return which() == Call::SendResultsTo::CALLER; +} +inline bool Call::SendResultsTo::Builder::isCaller() { + return which() == Call::SendResultsTo::CALLER; +} +inline ::capnp::Void Call::SendResultsTo::Reader::getCaller() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Call::SendResultsTo::Builder::getCaller() { + KJ_IREQUIRE((which() == Call::SendResultsTo::CALLER), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::SendResultsTo::Builder::setCaller( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::CALLER); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::SendResultsTo::Reader::isYourself() const { + return which() == Call::SendResultsTo::YOURSELF; +} +inline bool Call::SendResultsTo::Builder::isYourself() { + return which() == Call::SendResultsTo::YOURSELF; +} +inline ::capnp::Void Call::SendResultsTo::Reader::getYourself() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Call::SendResultsTo::Builder::getYourself() { + KJ_IREQUIRE((which() == Call::SendResultsTo::YOURSELF), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Call::SendResultsTo::Builder::setYourself( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::YOURSELF); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Call::SendResultsTo::Reader::isThirdParty() const { + return which() == Call::SendResultsTo::THIRD_PARTY; +} +inline bool Call::SendResultsTo::Builder::isThirdParty() { + return which() == Call::SendResultsTo::THIRD_PARTY; +} +inline bool Call::SendResultsTo::Reader::hasThirdParty() const { + if (which() != Call::SendResultsTo::THIRD_PARTY) return false; + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Call::SendResultsTo::Builder::hasThirdParty() { + if (which() != Call::SendResultsTo::THIRD_PARTY) return false; + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Call::SendResultsTo::Reader::getThirdParty() const { + KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::getThirdParty() { + KJ_IREQUIRE((which() == Call::SendResultsTo::THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Call::SendResultsTo::Builder::initThirdParty() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Call::SendResultsTo::THIRD_PARTY); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::capnp::rpc::Return::Which Return::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Return::Which Return::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Reader::getAnswerId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Builder::getAnswerId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setAnswerId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::getReleaseParamCaps() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} + +inline bool Return::Builder::getReleaseParamCaps() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} +inline void Return::Builder::setReleaseParamCaps(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value, true); +} + +inline bool Return::Reader::isResults() const { + return which() == Return::RESULTS; +} +inline bool Return::Builder::isResults() { + return which() == Return::RESULTS; +} +inline bool Return::Reader::hasResults() const { + if (which() != Return::RESULTS) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasResults() { + if (which() != Return::RESULTS) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Payload::Reader Return::Reader::getResults() const { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Payload::Builder Return::Builder::getResults() { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::setResults( ::capnp::rpc::Payload::Reader value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Payload::Builder Return::Builder::initResults() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::adoptResults( + ::capnp::Orphan< ::capnp::rpc::Payload>&& value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS); + ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Payload> Return::Builder::disownResults() { + KJ_IREQUIRE((which() == Return::RESULTS), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Payload>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Return::Reader::isException() const { + return which() == Return::EXCEPTION; +} +inline bool Return::Builder::isException() { + return which() == Return::EXCEPTION; +} +inline bool Return::Reader::hasException() const { + if (which() != Return::EXCEPTION) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasException() { + if (which() != Return::EXCEPTION) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Return::Reader::getException() const { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Return::Builder::getException() { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::setException( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Return::Builder::initException() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Return::Builder::adoptException( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Return::Builder::disownException() { + KJ_IREQUIRE((which() == Return::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Return::Reader::isCanceled() const { + return which() == Return::CANCELED; +} +inline bool Return::Builder::isCanceled() { + return which() == Return::CANCELED; +} +inline ::capnp::Void Return::Reader::getCanceled() const { + KJ_IREQUIRE((which() == Return::CANCELED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Return::Builder::getCanceled() { + KJ_IREQUIRE((which() == Return::CANCELED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setCanceled( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::CANCELED); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isResultsSentElsewhere() const { + return which() == Return::RESULTS_SENT_ELSEWHERE; +} +inline bool Return::Builder::isResultsSentElsewhere() { + return which() == Return::RESULTS_SENT_ELSEWHERE; +} +inline ::capnp::Void Return::Reader::getResultsSentElsewhere() const { + KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Return::Builder::getResultsSentElsewhere() { + KJ_IREQUIRE((which() == Return::RESULTS_SENT_ELSEWHERE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setResultsSentElsewhere( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::RESULTS_SENT_ELSEWHERE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isTakeFromOtherQuestion() const { + return which() == Return::TAKE_FROM_OTHER_QUESTION; +} +inline bool Return::Builder::isTakeFromOtherQuestion() { + return which() == Return::TAKE_FROM_OTHER_QUESTION; +} +inline ::uint32_t Return::Reader::getTakeFromOtherQuestion() const { + KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Return::Builder::getTakeFromOtherQuestion() { + KJ_IREQUIRE((which() == Return::TAKE_FROM_OTHER_QUESTION), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Return::Builder::setTakeFromOtherQuestion( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::TAKE_FROM_OTHER_QUESTION); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Return::Reader::isAcceptFromThirdParty() const { + return which() == Return::ACCEPT_FROM_THIRD_PARTY; +} +inline bool Return::Builder::isAcceptFromThirdParty() { + return which() == Return::ACCEPT_FROM_THIRD_PARTY; +} +inline bool Return::Reader::hasAcceptFromThirdParty() const { + if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Return::Builder::hasAcceptFromThirdParty() { + if (which() != Return::ACCEPT_FROM_THIRD_PARTY) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Return::Reader::getAcceptFromThirdParty() const { + KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Return::Builder::getAcceptFromThirdParty() { + KJ_IREQUIRE((which() == Return::ACCEPT_FROM_THIRD_PARTY), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Return::Builder::initAcceptFromThirdParty() { + _builder.setDataField( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, Return::ACCEPT_FROM_THIRD_PARTY); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Finish::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Finish::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Finish::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Finish::Reader::getReleaseResultCaps() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} + +inline bool Finish::Builder::getReleaseResultCaps() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, true); +} +inline void Finish::Builder::setReleaseResultCaps(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value, true); +} + +inline ::capnp::rpc::Resolve::Which Resolve::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Resolve::Which Resolve::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Resolve::Reader::getPromiseId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Resolve::Builder::getPromiseId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Resolve::Builder::setPromiseId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Resolve::Reader::isCap() const { + return which() == Resolve::CAP; +} +inline bool Resolve::Builder::isCap() { + return which() == Resolve::CAP; +} +inline bool Resolve::Reader::hasCap() const { + if (which() != Resolve::CAP) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Resolve::Builder::hasCap() { + if (which() != Resolve::CAP) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::CapDescriptor::Reader Resolve::Reader::getCap() const { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::getCap() { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::setCap( ::capnp::rpc::CapDescriptor::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::CapDescriptor::Builder Resolve::Builder::initCap() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::adoptCap( + ::capnp::Orphan< ::capnp::rpc::CapDescriptor>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::CAP); + ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::CapDescriptor> Resolve::Builder::disownCap() { + KJ_IREQUIRE((which() == Resolve::CAP), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::CapDescriptor>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Resolve::Reader::isException() const { + return which() == Resolve::EXCEPTION; +} +inline bool Resolve::Builder::isException() { + return which() == Resolve::EXCEPTION; +} +inline bool Resolve::Reader::hasException() const { + if (which() != Resolve::EXCEPTION) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Resolve::Builder::hasException() { + if (which() != Resolve::EXCEPTION) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::Exception::Reader Resolve::Reader::getException() const { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::Exception::Builder Resolve::Builder::getException() { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::setException( ::capnp::rpc::Exception::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::Exception::Builder Resolve::Builder::initException() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Resolve::Builder::adoptException( + ::capnp::Orphan< ::capnp::rpc::Exception>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Resolve::EXCEPTION); + ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::Exception> Resolve::Builder::disownException() { + KJ_IREQUIRE((which() == Resolve::EXCEPTION), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::Exception>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Release::Reader::getId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Release::Builder::getId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Release::Builder::setId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Release::Reader::getReferenceCount() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Release::Builder::getReferenceCount() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Release::Builder::setReferenceCount( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Disembargo::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Disembargo::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Disembargo::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Disembargo::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Disembargo::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Disembargo::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Disembargo::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline typename Disembargo::Context::Reader Disembargo::Reader::getContext() const { + return typename Disembargo::Context::Reader(_reader); +} +inline typename Disembargo::Context::Builder Disembargo::Builder::getContext() { + return typename Disembargo::Context::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Disembargo::Context::Pipeline Disembargo::Pipeline::getContext() { + return typename Disembargo::Context::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Disembargo::Context::Builder Disembargo::Builder::initContext() { + _builder.setDataField< ::uint32_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Disembargo::Context::Builder(_builder); +} +inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::Disembargo::Context::Which Disembargo::Context::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline bool Disembargo::Context::Reader::isSenderLoopback() const { + return which() == Disembargo::Context::SENDER_LOOPBACK; +} +inline bool Disembargo::Context::Builder::isSenderLoopback() { + return which() == Disembargo::Context::SENDER_LOOPBACK; +} +inline ::uint32_t Disembargo::Context::Reader::getSenderLoopback() const { + KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getSenderLoopback() { + KJ_IREQUIRE((which() == Disembargo::Context::SENDER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setSenderLoopback( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::SENDER_LOOPBACK); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isReceiverLoopback() const { + return which() == Disembargo::Context::RECEIVER_LOOPBACK; +} +inline bool Disembargo::Context::Builder::isReceiverLoopback() { + return which() == Disembargo::Context::RECEIVER_LOOPBACK; +} +inline ::uint32_t Disembargo::Context::Reader::getReceiverLoopback() const { + KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getReceiverLoopback() { + KJ_IREQUIRE((which() == Disembargo::Context::RECEIVER_LOOPBACK), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setReceiverLoopback( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::RECEIVER_LOOPBACK); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isAccept() const { + return which() == Disembargo::Context::ACCEPT; +} +inline bool Disembargo::Context::Builder::isAccept() { + return which() == Disembargo::Context::ACCEPT; +} +inline ::capnp::Void Disembargo::Context::Reader::getAccept() const { + KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Disembargo::Context::Builder::getAccept() { + KJ_IREQUIRE((which() == Disembargo::Context::ACCEPT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setAccept( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::ACCEPT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Disembargo::Context::Reader::isProvide() const { + return which() == Disembargo::Context::PROVIDE; +} +inline bool Disembargo::Context::Builder::isProvide() { + return which() == Disembargo::Context::PROVIDE; +} +inline ::uint32_t Disembargo::Context::Reader::getProvide() const { + KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Disembargo::Context::Builder::getProvide() { + KJ_IREQUIRE((which() == Disembargo::Context::PROVIDE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Disembargo::Context::Builder::setProvide( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, Disembargo::Context::PROVIDE); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Provide::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Provide::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Provide::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Provide::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Provide::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Provide::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Provide::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Provide::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Provide::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Provide::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Provide::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Provide::Reader::hasRecipient() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Provide::Builder::hasRecipient() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Provide::Reader::getRecipient() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Provide::Builder::getRecipient() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Provide::Builder::initRecipient() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t Accept::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Accept::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Accept::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Accept::Reader::hasProvision() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Accept::Builder::hasProvision() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Accept::Reader::getProvision() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Accept::Builder::getProvision() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Accept::Builder::initProvision() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Accept::Reader::getEmbargo() const { + return _reader.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} + +inline bool Accept::Builder::getEmbargo() { + return _builder.getDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS); +} +inline void Accept::Builder::setEmbargo(bool value) { + _builder.setDataField( + ::capnp::bounded<32>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Join::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Join::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Join::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Join::Reader::hasTarget() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Join::Builder::hasTarget() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::MessageTarget::Reader Join::Reader::getTarget() const { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::MessageTarget::Builder Join::Builder::getTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::rpc::MessageTarget::Pipeline Join::Pipeline::getTarget() { + return ::capnp::rpc::MessageTarget::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Join::Builder::setTarget( ::capnp::rpc::MessageTarget::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::MessageTarget::Builder Join::Builder::initTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Join::Builder::adoptTarget( + ::capnp::Orphan< ::capnp::rpc::MessageTarget>&& value) { + ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::MessageTarget> Join::Builder::disownTarget() { + return ::capnp::_::PointerHelpers< ::capnp::rpc::MessageTarget>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Join::Reader::hasKeyPart() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Join::Builder::hasKeyPart() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Join::Reader::getKeyPart() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Join::Builder::getKeyPart() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Join::Builder::initKeyPart() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::capnp::rpc::MessageTarget::Which MessageTarget::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::MessageTarget::Which MessageTarget::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline bool MessageTarget::Reader::isImportedCap() const { + return which() == MessageTarget::IMPORTED_CAP; +} +inline bool MessageTarget::Builder::isImportedCap() { + return which() == MessageTarget::IMPORTED_CAP; +} +inline ::uint32_t MessageTarget::Reader::getImportedCap() const { + KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t MessageTarget::Builder::getImportedCap() { + KJ_IREQUIRE((which() == MessageTarget::IMPORTED_CAP), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void MessageTarget::Builder::setImportedCap( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::IMPORTED_CAP); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool MessageTarget::Reader::isPromisedAnswer() const { + return which() == MessageTarget::PROMISED_ANSWER; +} +inline bool MessageTarget::Builder::isPromisedAnswer() { + return which() == MessageTarget::PROMISED_ANSWER; +} +inline bool MessageTarget::Reader::hasPromisedAnswer() const { + if (which() != MessageTarget::PROMISED_ANSWER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool MessageTarget::Builder::hasPromisedAnswer() { + if (which() != MessageTarget::PROMISED_ANSWER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::PromisedAnswer::Reader MessageTarget::Reader::getPromisedAnswer() const { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::getPromisedAnswer() { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void MessageTarget::Builder::setPromisedAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::PromisedAnswer::Builder MessageTarget::Builder::initPromisedAnswer() { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void MessageTarget::Builder::adoptPromisedAnswer( + ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { + _builder.setDataField( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, MessageTarget::PROMISED_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> MessageTarget::Builder::disownPromisedAnswer() { + KJ_IREQUIRE((which() == MessageTarget::PROMISED_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Payload::Reader::hasContent() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Payload::Builder::hasContent() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Payload::Reader::getContent() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Payload::Builder::getContent() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Payload::Builder::initContent() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Payload::Reader::hasCapTable() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Payload::Builder::hasCapTable() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader Payload::Reader::getCapTable() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::getCapTable() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Payload::Builder::setCapTable( ::capnp::List< ::capnp::rpc::CapDescriptor>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::rpc::CapDescriptor>::Builder Payload::Builder::initCapTable(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Payload::Builder::adoptCapTable( + ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::CapDescriptor>> Payload::Builder::disownCapTable() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::CapDescriptor>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::CapDescriptor::Which CapDescriptor::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool CapDescriptor::Reader::isNone() const { + return which() == CapDescriptor::NONE; +} +inline bool CapDescriptor::Builder::isNone() { + return which() == CapDescriptor::NONE; +} +inline ::capnp::Void CapDescriptor::Reader::getNone() const { + KJ_IREQUIRE((which() == CapDescriptor::NONE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void CapDescriptor::Builder::getNone() { + KJ_IREQUIRE((which() == CapDescriptor::NONE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setNone( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::NONE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isSenderHosted() const { + return which() == CapDescriptor::SENDER_HOSTED; +} +inline bool CapDescriptor::Builder::isSenderHosted() { + return which() == CapDescriptor::SENDER_HOSTED; +} +inline ::uint32_t CapDescriptor::Reader::getSenderHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getSenderHosted() { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_HOSTED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setSenderHosted( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::SENDER_HOSTED); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isSenderPromise() const { + return which() == CapDescriptor::SENDER_PROMISE; +} +inline bool CapDescriptor::Builder::isSenderPromise() { + return which() == CapDescriptor::SENDER_PROMISE; +} +inline ::uint32_t CapDescriptor::Reader::getSenderPromise() const { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getSenderPromise() { + KJ_IREQUIRE((which() == CapDescriptor::SENDER_PROMISE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setSenderPromise( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::SENDER_PROMISE); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isReceiverHosted() const { + return which() == CapDescriptor::RECEIVER_HOSTED; +} +inline bool CapDescriptor::Builder::isReceiverHosted() { + return which() == CapDescriptor::RECEIVER_HOSTED; +} +inline ::uint32_t CapDescriptor::Reader::getReceiverHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t CapDescriptor::Builder::getReceiverHosted() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_HOSTED), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void CapDescriptor::Builder::setReceiverHosted( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_HOSTED); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool CapDescriptor::Reader::isReceiverAnswer() const { + return which() == CapDescriptor::RECEIVER_ANSWER; +} +inline bool CapDescriptor::Builder::isReceiverAnswer() { + return which() == CapDescriptor::RECEIVER_ANSWER; +} +inline bool CapDescriptor::Reader::hasReceiverAnswer() const { + if (which() != CapDescriptor::RECEIVER_ANSWER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CapDescriptor::Builder::hasReceiverAnswer() { + if (which() != CapDescriptor::RECEIVER_ANSWER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::PromisedAnswer::Reader CapDescriptor::Reader::getReceiverAnswer() const { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::getReceiverAnswer() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::setReceiverAnswer( ::capnp::rpc::PromisedAnswer::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::PromisedAnswer::Builder CapDescriptor::Builder::initReceiverAnswer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::adoptReceiverAnswer( + ::capnp::Orphan< ::capnp::rpc::PromisedAnswer>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::RECEIVER_ANSWER); + ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::PromisedAnswer> CapDescriptor::Builder::disownReceiverAnswer() { + KJ_IREQUIRE((which() == CapDescriptor::RECEIVER_ANSWER), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::PromisedAnswer>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CapDescriptor::Reader::isThirdPartyHosted() const { + return which() == CapDescriptor::THIRD_PARTY_HOSTED; +} +inline bool CapDescriptor::Builder::isThirdPartyHosted() { + return which() == CapDescriptor::THIRD_PARTY_HOSTED; +} +inline bool CapDescriptor::Reader::hasThirdPartyHosted() const { + if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CapDescriptor::Builder::hasThirdPartyHosted() { + if (which() != CapDescriptor::THIRD_PARTY_HOSTED) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Reader CapDescriptor::Reader::getThirdPartyHosted() const { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::getThirdPartyHosted() { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::setThirdPartyHosted( ::capnp::rpc::ThirdPartyCapDescriptor::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::rpc::ThirdPartyCapDescriptor::Builder CapDescriptor::Builder::initThirdPartyHosted() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CapDescriptor::Builder::adoptThirdPartyHosted( + ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, CapDescriptor::THIRD_PARTY_HOSTED); + ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::rpc::ThirdPartyCapDescriptor> CapDescriptor::Builder::disownThirdPartyHosted() { + KJ_IREQUIRE((which() == CapDescriptor::THIRD_PARTY_HOSTED), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::rpc::ThirdPartyCapDescriptor>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t PromisedAnswer::Reader::getQuestionId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t PromisedAnswer::Builder::getQuestionId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Builder::setQuestionId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool PromisedAnswer::Reader::hasTransform() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool PromisedAnswer::Builder::hasTransform() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader PromisedAnswer::Reader::getTransform() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::getTransform() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void PromisedAnswer::Builder::setTransform( ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>::Builder PromisedAnswer::Builder::initTransform(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void PromisedAnswer::Builder::adoptTransform( + ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>> PromisedAnswer::Builder::disownTransform() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::rpc::PromisedAnswer::Op>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::rpc::PromisedAnswer::Op::Which PromisedAnswer::Op::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool PromisedAnswer::Op::Reader::isNoop() const { + return which() == PromisedAnswer::Op::NOOP; +} +inline bool PromisedAnswer::Op::Builder::isNoop() { + return which() == PromisedAnswer::Op::NOOP; +} +inline ::capnp::Void PromisedAnswer::Op::Reader::getNoop() const { + KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void PromisedAnswer::Op::Builder::getNoop() { + KJ_IREQUIRE((which() == PromisedAnswer::Op::NOOP), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Op::Builder::setNoop( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, PromisedAnswer::Op::NOOP); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool PromisedAnswer::Op::Reader::isGetPointerField() const { + return which() == PromisedAnswer::Op::GET_POINTER_FIELD; +} +inline bool PromisedAnswer::Op::Builder::isGetPointerField() { + return which() == PromisedAnswer::Op::GET_POINTER_FIELD; +} +inline ::uint16_t PromisedAnswer::Op::Reader::getGetPointerField() const { + KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t PromisedAnswer::Op::Builder::getGetPointerField() { + KJ_IREQUIRE((which() == PromisedAnswer::Op::GET_POINTER_FIELD), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void PromisedAnswer::Op::Builder::setGetPointerField( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, PromisedAnswer::Op::GET_POINTER_FIELD); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool ThirdPartyCapDescriptor::Reader::hasId() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool ThirdPartyCapDescriptor::Builder::hasId() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader ThirdPartyCapDescriptor::Reader::getId() const { + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::getId() { + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder ThirdPartyCapDescriptor::Builder::initId() { + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint32_t ThirdPartyCapDescriptor::Reader::getVineId() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t ThirdPartyCapDescriptor::Builder::getVineId() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void ThirdPartyCapDescriptor::Builder::setVineId( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Exception::Reader::hasReason() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Exception::Builder::hasReason() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Exception::Reader::getReason() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Exception::Builder::getReason() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Exception::Builder::setReason( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Exception::Builder::initReason(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Exception::Builder::adoptReason( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Exception::Builder::disownReason() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Exception::Reader::getObsoleteIsCallersFault() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Exception::Builder::getObsoleteIsCallersFault() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setObsoleteIsCallersFault(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Exception::Reader::getObsoleteDurability() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Exception::Builder::getObsoleteDurability() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setObsoleteDurability( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::rpc::Exception::Type Exception::Reader::getType() const { + return _reader.getDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::capnp::rpc::Exception::Type Exception::Builder::getType() { + return _builder.getDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Exception::Builder::setType( ::capnp::rpc::Exception::Type value) { + _builder.setDataField< ::capnp::rpc::Exception::Type>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_b312981b2552a250_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/rpc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/rpc.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,537 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_RPC_H_ +#define CAPNP_RPC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "capability.h" +#include "rpc-prelude.h" + +namespace capnp { + +template +class VatNetwork; +template +class SturdyRefRestorer; + +template +class BootstrapFactory: public _::BootstrapFactoryBase { + // Interface that constructs per-client bootstrap interfaces. Use this if you want each client + // who connects to see a different bootstrap interface based on their (authenticated) VatId. + // This allows an application to bootstrap off of the authentication performed at the VatNetwork + // level. (Typically VatId is some sort of public key.) + // + // This is only useful for multi-party networks. For TwoPartyVatNetwork, there's no reason to + // use a BootstrapFactory; just specify a single bootstrap capability in this case. + +public: + virtual Capability::Client createFor(typename VatId::Reader clientId) = 0; + // Create a bootstrap capability appropriate for exposing to the given client. VatNetwork will + // have authenticated the client VatId before this is called. + +private: + Capability::Client baseCreateFor(AnyStruct::Reader clientId) override; +}; + +template +class RpcSystem: public _::RpcSystemBase { + // Represents the RPC system, which is the portal to objects available on the network. + // + // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` + // determines how to form connections between vats -- specifically, two-way, private, reliable, + // sequenced datagram connections. The RPC implementation determines how to use such connections + // to manage object references and make method calls. + // + // See `makeRpcServer()` and `makeRpcClient()` below for convenient syntax for setting up an + // `RpcSystem` given a `VatNetwork`. + // + // See `ez-rpc.h` for an even simpler interface for setting up RPC in a typical two-party + // client/server scenario. + +public: + template + RpcSystem( + VatNetwork& network, + kj::Maybe bootstrapInterface, + kj::Maybe::Client> gateway = nullptr); + + template + RpcSystem( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, + kj::Maybe::Client> gateway = nullptr); + + template + RpcSystem( + VatNetwork& network, + SturdyRefRestorer& restorer); + + RpcSystem(RpcSystem&& other) = default; + + Capability::Client bootstrap(typename VatId::Reader vatId); + // Connect to the given vat and return its bootstrap interface. + + Capability::Client restore(typename VatId::Reader hostId, AnyPointer::Reader objectId) + KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); + // ** DEPRECATED ** + // + // Restores the given SturdyRef from the network and return the capability representing it. + // + // `hostId` identifies the host from which to request the ref, in the format specified by the + // `VatNetwork` in use. `objectId` is the object ID in whatever format is expected by said host. + // + // This method will be removed in a future version of Cap'n Proto. Instead, please transition + // to using bootstrap(), which is equivalent to calling restore() with a null `objectId`. + // You may emulate the old concept of object IDs by exporting a bootstrap interface which has + // methods that can be used to obtain other capabilities by ID. + + void setFlowLimit(size_t words); + // Sets the incoming call flow limit. If more than `words` worth of call messages have not yet + // received responses, the RpcSystem will not read further messages from the stream. This can be + // used as a crude way to prevent a resource exhaustion attack (or bug) in which a peer makes an + // excessive number of simultaneous calls that consume the receiver's RAM. + // + // There are some caveats. When over the flow limit, all messages are blocked, including returns. + // If the outstanding calls are themselves waiting on calls going in the opposite direction, the + // flow limit may prevent those calls from completing, leading to deadlock. However, a + // sufficiently high limit should make this unlikely. + // + // Note that a call's parameter size counts against the flow limit until the call returns, even + // if the recipient calls releaseParams() to free the parameter memory early. This is because + // releaseParams() may simply indicate that the parameters have been forwarded to another + // machine, but are still in-memory there. For illustration, say that Alice made a call to Bob + // who forwarded the call to Carol. Bob has imposed a flow limit on Alice. Alice's calls are + // being forwarded to Carol, so Bob never keeps the parameters in-memory for more than a brief + // period. However, the flow limit counts all calls that haven't returned, even if Bob has + // already freed the memory they consumed. You might argue that the right solution here is + // instead for Carol to impose her own flow limit on Bob. This has a serious problem, though: + // Bob might be forwarding requests to Carol on behalf of many different parties, not just Alice. + // If Alice can pump enough data to hit the Bob -> Carol flow limit, then those other parties + // will be disrupted. Thus, we can only really impose the limit on the Alice -> Bob link, which + // only affects Alice. We need that one flow limit to limit Alice's impact on the whole system, + // so it has to count all in-flight calls. + // + // In Sandstorm, flow limits are imposed by the supervisor on calls coming out of a grain, in + // order to prevent a grain from inundating the system with in-flight calls. In practice, the + // main time this happens is when a grain is pushing a large file download and doesn't implement + // proper cooperative flow control. +}; + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface); +// Make an RPC server. Typical usage (e.g. in a main() function): +// +// MyEventLoop eventLoop; +// kj::WaitScope waitScope(eventLoop); +// MyNetwork network; +// MyMainInterface::Client bootstrap = makeMain(); +// auto server = makeRpcServer(network, bootstrap); +// kj::NEVER_DONE.wait(waitScope); // run forever +// +// See also ez-rpc.h, which has simpler instructions for the common case of a two-party +// client-server RPC connection. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface, RealmGatewayClient gateway); +// Make an RPC server for a VatNetwork that resides in a different realm from the application. +// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format +// and the network's ("external") format. + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory); +// Make an RPC server that can serve different bootstrap interfaces to different clients via a +// BootstrapInterface. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway); +// Make an RPC server that can serve different bootstrap interfaces to different clients via a +// BootstrapInterface and communicates with a different realm than the application is in via a +// RealmGateway. + +template +RpcSystem makeRpcServer( + VatNetwork& network, + SturdyRefRestorer& restorer) + KJ_DEPRECATED("Please transition to using a bootstrap interface instead."); +// ** DEPRECATED ** +// +// Create an RPC server which exports multiple main interfaces by object ID. The `restorer` object +// can be used to look up objects by ID. +// +// Please transition to exporting only one interface, which is known as the "bootstrap" interface. +// For backwards-compatibility with old clients, continue to implement SturdyRefRestorer, but +// return the new bootstrap interface when the request object ID is null. When new clients connect +// and request the bootstrap interface, they will get that interface. Eventually, once all clients +// are updated to request only the bootstrap interface, stop implementing SturdyRefRestorer and +// switch to passing the bootstrap capability itself as the second parameter to `makeRpcServer()`. + +template +RpcSystem makeRpcClient( + VatNetwork& network); +// Make an RPC client. Typical usage (e.g. in a main() function): +// +// MyEventLoop eventLoop; +// kj::WaitScope waitScope(eventLoop); +// MyNetwork network; +// auto client = makeRpcClient(network); +// MyCapability::Client cap = client.restore(hostId, objId).castAs(); +// auto response = cap.fooRequest().send().wait(waitScope); +// handleMyResponse(response); +// +// See also ez-rpc.h, which has simpler instructions for the common case of a two-party +// client-server RPC connection. + +template , + typename ExternalRef = _::ExternalRefFromRealmGatewayClient> +RpcSystem makeRpcClient( + VatNetwork& network, + RealmGatewayClient gateway); +// Make an RPC client for a VatNetwork that resides in a different realm from the application. +// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format +// and the network's ("external") format. + +template +class SturdyRefRestorer: public _::SturdyRefRestorerBase { + // ** DEPRECATED ** + // + // In Cap'n Proto 0.4.x, applications could export multiple main interfaces identified by + // object IDs. The callback used to map object IDs to objects was `SturdyRefRestorer`, as we + // imagined this would eventually be used for restoring SturdyRefs as well. In practice, it was + // never used for real SturdyRefs, only for exporting singleton objects under well-known names. + // + // The new preferred strategy is to export only a _single_ such interface, called the + // "bootstrap interface". That interface can itself have methods for obtaining other objects, of + // course, but that is up to the app. `SturdyRefRestorer` exists for backwards-compatibility. + // + // Hint: Use SturdyRefRestorer to define a server that exports services under + // string names. + +public: + virtual Capability::Client restore(typename SturdyRefObjectId::Reader ref) + KJ_DEPRECATED( + "Please transition to using bootstrap interfaces instead of SturdyRefRestorer.") = 0; + // Restore the given object, returning a capability representing it. + +private: + Capability::Client baseRestore(AnyPointer::Reader ref) override final; +}; + +// ======================================================================================= +// VatNetwork + +class OutgoingRpcMessage { + // A message to be sent by a `VatNetwork`. + +public: + virtual AnyPointer::Builder getBody() = 0; + // Get the message body, which the caller may fill in any way it wants. (The standard RPC + // implementation initializes it as a Message as defined in rpc.capnp.) + + virtual void send() = 0; + // Send the message, or at least put it in a queue to be sent later. Note that the builder + // returned by `getBody()` remains valid at least until the `OutgoingRpcMessage` is destroyed. +}; + +class IncomingRpcMessage { + // A message received from a `VatNetwork`. + +public: + virtual AnyPointer::Reader getBody() = 0; + // Get the message body, to be interpreted by the caller. (The standard RPC implementation + // interprets it as a Message as defined in rpc.capnp.) +}; + +template +class VatNetwork: public _::VatNetworkBase { + // Cap'n Proto RPC operates between vats, where a "vat" is some sort of host of objects. + // Typically one Cap'n Proto process (in the Unix sense) is one vat. The RPC system is what + // allows calls between objects hosted in different vats. + // + // The RPC implementation sits on top of an implementation of `VatNetwork`. The `VatNetwork` + // determines how to form connections between vats -- specifically, two-way, private, reliable, + // sequenced datagram connections. The RPC implementation determines how to use such connections + // to manage object references and make method calls. + // + // The most common implementation of VatNetwork is TwoPartyVatNetwork (rpc-twoparty.h). Most + // simple client-server apps will want to use it. (You may even want to use the EZ RPC + // interfaces in `ez-rpc.h` and avoid all of this.) + // + // TODO(someday): Provide a standard implementation for the public internet. + +public: + class Connection; + + struct ConnectionAndProvisionId { + // Result of connecting to a vat introduced by another vat. + + kj::Own connection; + // Connection to the new vat. + + kj::Own firstMessage; + // An already-allocated `OutgoingRpcMessage` associated with `connection`. The RPC system will + // construct this as an `Accept` message and send it. + + Orphan provisionId; + // A `ProvisionId` already allocated inside `firstMessage`, which the RPC system will use to + // build the `Accept` message. + }; + + class Connection: public _::VatNetworkBase::Connection { + // A two-way RPC connection. + // + // This object may represent a connection that doesn't exist yet, but is expected to exist + // in the future. In this case, sent messages will automatically be queued and sent once the + // connection is ready, so that the caller doesn't need to know the difference. + + public: + // Level 0 features ---------------------------------------------- + + virtual typename VatId::Reader getPeerVatId() = 0; + // Returns the connected vat's authenticated VatId. It is the VatNetwork's responsibility to + // authenticate this, so that the caller can be assured that they are really talking to the + // identified vat and not an imposter. + + virtual kj::Own newOutgoingMessage(uint firstSegmentWordSize) override = 0; + // Allocate a new message to be sent on this connection. + // + // If `firstSegmentWordSize` is non-zero, it should be treated as a hint suggesting how large + // to make the first segment. This is entirely a hint and the connection may adjust it up or + // down. If it is zero, the connection should choose the size itself. + + virtual kj::Promise>> receiveIncomingMessage() override = 0; + // Wait for a message to be received and return it. If the read stream cleanly terminates, + // return null. If any other problem occurs, throw an exception. + + virtual kj::Promise shutdown() override KJ_WARN_UNUSED_RESULT = 0; + // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The + // returned promise resolves after shutdown is complete. + + private: + AnyStruct::Reader baseGetPeerVatId() override; + }; + + // Level 0 features ------------------------------------------------ + + virtual kj::Maybe> connect(typename VatId::Reader hostId) = 0; + // Connect to a VatId. Note that this method immediately returns a `Connection`, even + // if the network connection has not yet been established. Messages can be queued to this + // connection and will be delivered once it is open. The caller must attempt to read from the + // connection to verify that it actually succeeded; the read will fail if the connection + // couldn't be opened. Some network implementations may actually start sending messages before + // hearing back from the server at all, to avoid a round trip. + // + // Returns nullptr if `hostId` refers to the local host. + + virtual kj::Promise> accept() = 0; + // Wait for the next incoming connection and return it. + + // Level 4 features ------------------------------------------------ + // TODO(someday) + +private: + kj::Maybe> + baseConnect(AnyStruct::Reader hostId) override final; + kj::Promise> baseAccept() override final; +}; + +// ======================================================================================= +// *************************************************************************************** +// Inline implementation details start here +// *************************************************************************************** +// ======================================================================================= + +template +Capability::Client BootstrapFactory::baseCreateFor(AnyStruct::Reader clientId) { + return createFor(clientId.as()); +} + +template +kj::Maybe> + VatNetwork:: + baseConnect(AnyStruct::Reader ref) { + auto maybe = connect(ref.as()); + return maybe.map([](kj::Own& conn) -> kj::Own<_::VatNetworkBase::Connection> { + return kj::mv(conn); + }); +} + +template +kj::Promise> + VatNetwork::baseAccept() { + return accept().then( + [](kj::Own&& connection) -> kj::Own<_::VatNetworkBase::Connection> { + return kj::mv(connection); + }); +} + +template +AnyStruct::Reader VatNetwork< + SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>:: + Connection::baseGetPeerVatId() { + return getPeerVatId(); +} + +template +Capability::Client SturdyRefRestorer::baseRestore(AnyPointer::Reader ref) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return restore(ref.getAs()); +#pragma GCC diagnostic pop +} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + kj::Maybe bootstrap, + kj::Maybe::Client> gateway) + : _::RpcSystemBase(network, kj::mv(bootstrap), kj::mv(gateway)) {} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, + kj::Maybe::Client> gateway) + : _::RpcSystemBase(network, bootstrapFactory, kj::mv(gateway)) {} + +template +template +RpcSystem::RpcSystem( + VatNetwork& network, + SturdyRefRestorer& restorer) + : _::RpcSystemBase(network, restorer) {} + +template +Capability::Client RpcSystem::bootstrap(typename VatId::Reader vatId) { + return baseBootstrap(_::PointerHelpers::getInternalReader(vatId)); +} + +template +Capability::Client RpcSystem::restore( + typename VatId::Reader hostId, AnyPointer::Reader objectId) { + return baseRestore(_::PointerHelpers::getInternalReader(hostId), objectId); +} + +template +inline void RpcSystem::setFlowLimit(size_t words) { + baseSetFlowLimit(words); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface) { + return RpcSystem(network, kj::mv(bootstrapInterface)); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + Capability::Client bootstrapInterface, RealmGatewayClient gateway) { + return RpcSystem(network, kj::mv(bootstrapInterface), + gateway.template castAs>()); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory) { + return RpcSystem(network, bootstrapFactory); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + BootstrapFactory& bootstrapFactory, RealmGatewayClient gateway) { + return RpcSystem(network, bootstrapFactory, gateway.template castAs>()); +} + +template +RpcSystem makeRpcServer( + VatNetwork& network, + SturdyRefRestorer& restorer) { + return RpcSystem(network, restorer); +} + +template +RpcSystem makeRpcClient( + VatNetwork& network) { + return RpcSystem(network, nullptr); +} + +template +RpcSystem makeRpcClient( + VatNetwork& network, + RealmGatewayClient gateway) { + return RpcSystem(network, nullptr, gateway.template castAs>()); +} + +} // namespace capnp + +#endif // CAPNP_RPC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-lite.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-lite.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,48 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_LITE_H_ +#define CAPNP_SCHEMA_LITE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "message.h" + +namespace capnp { + +template +inline schema::Node::Reader schemaProto() { + // Get the schema::Node for this type's schema. This function works even in lite mode. + return readMessageUnchecked(CapnpPrivate::encodedSchema()); +} + +template ::typeId> +inline schema::Node::Reader schemaProto() { + // Get the schema::Node for this type's schema. This function works even in lite mode. + return readMessageUnchecked(schemas::EnumInfo::encodedSchema()); +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_LITE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-loader-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-loader-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,392 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema-loader.h" +#include +#include "test-util.h" +#include + +namespace capnp { +namespace _ { // private +namespace { + +TEST(SchemaLoader, Load) { + SchemaLoader loader; + + Schema struct32Schema = loader.load(Schema::from().getProto()); + + auto nativeSchema = Schema::from(); + Schema testListsSchema = loader.load(nativeSchema.getProto()); + + Schema struct8Schema = loader.load(Schema::from().getProto()); + Schema structPSchema = loader.load(Schema::from().getProto()); + + EXPECT_EQ(kj::str(nativeSchema.getProto()), kj::str(testListsSchema.getProto())); + + EXPECT_FALSE(testListsSchema == nativeSchema); + EXPECT_FALSE(struct32Schema == Schema::from()); + EXPECT_FALSE(struct8Schema == Schema::from()); + EXPECT_FALSE(structPSchema == Schema::from()); + + EXPECT_TRUE(testListsSchema.getDependency(typeId()) == struct32Schema); + EXPECT_TRUE(testListsSchema.getDependency(typeId()) == struct8Schema); + EXPECT_TRUE(testListsSchema.getDependency(typeId()) == structPSchema); + + auto struct16Schema = testListsSchema.getDependency(typeId()); + EXPECT_EQ(0u, struct16Schema.getProto().getStruct().getFields().size()); +} + +TEST(SchemaLoader, LoadLateUnion) { + SchemaLoader loader; + + StructSchema schema = + loader.load(Schema::from().getProto()).asStruct(); + loader.load(Schema::from().getProto()).asStruct(); + loader.load(Schema::from().getProto()).asStruct(); + + EXPECT_EQ(6, + schema.getDependency(schema.getFieldByName("theUnion").getProto().getGroup().getTypeId()) + .asStruct().getFieldByName("grault").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(9, + schema.getDependency(schema.getFieldByName("anotherUnion").getProto().getGroup().getTypeId()) + .asStruct().getFieldByName("corge").getProto().getOrdinal().getExplicit()); + EXPECT_TRUE(schema.findFieldByName("corge") == nullptr); + EXPECT_TRUE(schema.findFieldByName("grault") == nullptr); +} + +TEST(SchemaLoader, LoadUnnamedUnion) { + SchemaLoader loader; + + StructSchema schema = + loader.load(Schema::from().getProto()).asStruct(); + + EXPECT_TRUE(schema.findFieldByName("") == nullptr); + + EXPECT_TRUE(schema.findFieldByName("foo") != nullptr); + EXPECT_TRUE(schema.findFieldByName("bar") != nullptr); + EXPECT_TRUE(schema.findFieldByName("before") != nullptr); + EXPECT_TRUE(schema.findFieldByName("after") != nullptr); +} + +TEST(SchemaLoader, Use) { + SchemaLoader loader; + + StructSchema schema = loader.load(Schema::from().getProto()).asStruct(); + + // Also have to load TestEnum. + loader.load(Schema::from().getProto()); + + { + MallocMessageBuilder builder; + auto root = builder.getRoot(schema); + + initDynamicTestMessage(root); + checkDynamicTestMessage(root.asReader()); + + // Can't convert to TestAllTypes because we didn't use loadCompiledTypeAndDependencies(). + EXPECT_ANY_THROW(root.as()); + + // But if we reinterpret the raw bytes, it works. + checkTestMessage(builder.getRoot()); + } + + loader.loadCompiledTypeAndDependencies(); + + { + MallocMessageBuilder builder; + auto root = builder.getRoot(schema); + + initDynamicTestMessage(root); + + // Now we can actually cast. + checkTestMessage(root.as()); + } + + // Let's also test TestListDefaults, but as we do so, let's load the compiled types first, to + // make sure the opposite order works. + + loader.loadCompiledTypeAndDependencies(); + StructSchema testListsSchema = loader.get(typeId()).asStruct(); + EXPECT_TRUE(testListsSchema != Schema::from()); + + { + MallocMessageBuilder builder; + auto root = builder.getRoot(testListsSchema); + + initDynamicTestLists(root); + checkDynamicTestLists(root.asReader()); + + checkTestMessage(root.as()); + } + + EXPECT_TRUE(loader.load(Schema::from().getProto()) == testListsSchema); + + { + MallocMessageBuilder builder; + auto root = builder.getRoot(testListsSchema); + + initDynamicTestLists(root); + checkTestMessage(root.as()); + } + + // Finally, let's test some unions. + StructSchema unionSchema = loader.load(Schema::from().getProto()).asStruct(); + loader.load(Schema::from().getProto()); + loader.load(Schema::from().getProto()); + { + MallocMessageBuilder builder; + auto root = builder.getRoot(unionSchema); + + root.get("union0").as().set("u0f1s16", 123); + root.get("union1").as().set("u1f0sp", "hello"); + + auto reader = builder.getRoot().asReader(); + EXPECT_EQ(123, reader.getUnion0().getU0f1s16()); + EXPECT_EQ("hello", reader.getUnion1().getU1f0sp()); + } +} + +template +Schema loadUnderAlternateTypeId(SchemaLoader& loader, uint64_t id) { + MallocMessageBuilder schemaBuilder; + schemaBuilder.setRoot(Schema::from().getProto()); + auto root = schemaBuilder.getRoot(); + root.setId(id); + + if (root.isStruct()) { + // If the struct contains any self-referential members, change their type IDs as well. + auto fields = root.getStruct().getFields(); + for (auto field: fields) { + if (field.isSlot()) { + auto type = field.getSlot().getType(); + if (type.isStruct() && type.getStruct().getTypeId() == typeId()) { + type.getStruct().setTypeId(id); + } + } + } + } + + return loader.load(root); +} + +TEST(SchemaLoader, Upgrade) { + SchemaLoader loader; + + loader.loadCompiledTypeAndDependencies(); + + StructSchema schema = loader.get(typeId()).asStruct(); + + EXPECT_EQ(kj::str(Schema::from().getProto()), + kj::str(schema.getProto())); + + loadUnderAlternateTypeId(loader, typeId()); + + // The new version replaced the old. + EXPECT_EQ(Schema::from().getProto().getDisplayName(), + schema.getProto().getDisplayName()); + + // But it is still usable as the old version. + schema.requireUsableAs(); +} + +TEST(SchemaLoader, Downgrade) { + SchemaLoader loader; + + loader.loadCompiledTypeAndDependencies(); + + StructSchema schema = loader.get(typeId()).asStruct(); + + EXPECT_EQ(kj::str(Schema::from().getProto()), kj::str(schema.getProto())); + + loadUnderAlternateTypeId(loader, typeId()); + + // We kept the new version, because the replacement was older. + EXPECT_EQ(Schema::from().getProto().getDisplayName(), + schema.getProto().getDisplayName()); + schema.requireUsableAs(); +} + +TEST(SchemaLoader, Incompatible) { + SchemaLoader loader; + loader.loadCompiledTypeAndDependencies(); + EXPECT_NONFATAL_FAILURE( + loadUnderAlternateTypeId(loader, typeId())); +} + +TEST(SchemaLoader, Enumerate) { + SchemaLoader loader; + loader.loadCompiledTypeAndDependencies(); + auto list = loader.getAllLoaded(); + + ASSERT_EQ(2u, list.size()); + if (list[0] == loader.get(typeId())) { + EXPECT_TRUE(list[1] == loader.get(typeId())); + } else { + EXPECT_TRUE(list[0] == loader.get(typeId())); + EXPECT_TRUE(list[1] == loader.get(typeId())); + } +} + +TEST(SchemaLoader, EnumerateNoPlaceholders) { + SchemaLoader loader; + Schema schema = loader.load(Schema::from().getProto()); + + { + auto list = loader.getAllLoaded(); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(list[0] == schema); + } + + Schema dep = schema.getDependency(typeId()); + + { + auto list = loader.getAllLoaded(); + ASSERT_EQ(2u, list.size()); + if (list[0] == schema) { + EXPECT_TRUE(list[1] == dep); + } else { + EXPECT_TRUE(list[0] == dep); + EXPECT_TRUE(list[1] == schema); + } + } +} + +class FakeLoaderCallback: public SchemaLoader::LazyLoadCallback { +public: + FakeLoaderCallback(const schema::Node::Reader node): node(node), loaded(false) {} + + bool isLoaded() { return loaded; } + + void load(const SchemaLoader& loader, uint64_t id) const override { + if (id == 1234) { + // Magic "not found" ID. + return; + } + + EXPECT_EQ(node.getId(), id); + EXPECT_FALSE(loaded); + loaded = true; + loader.loadOnce(node); + } + +private: + const schema::Node::Reader node; + mutable bool loaded = false; +}; + +TEST(SchemaLoader, LazyLoad) { + FakeLoaderCallback callback(Schema::from().getProto()); + SchemaLoader loader(callback); + + EXPECT_TRUE(loader.tryGet(1234) == nullptr); + + EXPECT_FALSE(callback.isLoaded()); + Schema schema = loader.get(typeId()); + EXPECT_TRUE(callback.isLoaded()); + + EXPECT_EQ(schema.getProto().getDisplayName(), + Schema::from().getProto().getDisplayName()); + + EXPECT_EQ(schema, schema.getDependency(typeId())); + EXPECT_EQ(schema, loader.get(typeId())); +} + +TEST(SchemaLoader, LazyLoadGetDependency) { + FakeLoaderCallback callback(Schema::from().getProto()); + SchemaLoader loader(callback); + + Schema schema = loader.load(Schema::from().getProto()); + + EXPECT_FALSE(callback.isLoaded()); + + Schema dep = schema.getDependency(typeId()); + + EXPECT_TRUE(callback.isLoaded()); + + EXPECT_EQ(dep.getProto().getDisplayName(), + Schema::from().getProto().getDisplayName()); + + EXPECT_EQ(dep, schema.getDependency(typeId())); + EXPECT_EQ(dep, loader.get(typeId())); +} + +TEST(SchemaLoader, Generics) { + SchemaLoader loader; + + StructSchema allTypes = loader.load(Schema::from().getProto()).asStruct(); + StructSchema tap = loader.load(Schema::from().getProto()).asStruct(); + loader.load(Schema::from::Inner>().getProto()); + loader.load(Schema::from::Inner2<>>().getProto()); + loader.load(Schema::from::Interface<>>().getProto()); + loader.load(Schema::from::Interface<>::CallResults>().getProto()); + loader.load(Schema::from>().getProto()); + StructSchema schema = loader.load(Schema::from().getProto()).asStruct(); + + StructSchema branded; + + { + StructSchema::Field basic = schema.getFieldByName("basic"); + branded = basic.getType().asStruct(); + + StructSchema::Field foo = branded.getFieldByName("foo"); + EXPECT_TRUE(foo.getType().asStruct() == allTypes); + EXPECT_TRUE(foo.getType().asStruct() != tap); + + StructSchema instance2 = branded.getFieldByName("rev").getType().asStruct(); + StructSchema::Field foo2 = instance2.getFieldByName("foo"); + EXPECT_TRUE(foo2.getType().asStruct() == tap); + EXPECT_TRUE(foo2.getType().asStruct() != allTypes); + } + + { + StructSchema inner2 = schema.getFieldByName("inner2").getType().asStruct(); + + StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); + Type boundFoo = bound.getFieldByName("foo").getType(); + EXPECT_FALSE(boundFoo.isAnyPointer()); + EXPECT_TRUE(boundFoo.asStruct() == allTypes); + + StructSchema unbound = inner2.getFieldByName("innerUnbound").getType().asStruct(); + Type unboundFoo = unbound.getFieldByName("foo").getType(); + EXPECT_TRUE(unboundFoo.isAnyPointer()); + } + + { + InterfaceSchema cap = schema.getFieldByName("genericCap").getType().asInterface(); + InterfaceSchema::Method method = cap.getMethodByName("call"); + + StructSchema inner2 = method.getParamType(); + StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); + Type boundFoo = bound.getFieldByName("foo").getType(); + EXPECT_FALSE(boundFoo.isAnyPointer()); + EXPECT_TRUE(boundFoo.asStruct() == allTypes); + EXPECT_TRUE(inner2.getFieldByName("baz").getType().isText()); + + StructSchema results = method.getResultType(); + EXPECT_TRUE(results.getFieldByName("qux").getType().isData()); + + EXPECT_TRUE(results.getFieldByName("gen").getType().asStruct() == branded); + } +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-loader.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-loader.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,2112 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define CAPNP_PRIVATE +#include "schema-loader.h" +#include +#include +#include +#include "message.h" +#include "arena.h" +#include +#include +#include +#include +#include + +#if _MSC_VER +#include +#endif + +namespace capnp { + +namespace { + +struct ByteArrayHash { + size_t operator()(kj::ArrayPtr bytes) const { + // FNV hash. Probably sucks, but the code is simple. + // + // TODO(perf): Add CityHash or something to KJ and use it here. + + uint64_t hash = 0xcbf29ce484222325ull; + for (byte b: bytes) { + hash = hash * 0x100000001b3ull; + hash ^= b; + } + return hash; + } +}; + +struct ByteArrayEq { + bool operator()(kj::ArrayPtr a, kj::ArrayPtr b) const { + return a.size() == b.size() && memcmp(a.begin(), b.begin(), a.size()) == 0; + } +}; + +struct SchemaBindingsPair { + const _::RawSchema* schema; + const _::RawBrandedSchema::Scope* scopeBindings; + + inline bool operator==(const SchemaBindingsPair& other) const { + return schema == other.schema && scopeBindings == other.scopeBindings; + } +}; + +struct SchemaBindingsPairHash { + size_t operator()(SchemaBindingsPair pair) const { + return 31 * reinterpret_cast(pair.schema) + + reinterpret_cast(pair.scopeBindings); + } +}; + +} // namespace + +bool hasDiscriminantValue(const schema::Field::Reader& reader) { + return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT; +} + +class SchemaLoader::InitializerImpl: public _::RawSchema::Initializer { +public: + inline explicit InitializerImpl(const SchemaLoader& loader): loader(loader), callback(nullptr) {} + inline InitializerImpl(const SchemaLoader& loader, const LazyLoadCallback& callback) + : loader(loader), callback(callback) {} + + inline kj::Maybe getCallback() const { return callback; } + + void init(const _::RawSchema* schema) const override; + + inline bool operator==(decltype(nullptr)) const { return callback == nullptr; } + +private: + const SchemaLoader& loader; + kj::Maybe callback; +}; + +class SchemaLoader::BrandedInitializerImpl: public _::RawBrandedSchema::Initializer { +public: + inline explicit BrandedInitializerImpl(const SchemaLoader& loader): loader(loader) {} + + void init(const _::RawBrandedSchema* schema) const override; + +private: + const SchemaLoader& loader; +}; + +class SchemaLoader::Impl { +public: + inline explicit Impl(const SchemaLoader& loader) + : initializer(loader), brandedInitializer(loader) {} + inline Impl(const SchemaLoader& loader, const LazyLoadCallback& callback) + : initializer(loader, callback), brandedInitializer(loader) {} + + _::RawSchema* load(const schema::Node::Reader& reader, bool isPlaceholder); + + _::RawSchema* loadNative(const _::RawSchema* nativeSchema); + + _::RawSchema* loadEmpty(uint64_t id, kj::StringPtr name, schema::Node::Which kind, + bool isPlaceholder); + // Create a dummy empty schema of the given kind for the given id and load it. + + const _::RawBrandedSchema* makeBranded( + const _::RawSchema* schema, schema::Brand::Reader proto, + kj::Maybe> clientBrand); + + struct TryGetResult { + _::RawSchema* schema; + kj::Maybe callback; + }; + + TryGetResult tryGet(uint64_t typeId) const; + + const _::RawBrandedSchema* getUnbound(const _::RawSchema* schema); + + kj::Array getAllLoaded() const; + + void requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount); + // Require any struct nodes loaded with this ID -- in the past and in the future -- to have at + // least the given sizes. Struct nodes that don't comply will simply be rewritten to comply. + // This is used to ensure that parents of group nodes have at least the size of the group node, + // so that allocating a struct that contains a group then getting the group node and setting + // its fields can't possibly write outside of the allocated space. + + kj::Arena arena; + +private: + std::unordered_set, ByteArrayHash, ByteArrayEq> dedupTable; + // Records raw segments of memory in the arena against which we my want to de-dupe later + // additions. Specifically, RawBrandedSchema binding tables are de-duped. + + std::unordered_map schemas; + std::unordered_map brands; + std::unordered_map unboundBrands; + + struct RequiredSize { + uint16_t dataWordCount; + uint16_t pointerCount; + }; + std::unordered_map structSizeRequirements; + + InitializerImpl initializer; + BrandedInitializerImpl brandedInitializer; + + kj::ArrayPtr makeUncheckedNode(schema::Node::Reader node); + // Construct a copy of the given schema node, allocated as a single-segment ("unchecked") node + // within the loader's arena. + + kj::ArrayPtr makeUncheckedNodeEnforcingSizeRequirements(schema::Node::Reader node); + // Like makeUncheckedNode() but if structSizeRequirements has a requirement for this node which + // is larger than the node claims to be, the size will be edited to comply. This should be rare. + // If the incoming node is not a struct, any struct size requirements will be ignored, but if + // such requirements exist, this indicates an inconsistency that could cause exceptions later on + // (but at least can't cause memory corruption). + + kj::ArrayPtr rewriteStructNodeWithSizes( + schema::Node::Reader node, uint dataWordCount, uint pointerCount); + // Make a copy of the given node (which must be a struct node) and set its sizes to be the max + // of what it said already and the given sizes. + + // If the encoded node does not meet the given struct size requirements, make a new copy that + // does. + void applyStructSizeRequirement(_::RawSchema* raw, uint dataWordCount, uint pointerCount); + + const _::RawBrandedSchema* makeBranded(const _::RawSchema* schema, + kj::ArrayPtr scopes); + + kj::ArrayPtr makeBrandedDependencies( + const _::RawSchema* schema, + kj::Maybe> bindings); + + void makeDep(_::RawBrandedSchema::Binding& result, + schema::Type::Reader type, kj::StringPtr scopeName, + kj::Maybe> brandBindings); + void makeDep(_::RawBrandedSchema::Binding& result, + uint64_t typeId, schema::Type::Which whichType, schema::Node::Which expectedKind, + schema::Brand::Reader brand, kj::StringPtr scopeName, + kj::Maybe> brandBindings); + // Looks up the schema and brand for a dependency, or creates lazily-evaluated placeholders if + // they don't already exist, and fills in `result`. `scopeName` is a human-readable name of the + // place where the type appeared. + // + // Note that we don't simply return a Binding because we need to be careful about initialization + // to ensure that our byte-based de-duplification works. If we constructed a Binding on the stack + // and returned it, padding bytes in that Binding could go uninitialized, causing it to appear + // unique when it's not. It is expected that `result` has been zero'd via memset() before these + // methods are called. + + const _::RawBrandedSchema* makeDepSchema( + schema::Type::Reader type, kj::StringPtr scopeName, + kj::Maybe> brandBindings); + const _::RawBrandedSchema* makeDepSchema( + uint64_t typeId, schema::Type::Which whichType, schema::Node::Which expectedKind, + schema::Brand::Reader brand, kj::StringPtr scopeName, + kj::Maybe> brandBindings); + // Invoke makeDep() then return the result's schema, or nullptr if it's a primitive type. + + template + kj::ArrayPtr copyDeduped(kj::ArrayPtr values); + template + kj::ArrayPtr copyDeduped(kj::ArrayPtr values); + // Copy the given array into the arena and return the copy -- unless an identical array + // was copied previously, in which case the existing copy is returned. + + friend class SchemaLoader::BrandedInitializerImpl; +}; + +// ======================================================================================= + +inline static void verifyVoid(Void value) {} +// Calls to this will break if the parameter type changes to non-void. We use this to detect +// when the code needs updating. + +class SchemaLoader::Validator { +public: + Validator(SchemaLoader::Impl& loader): loader(loader) {} + + bool validate(const schema::Node::Reader& node) { + isValid = true; + nodeName = node.getDisplayName(); + dependencies.clear(); + + KJ_CONTEXT("validating schema node", nodeName, (uint)node.which()); + + if (node.getParameters().size() > 0) { + KJ_REQUIRE(node.getIsGeneric(), "if parameter list is non-empty, isGeneric must be true") { + isValid = false; + return false; + } + } + + switch (node.which()) { + case schema::Node::FILE: + verifyVoid(node.getFile()); + break; + case schema::Node::STRUCT: + validate(node.getStruct(), node.getScopeId()); + break; + case schema::Node::ENUM: + validate(node.getEnum()); + break; + case schema::Node::INTERFACE: + validate(node.getInterface()); + break; + case schema::Node::CONST: + validate(node.getConst()); + break; + case schema::Node::ANNOTATION: + validate(node.getAnnotation()); + break; + } + + // We accept and pass through node types we don't recognize. + return isValid; + } + + const _::RawSchema** makeDependencyArray(uint32_t* count) { + *count = dependencies.size(); + kj::ArrayPtr result = + loader.arena.allocateArray(*count); + uint pos = 0; + for (auto& dep: dependencies) { + result[pos++] = dep.second; + } + KJ_DASSERT(pos == *count); + return result.begin(); + } + + const uint16_t* makeMemberInfoArray(uint32_t* count) { + *count = members.size(); + kj::ArrayPtr result = loader.arena.allocateArray(*count); + uint pos = 0; + for (auto& member: members) { + result[pos++] = member.second; + } + KJ_DASSERT(pos == *count); + return result.begin(); + } + + const uint16_t* makeMembersByDiscriminantArray() { + return membersByDiscriminant.begin(); + } + +private: + SchemaLoader::Impl& loader; + Text::Reader nodeName; + bool isValid; + std::map dependencies; + + // Maps name -> index for each member. + std::map members; + + kj::ArrayPtr membersByDiscriminant; + +#define VALIDATE_SCHEMA(condition, ...) \ + KJ_REQUIRE(condition, ##__VA_ARGS__) { isValid = false; return; } +#define FAIL_VALIDATE_SCHEMA(...) \ + KJ_FAIL_REQUIRE(__VA_ARGS__) { isValid = false; return; } + + void validateMemberName(kj::StringPtr name, uint index) { + bool isNewName = members.insert(std::make_pair(name, index)).second; + VALIDATE_SCHEMA(isNewName, "duplicate name", name); + } + + void validate(const schema::Node::Struct::Reader& structNode, uint64_t scopeId) { + uint dataSizeInBits = structNode.getDataWordCount() * 64; + uint pointerCount = structNode.getPointerCount(); + + auto fields = structNode.getFields(); + + KJ_STACK_ARRAY(bool, sawCodeOrder, fields.size(), 32, 256); + memset(sawCodeOrder.begin(), 0, sawCodeOrder.size() * sizeof(sawCodeOrder[0])); + + KJ_STACK_ARRAY(bool, sawDiscriminantValue, structNode.getDiscriminantCount(), 32, 256); + memset(sawDiscriminantValue.begin(), 0, + sawDiscriminantValue.size() * sizeof(sawDiscriminantValue[0])); + + if (structNode.getDiscriminantCount() > 0) { + VALIDATE_SCHEMA(structNode.getDiscriminantCount() != 1, + "union must have at least two members"); + VALIDATE_SCHEMA(structNode.getDiscriminantCount() <= fields.size(), + "struct can't have more union fields than total fields"); + + VALIDATE_SCHEMA((structNode.getDiscriminantOffset() + 1) * 16 <= dataSizeInBits, + "union discriminant is out-of-bounds"); + } + + membersByDiscriminant = loader.arena.allocateArray(fields.size()); + uint discriminantPos = 0; + uint nonDiscriminantPos = structNode.getDiscriminantCount(); + + uint index = 0; + uint nextOrdinal = 0; + for (auto field: fields) { + KJ_CONTEXT("validating struct field", field.getName()); + + validateMemberName(field.getName(), index); + VALIDATE_SCHEMA(field.getCodeOrder() < sawCodeOrder.size() && + !sawCodeOrder[field.getCodeOrder()], + "invalid codeOrder"); + sawCodeOrder[field.getCodeOrder()] = true; + + auto ordinal = field.getOrdinal(); + if (ordinal.isExplicit()) { + VALIDATE_SCHEMA(ordinal.getExplicit() >= nextOrdinal, + "fields were not ordered by ordinal"); + nextOrdinal = ordinal.getExplicit() + 1; + } + + if (hasDiscriminantValue(field)) { + VALIDATE_SCHEMA(field.getDiscriminantValue() < sawDiscriminantValue.size() && + !sawDiscriminantValue[field.getDiscriminantValue()], + "invalid discriminantValue"); + sawDiscriminantValue[field.getDiscriminantValue()] = true; + + membersByDiscriminant[discriminantPos++] = index; + } else { + VALIDATE_SCHEMA(nonDiscriminantPos <= fields.size(), + "discriminantCount did not match fields"); + membersByDiscriminant[nonDiscriminantPos++] = index; + } + + switch (field.which()) { + case schema::Field::SLOT: { + auto slot = field.getSlot(); + + uint fieldBits = 0; + bool fieldIsPointer = false; + validate(slot.getType(), slot.getDefaultValue(), &fieldBits, &fieldIsPointer); + VALIDATE_SCHEMA(fieldBits * (slot.getOffset() + 1) <= dataSizeInBits && + fieldIsPointer * (slot.getOffset() + 1) <= pointerCount, + "field offset out-of-bounds", + slot.getOffset(), dataSizeInBits, pointerCount); + + break; + } + + case schema::Field::GROUP: + // Require that the group is a struct node. + validateTypeId(field.getGroup().getTypeId(), schema::Node::STRUCT); + break; + } + + ++index; + } + + // If the above code is correct, these should pass. + KJ_ASSERT(discriminantPos == structNode.getDiscriminantCount()); + KJ_ASSERT(nonDiscriminantPos == fields.size()); + + if (structNode.getIsGroup()) { + VALIDATE_SCHEMA(scopeId != 0, "group node missing scopeId"); + + // Require that the group's scope has at least the same size as the group, so that anyone + // constructing an instance of the outer scope can safely read/write the group. + loader.requireStructSize(scopeId, structNode.getDataWordCount(), + structNode.getPointerCount()); + + // Require that the parent type is a struct. + validateTypeId(scopeId, schema::Node::STRUCT); + } + } + + void validate(const schema::Node::Enum::Reader& enumNode) { + auto enumerants = enumNode.getEnumerants(); + KJ_STACK_ARRAY(bool, sawCodeOrder, enumerants.size(), 32, 256); + memset(sawCodeOrder.begin(), 0, sawCodeOrder.size() * sizeof(sawCodeOrder[0])); + + uint index = 0; + for (auto enumerant: enumerants) { + validateMemberName(enumerant.getName(), index++); + + VALIDATE_SCHEMA(enumerant.getCodeOrder() < enumerants.size() && + !sawCodeOrder[enumerant.getCodeOrder()], + "invalid codeOrder", enumerant.getName()); + sawCodeOrder[enumerant.getCodeOrder()] = true; + } + } + + void validate(const schema::Node::Interface::Reader& interfaceNode) { + for (auto extend: interfaceNode.getSuperclasses()) { + validateTypeId(extend.getId(), schema::Node::INTERFACE); + validate(extend.getBrand()); + } + + auto methods = interfaceNode.getMethods(); + KJ_STACK_ARRAY(bool, sawCodeOrder, methods.size(), 32, 256); + memset(sawCodeOrder.begin(), 0, sawCodeOrder.size() * sizeof(sawCodeOrder[0])); + + uint index = 0; + for (auto method: methods) { + KJ_CONTEXT("validating method", method.getName()); + validateMemberName(method.getName(), index++); + + VALIDATE_SCHEMA(method.getCodeOrder() < methods.size() && + !sawCodeOrder[method.getCodeOrder()], + "invalid codeOrder"); + sawCodeOrder[method.getCodeOrder()] = true; + + validateTypeId(method.getParamStructType(), schema::Node::STRUCT); + validate(method.getParamBrand()); + validateTypeId(method.getResultStructType(), schema::Node::STRUCT); + validate(method.getResultBrand()); + } + } + + void validate(const schema::Node::Const::Reader& constNode) { + uint dummy1; + bool dummy2; + validate(constNode.getType(), constNode.getValue(), &dummy1, &dummy2); + } + + void validate(const schema::Node::Annotation::Reader& annotationNode) { + validate(annotationNode.getType()); + } + + void validate(const schema::Type::Reader& type, const schema::Value::Reader& value, + uint* dataSizeInBits, bool* isPointer) { + validate(type); + + schema::Value::Which expectedValueType = schema::Value::VOID; + bool hadCase = false; + switch (type.which()) { +#define HANDLE_TYPE(name, bits, ptr) \ + case schema::Type::name: \ + expectedValueType = schema::Value::name; \ + *dataSizeInBits = bits; *isPointer = ptr; \ + hadCase = true; \ + break; + HANDLE_TYPE(VOID, 0, false) + HANDLE_TYPE(BOOL, 1, false) + HANDLE_TYPE(INT8, 8, false) + HANDLE_TYPE(INT16, 16, false) + HANDLE_TYPE(INT32, 32, false) + HANDLE_TYPE(INT64, 64, false) + HANDLE_TYPE(UINT8, 8, false) + HANDLE_TYPE(UINT16, 16, false) + HANDLE_TYPE(UINT32, 32, false) + HANDLE_TYPE(UINT64, 64, false) + HANDLE_TYPE(FLOAT32, 32, false) + HANDLE_TYPE(FLOAT64, 64, false) + HANDLE_TYPE(TEXT, 0, true) + HANDLE_TYPE(DATA, 0, true) + HANDLE_TYPE(LIST, 0, true) + HANDLE_TYPE(ENUM, 16, false) + HANDLE_TYPE(STRUCT, 0, true) + HANDLE_TYPE(INTERFACE, 0, true) + HANDLE_TYPE(ANY_POINTER, 0, true) +#undef HANDLE_TYPE + } + + if (hadCase) { + VALIDATE_SCHEMA(value.which() == expectedValueType, "Value did not match type.", + (uint)value.which(), (uint)expectedValueType); + } + } + + void validate(const schema::Type::Reader& type) { + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::ANY_POINTER: + break; + + case schema::Type::STRUCT: { + auto structType = type.getStruct(); + validateTypeId(structType.getTypeId(), schema::Node::STRUCT); + validate(structType.getBrand()); + break; + } + case schema::Type::ENUM: { + auto enumType = type.getEnum(); + validateTypeId(enumType.getTypeId(), schema::Node::ENUM); + validate(enumType.getBrand()); + break; + } + case schema::Type::INTERFACE: { + auto interfaceType = type.getInterface(); + validateTypeId(interfaceType.getTypeId(), schema::Node::INTERFACE); + validate(interfaceType.getBrand()); + break; + } + + case schema::Type::LIST: + validate(type.getList().getElementType()); + break; + } + + // We intentionally allow unknown types. + } + + void validate(const schema::Brand::Reader& brand) { + for (auto scope: brand.getScopes()) { + switch (scope.which()) { + case schema::Brand::Scope::BIND: + for (auto binding: scope.getBind()) { + switch (binding.which()) { + case schema::Brand::Binding::UNBOUND: + break; + case schema::Brand::Binding::TYPE: { + auto type = binding.getType(); + validate(type); + bool isPointer = true; + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + isPointer = false; + break; + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::ANY_POINTER: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::LIST: + isPointer = true; + break; + } + VALIDATE_SCHEMA(isPointer, + "generic type parameter must be a pointer type", type); + + break; + } + } + } + break; + case schema::Brand::Scope::INHERIT: + break; + } + } + } + + void validateTypeId(uint64_t id, schema::Node::Which expectedKind) { + _::RawSchema* existing = loader.tryGet(id).schema; + if (existing != nullptr) { + auto node = readMessageUnchecked(existing->encodedNode); + VALIDATE_SCHEMA(node.which() == expectedKind, + "expected a different kind of node for this ID", + id, (uint)expectedKind, (uint)node.which(), node.getDisplayName()); + dependencies.insert(std::make_pair(id, existing)); + return; + } + + dependencies.insert(std::make_pair(id, loader.loadEmpty( + id, kj::str("(unknown type used by ", nodeName , ")"), expectedKind, true))); + } + +#undef VALIDATE_SCHEMA +#undef FAIL_VALIDATE_SCHEMA +}; + +// ======================================================================================= + +class SchemaLoader::CompatibilityChecker { +public: + CompatibilityChecker(SchemaLoader::Impl& loader): loader(loader) {} + + bool shouldReplace(const schema::Node::Reader& existingNode, + const schema::Node::Reader& replacement, + bool preferReplacementIfEquivalent) { + this->existingNode = existingNode; + this->replacementNode = replacement; + + KJ_CONTEXT("checking compatibility with previously-loaded node of the same id", + existingNode.getDisplayName()); + + KJ_DREQUIRE(existingNode.getId() == replacement.getId()); + + nodeName = existingNode.getDisplayName(); + compatibility = EQUIVALENT; + + checkCompatibility(existingNode, replacement); + + // Prefer the newer schema. + return preferReplacementIfEquivalent ? compatibility != OLDER : compatibility == NEWER; + } + +private: + SchemaLoader::Impl& loader; + Text::Reader nodeName; + schema::Node::Reader existingNode; + schema::Node::Reader replacementNode; + + enum Compatibility { + EQUIVALENT, + OLDER, + NEWER, + INCOMPATIBLE + }; + Compatibility compatibility; + +#define VALIDATE_SCHEMA(condition, ...) \ + KJ_REQUIRE(condition, ##__VA_ARGS__) { compatibility = INCOMPATIBLE; return; } +#define FAIL_VALIDATE_SCHEMA(...) \ + KJ_FAIL_REQUIRE(__VA_ARGS__) { compatibility = INCOMPATIBLE; return; } + + void replacementIsNewer() { + switch (compatibility) { + case EQUIVALENT: + compatibility = NEWER; + break; + case OLDER: + FAIL_VALIDATE_SCHEMA("Schema node contains some changes that are upgrades and some " + "that are downgrades. All changes must be in the same direction for compatibility."); + break; + case NEWER: + break; + case INCOMPATIBLE: + break; + } + } + + void replacementIsOlder() { + switch (compatibility) { + case EQUIVALENT: + compatibility = OLDER; + break; + case OLDER: + break; + case NEWER: + FAIL_VALIDATE_SCHEMA("Schema node contains some changes that are upgrades and some " + "that are downgrades. All changes must be in the same direction for compatibility."); + break; + case INCOMPATIBLE: + break; + } + } + + void checkCompatibility(const schema::Node::Reader& node, + const schema::Node::Reader& replacement) { + // Returns whether `replacement` is equivalent, older than, newer than, or incompatible with + // `node`. If exceptions are enabled, this will throw an exception on INCOMPATIBLE. + + VALIDATE_SCHEMA(node.which() == replacement.which(), + "kind of declaration changed"); + + // No need to check compatibility of most of the non-body parts of the node: + // - Arbitrary renaming and moving between scopes is allowed. + // - Annotations are ignored for compatibility purposes. + + if (replacement.getParameters().size() > node.getParameters().size()) { + replacementIsNewer(); + } else if (replacement.getParameters().size() < node.getParameters().size()) { + replacementIsOlder(); + } + + switch (node.which()) { + case schema::Node::FILE: + verifyVoid(node.getFile()); + break; + case schema::Node::STRUCT: + checkCompatibility(node.getStruct(), replacement.getStruct(), + node.getScopeId(), replacement.getScopeId()); + break; + case schema::Node::ENUM: + checkCompatibility(node.getEnum(), replacement.getEnum()); + break; + case schema::Node::INTERFACE: + checkCompatibility(node.getInterface(), replacement.getInterface()); + break; + case schema::Node::CONST: + checkCompatibility(node.getConst(), replacement.getConst()); + break; + case schema::Node::ANNOTATION: + checkCompatibility(node.getAnnotation(), replacement.getAnnotation()); + break; + } + } + + void checkCompatibility(const schema::Node::Struct::Reader& structNode, + const schema::Node::Struct::Reader& replacement, + uint64_t scopeId, uint64_t replacementScopeId) { + if (replacement.getDataWordCount() > structNode.getDataWordCount()) { + replacementIsNewer(); + } else if (replacement.getDataWordCount() < structNode.getDataWordCount()) { + replacementIsOlder(); + } + if (replacement.getPointerCount() > structNode.getPointerCount()) { + replacementIsNewer(); + } else if (replacement.getPointerCount() < structNode.getPointerCount()) { + replacementIsOlder(); + } + if (replacement.getDiscriminantCount() > structNode.getDiscriminantCount()) { + replacementIsNewer(); + } else if (replacement.getDiscriminantCount() < structNode.getDiscriminantCount()) { + replacementIsOlder(); + } + + if (replacement.getDiscriminantCount() > 0 && structNode.getDiscriminantCount() > 0) { + VALIDATE_SCHEMA(replacement.getDiscriminantOffset() == structNode.getDiscriminantOffset(), + "union discriminant position changed"); + } + + // The shared members should occupy corresponding positions in the member lists, since the + // lists are sorted by ordinal. + auto fields = structNode.getFields(); + auto replacementFields = replacement.getFields(); + uint count = std::min(fields.size(), replacementFields.size()); + + if (replacementFields.size() > fields.size()) { + replacementIsNewer(); + } else if (replacementFields.size() < fields.size()) { + replacementIsOlder(); + } + + for (uint i = 0; i < count; i++) { + checkCompatibility(fields[i], replacementFields[i]); + } + + // For the moment, we allow "upgrading" from non-group to group, mainly so that the + // placeholders we generate for group parents (which in the absence of more info, we assume to + // be non-groups) can be replaced with groups. + // + // TODO(cleanup): The placeholder approach is really breaking down. Maybe we need to maintain + // a list of expectations for nodes we haven't loaded yet. + if (structNode.getIsGroup()) { + if (replacement.getIsGroup()) { + VALIDATE_SCHEMA(replacementScopeId == scopeId, "group node's scope changed"); + } else { + replacementIsOlder(); + } + } else { + if (replacement.getIsGroup()) { + replacementIsNewer(); + } + } + } + + void checkCompatibility(const schema::Field::Reader& field, + const schema::Field::Reader& replacement) { + KJ_CONTEXT("comparing struct field", field.getName()); + + // A field that is initially not in a union can be upgraded to be in one, as long as it has + // discriminant 0. + uint discriminant = hasDiscriminantValue(field) ? field.getDiscriminantValue() : 0; + uint replacementDiscriminant = + hasDiscriminantValue(replacement) ? replacement.getDiscriminantValue() : 0; + VALIDATE_SCHEMA(discriminant == replacementDiscriminant, "Field discriminant changed."); + + switch (field.which()) { + case schema::Field::SLOT: { + auto slot = field.getSlot(); + + switch (replacement.which()) { + case schema::Field::SLOT: { + auto replacementSlot = replacement.getSlot(); + + checkCompatibility(slot.getType(), replacementSlot.getType(), + NO_UPGRADE_TO_STRUCT); + checkDefaultCompatibility(slot.getDefaultValue(), + replacementSlot.getDefaultValue()); + + VALIDATE_SCHEMA(slot.getOffset() == replacementSlot.getOffset(), + "field position changed"); + break; + } + case schema::Field::GROUP: + checkUpgradeToStruct(slot.getType(), replacement.getGroup().getTypeId(), + existingNode, field); + break; + } + + break; + } + + case schema::Field::GROUP: + switch (replacement.which()) { + case schema::Field::SLOT: + checkUpgradeToStruct(replacement.getSlot().getType(), field.getGroup().getTypeId(), + replacementNode, replacement); + break; + case schema::Field::GROUP: + VALIDATE_SCHEMA(field.getGroup().getTypeId() == replacement.getGroup().getTypeId(), + "group id changed"); + break; + } + break; + } + } + + void checkCompatibility(const schema::Node::Enum::Reader& enumNode, + const schema::Node::Enum::Reader& replacement) { + uint size = enumNode.getEnumerants().size(); + uint replacementSize = replacement.getEnumerants().size(); + if (replacementSize > size) { + replacementIsNewer(); + } else if (replacementSize < size) { + replacementIsOlder(); + } + } + + void checkCompatibility(const schema::Node::Interface::Reader& interfaceNode, + const schema::Node::Interface::Reader& replacement) { + { + // Check superclasses. + + kj::Vector superclasses; + kj::Vector replacementSuperclasses; + for (auto superclass: interfaceNode.getSuperclasses()) { + superclasses.add(superclass.getId()); + } + for (auto superclass: replacement.getSuperclasses()) { + replacementSuperclasses.add(superclass.getId()); + } + std::sort(superclasses.begin(), superclasses.end()); + std::sort(replacementSuperclasses.begin(), replacementSuperclasses.end()); + + auto iter = superclasses.begin(); + auto replacementIter = replacementSuperclasses.begin(); + + while (iter != superclasses.end() || replacementIter != replacementSuperclasses.end()) { + if (iter == superclasses.end()) { + replacementIsNewer(); + break; + } else if (replacementIter == replacementSuperclasses.end()) { + replacementIsOlder(); + break; + } else if (*iter < *replacementIter) { + replacementIsOlder(); + ++iter; + } else if (*iter > *replacementIter) { + replacementIsNewer(); + ++replacementIter; + } else { + ++iter; + ++replacementIter; + } + } + } + + auto methods = interfaceNode.getMethods(); + auto replacementMethods = replacement.getMethods(); + + if (replacementMethods.size() > methods.size()) { + replacementIsNewer(); + } else if (replacementMethods.size() < methods.size()) { + replacementIsOlder(); + } + + uint count = std::min(methods.size(), replacementMethods.size()); + + for (uint i = 0; i < count; i++) { + checkCompatibility(methods[i], replacementMethods[i]); + } + } + + void checkCompatibility(const schema::Method::Reader& method, + const schema::Method::Reader& replacement) { + KJ_CONTEXT("comparing method", method.getName()); + + // TODO(someday): Allow named parameter list to be replaced by compatible struct type. + VALIDATE_SCHEMA(method.getParamStructType() == replacement.getParamStructType(), + "Updated method has different parameters."); + VALIDATE_SCHEMA(method.getResultStructType() == replacement.getResultStructType(), + "Updated method has different results."); + } + + void checkCompatibility(const schema::Node::Const::Reader& constNode, + const schema::Node::Const::Reader& replacement) { + // Who cares? These don't appear on the wire. + } + + void checkCompatibility(const schema::Node::Annotation::Reader& annotationNode, + const schema::Node::Annotation::Reader& replacement) { + // Who cares? These don't appear on the wire. + } + + enum UpgradeToStructMode { + ALLOW_UPGRADE_TO_STRUCT, + NO_UPGRADE_TO_STRUCT + }; + + void checkCompatibility(const schema::Type::Reader& type, + const schema::Type::Reader& replacement, + UpgradeToStructMode upgradeToStructMode) { + if (replacement.which() != type.which()) { + // Check for allowed "upgrade" to Data or AnyPointer. + if (replacement.isData() && canUpgradeToData(type)) { + replacementIsNewer(); + return; + } else if (type.isData() && canUpgradeToData(replacement)) { + replacementIsOlder(); + return; + } else if (replacement.isAnyPointer() && canUpgradeToAnyPointer(type)) { + replacementIsNewer(); + return; + } else if (type.isAnyPointer() && canUpgradeToAnyPointer(replacement)) { + replacementIsOlder(); + return; + } + + if (upgradeToStructMode == ALLOW_UPGRADE_TO_STRUCT) { + if (type.isStruct()) { + checkUpgradeToStruct(replacement, type.getStruct().getTypeId()); + return; + } else if (replacement.isStruct()) { + checkUpgradeToStruct(type, replacement.getStruct().getTypeId()); + return; + } + } + + FAIL_VALIDATE_SCHEMA("a type was changed"); + } + + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::ANY_POINTER: + return; + + case schema::Type::LIST: + checkCompatibility(type.getList().getElementType(), replacement.getList().getElementType(), + ALLOW_UPGRADE_TO_STRUCT); + return; + + case schema::Type::ENUM: + VALIDATE_SCHEMA(replacement.getEnum().getTypeId() == type.getEnum().getTypeId(), + "type changed enum type"); + return; + + case schema::Type::STRUCT: + // TODO(someday): If the IDs don't match, we should compare the two structs for + // compatibility. This is tricky, though, because the new type's target may not yet be + // loaded. In that case we could take the old type, make a copy of it, assign the new + // ID to the copy, and load() that. That forces any struct type loaded for that ID to + // be compatible. However, that has another problem, which is that it could be that the + // whole reason the type was replaced was to fork that type, and so an incompatibility + // could be very much expected. This could be a rat hole... + VALIDATE_SCHEMA(replacement.getStruct().getTypeId() == type.getStruct().getTypeId(), + "type changed to incompatible struct type"); + return; + + case schema::Type::INTERFACE: + VALIDATE_SCHEMA(replacement.getInterface().getTypeId() == type.getInterface().getTypeId(), + "type changed to incompatible interface type"); + return; + } + + // We assume unknown types (from newer versions of Cap'n Proto?) are equivalent. + } + + void checkUpgradeToStruct(const schema::Type::Reader& type, uint64_t structTypeId, + kj::Maybe matchSize = nullptr, + kj::Maybe matchPosition = nullptr) { + // We can't just look up the target struct and check it because it may not have been loaded + // yet. Instead, we contrive a struct that looks like what we want and load() that, which + // guarantees that any incompatibility will be caught either now or when the real version of + // that struct is loaded. + + word scratch[32]; + memset(scratch, 0, sizeof(scratch)); + MallocMessageBuilder builder(scratch); + auto node = builder.initRoot(); + node.setId(structTypeId); + node.setDisplayName(kj::str("(unknown type used in ", nodeName, ")")); + auto structNode = node.initStruct(); + + switch (type.which()) { + case schema::Type::VOID: + structNode.setDataWordCount(0); + structNode.setPointerCount(0); + break; + + case schema::Type::BOOL: + structNode.setDataWordCount(1); + structNode.setPointerCount(0); + break; + + case schema::Type::INT8: + case schema::Type::UINT8: + structNode.setDataWordCount(1); + structNode.setPointerCount(0); + break; + + case schema::Type::INT16: + case schema::Type::UINT16: + case schema::Type::ENUM: + structNode.setDataWordCount(1); + structNode.setPointerCount(0); + break; + + case schema::Type::INT32: + case schema::Type::UINT32: + case schema::Type::FLOAT32: + structNode.setDataWordCount(1); + structNode.setPointerCount(0); + break; + + case schema::Type::INT64: + case schema::Type::UINT64: + case schema::Type::FLOAT64: + structNode.setDataWordCount(1); + structNode.setPointerCount(0); + break; + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + structNode.setDataWordCount(0); + structNode.setPointerCount(1); + break; + } + + KJ_IF_MAYBE(s, matchSize) { + auto match = s->getStruct(); + structNode.setDataWordCount(match.getDataWordCount()); + structNode.setPointerCount(match.getPointerCount()); + } + + auto field = structNode.initFields(1)[0]; + field.setName("member0"); + field.setCodeOrder(0); + auto slot = field.initSlot(); + slot.setType(type); + + KJ_IF_MAYBE(p, matchPosition) { + if (p->getOrdinal().isExplicit()) { + field.getOrdinal().setExplicit(p->getOrdinal().getExplicit()); + } else { + field.getOrdinal().setImplicit(); + } + auto matchSlot = p->getSlot(); + slot.setOffset(matchSlot.getOffset()); + slot.setDefaultValue(matchSlot.getDefaultValue()); + } else { + field.getOrdinal().setExplicit(0); + slot.setOffset(0); + + schema::Value::Builder value = slot.initDefaultValue(); + switch (type.which()) { + case schema::Type::VOID: value.setVoid(); break; + case schema::Type::BOOL: value.setBool(false); break; + case schema::Type::INT8: value.setInt8(0); break; + case schema::Type::INT16: value.setInt16(0); break; + case schema::Type::INT32: value.setInt32(0); break; + case schema::Type::INT64: value.setInt64(0); break; + case schema::Type::UINT8: value.setUint8(0); break; + case schema::Type::UINT16: value.setUint16(0); break; + case schema::Type::UINT32: value.setUint32(0); break; + case schema::Type::UINT64: value.setUint64(0); break; + case schema::Type::FLOAT32: value.setFloat32(0); break; + case schema::Type::FLOAT64: value.setFloat64(0); break; + case schema::Type::ENUM: value.setEnum(0); break; + case schema::Type::TEXT: value.adoptText(Orphan()); break; + case schema::Type::DATA: value.adoptData(Orphan()); break; + case schema::Type::LIST: value.initList(); break; + case schema::Type::STRUCT: value.initStruct(); break; + case schema::Type::INTERFACE: value.setInterface(); break; + case schema::Type::ANY_POINTER: value.initAnyPointer(); break; + } + } + + loader.load(node, true); + } + + bool canUpgradeToData(const schema::Type::Reader& type) { + if (type.isText()) { + return true; + } else if (type.isList()) { + switch (type.getList().getElementType().which()) { + case schema::Type::INT8: + case schema::Type::UINT8: + return true; + default: + return false; + } + } else { + return false; + } + } + + bool canUpgradeToAnyPointer(const schema::Type::Reader& type) { + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::ENUM: + return false; + + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::LIST: + case schema::Type::STRUCT: + case schema::Type::INTERFACE: + case schema::Type::ANY_POINTER: + return true; + } + + // Be lenient with unknown types. + return true; + } + + void checkDefaultCompatibility(const schema::Value::Reader& value, + const schema::Value::Reader& replacement) { + // Note that we test default compatibility only after testing type compatibility, and default + // values have already been validated as matching their types, so this should pass. + KJ_ASSERT(value.which() == replacement.which()) { + compatibility = INCOMPATIBLE; + return; + } + + switch (value.which()) { +#define HANDLE_TYPE(discrim, name) \ + case schema::Value::discrim: \ + VALIDATE_SCHEMA(value.get##name() == replacement.get##name(), "default value changed"); \ + break; + HANDLE_TYPE(VOID, Void); + HANDLE_TYPE(BOOL, Bool); + HANDLE_TYPE(INT8, Int8); + HANDLE_TYPE(INT16, Int16); + HANDLE_TYPE(INT32, Int32); + HANDLE_TYPE(INT64, Int64); + HANDLE_TYPE(UINT8, Uint8); + HANDLE_TYPE(UINT16, Uint16); + HANDLE_TYPE(UINT32, Uint32); + HANDLE_TYPE(UINT64, Uint64); + HANDLE_TYPE(FLOAT32, Float32); + HANDLE_TYPE(FLOAT64, Float64); + HANDLE_TYPE(ENUM, Enum); +#undef HANDLE_TYPE + + case schema::Value::TEXT: + case schema::Value::DATA: + case schema::Value::LIST: + case schema::Value::STRUCT: + case schema::Value::INTERFACE: + case schema::Value::ANY_POINTER: + // It's not a big deal if default values for pointers change, and it would be difficult for + // us to compare these defaults here, so just let it slide. + break; + } + } +}; + +// ======================================================================================= + +_::RawSchema* SchemaLoader::Impl::load(const schema::Node::Reader& reader, bool isPlaceholder) { + // Make a copy of the node which can be used unchecked. + kj::ArrayPtr validated = makeUncheckedNodeEnforcingSizeRequirements(reader); + + // Validate the copy. + Validator validator(*this); + auto validatedReader = readMessageUnchecked(validated.begin()); + + if (!validator.validate(validatedReader)) { + // Not valid. Construct an empty schema of the same type and return that. + return loadEmpty(validatedReader.getId(), + validatedReader.getDisplayName(), + validatedReader.which(), + false); + } + + // Check if we already have a schema for this ID. + _::RawSchema*& slot = schemas[validatedReader.getId()]; + bool shouldReplace; + bool shouldClearInitializer; + if (slot == nullptr) { + // Nope, allocate a new RawSchema. + slot = &arena.allocate<_::RawSchema>(); + memset(&slot->defaultBrand, 0, sizeof(slot->defaultBrand)); + slot->id = validatedReader.getId(); + slot->canCastTo = nullptr; + slot->defaultBrand.generic = slot; + slot->lazyInitializer = isPlaceholder ? &initializer : nullptr; + slot->defaultBrand.lazyInitializer = isPlaceholder ? &brandedInitializer : nullptr; + shouldReplace = true; + shouldClearInitializer = false; + } else { + // Yes, check if it is compatible and figure out which schema is newer. + + // If the existing slot is a placeholder, but we're upgrading it to a non-placeholder, we + // need to clear the initializer later. + shouldClearInitializer = slot->lazyInitializer != nullptr && !isPlaceholder; + + auto existing = readMessageUnchecked(slot->encodedNode); + CompatibilityChecker checker(*this); + + // Prefer to replace the existing schema if the existing schema is a placeholder. Otherwise, + // prefer to keep the existing schema. + shouldReplace = checker.shouldReplace( + existing, validatedReader, slot->lazyInitializer != nullptr); + } + + if (shouldReplace) { + // Initialize the RawSchema. + slot->encodedNode = validated.begin(); + slot->encodedSize = validated.size(); + slot->dependencies = validator.makeDependencyArray(&slot->dependencyCount); + slot->membersByName = validator.makeMemberInfoArray(&slot->memberCount); + slot->membersByDiscriminant = validator.makeMembersByDiscriminantArray(); + + // Even though this schema isn't itself branded, it may have dependencies that are. So, we + // need to set up the "dependencies" map under defaultBrand. + auto deps = makeBrandedDependencies(slot, kj::ArrayPtr()); + slot->defaultBrand.dependencies = deps.begin(); + slot->defaultBrand.dependencyCount = deps.size(); + } + + if (shouldClearInitializer) { + // If this schema is not newly-allocated, it may already be in the wild, specifically in the + // dependency list of other schemas. Once the initializer is null, it is live, so we must do + // a release-store here. +#if __GNUC__ + __atomic_store_n(&slot->lazyInitializer, nullptr, __ATOMIC_RELEASE); + __atomic_store_n(&slot->defaultBrand.lazyInitializer, nullptr, __ATOMIC_RELEASE); +#elif _MSC_VER + std::atomic_thread_fence(std::memory_order_release); + *static_cast<_::RawSchema::Initializer const* volatile*>(&slot->lazyInitializer) = nullptr; + *static_cast<_::RawBrandedSchema::Initializer const* volatile*>( + &slot->defaultBrand.lazyInitializer) = nullptr; +#else +#error "Platform not supported" +#endif + } + + return slot; +} + +_::RawSchema* SchemaLoader::Impl::loadNative(const _::RawSchema* nativeSchema) { + _::RawSchema*& slot = schemas[nativeSchema->id]; + bool shouldReplace; + bool shouldClearInitializer; + if (slot == nullptr) { + slot = &arena.allocate<_::RawSchema>(); + memset(&slot->defaultBrand, 0, sizeof(slot->defaultBrand)); + slot->defaultBrand.generic = slot; + slot->lazyInitializer = nullptr; + slot->defaultBrand.lazyInitializer = nullptr; + shouldReplace = true; + shouldClearInitializer = false; // already cleared above + } else if (slot->canCastTo != nullptr) { + // Already loaded natively, or we're currently in the process of loading natively and there + // was a dependency cycle. + KJ_REQUIRE(slot->canCastTo == nativeSchema, + "two different compiled-in type have the same type ID", + nativeSchema->id, + readMessageUnchecked(nativeSchema->encodedNode).getDisplayName(), + readMessageUnchecked(slot->canCastTo->encodedNode).getDisplayName()); + return slot; + } else { + auto existing = readMessageUnchecked(slot->encodedNode); + auto native = readMessageUnchecked(nativeSchema->encodedNode); + CompatibilityChecker checker(*this); + shouldReplace = checker.shouldReplace(existing, native, true); + shouldClearInitializer = slot->lazyInitializer != nullptr; + } + + // Since we recurse below, the slot in the hash map could move around. Copy out the pointer + // for subsequent use. + // TODO(cleanup): Above comment is actually not true of unordered_map. Leaving here to explain + // code pattern below. + _::RawSchema* result = slot; + + if (shouldReplace) { + // Set the schema to a copy of the native schema, but make sure not to null out lazyInitializer + // yet. + _::RawSchema temp = *nativeSchema; + temp.lazyInitializer = result->lazyInitializer; + *result = temp; + + result->defaultBrand.generic = result; + + // Indicate that casting is safe. Note that it's important to set this before recursively + // loading dependencies, so that cycles don't cause infinite loops! + result->canCastTo = nativeSchema; + + // We need to set the dependency list to point at other loader-owned RawSchemas. + kj::ArrayPtr dependencies = + arena.allocateArray(result->dependencyCount); + for (uint i = 0; i < nativeSchema->dependencyCount; i++) { + dependencies[i] = loadNative(nativeSchema->dependencies[i]); + } + result->dependencies = dependencies.begin(); + + // Also need to re-do the branded dependencies. + auto deps = makeBrandedDependencies(slot, kj::ArrayPtr()); + slot->defaultBrand.dependencies = deps.begin(); + slot->defaultBrand.dependencyCount = deps.size(); + + // If there is a struct size requirement, we need to make sure that it is satisfied. + auto reqIter = structSizeRequirements.find(nativeSchema->id); + if (reqIter != structSizeRequirements.end()) { + applyStructSizeRequirement(result, reqIter->second.dataWordCount, + reqIter->second.pointerCount); + } + } else { + // The existing schema is newer. + + // Indicate that casting is safe. Note that it's important to set this before recursively + // loading dependencies, so that cycles don't cause infinite loops! + result->canCastTo = nativeSchema; + + // Make sure the dependencies are loaded and compatible. + for (uint i = 0; i < nativeSchema->dependencyCount; i++) { + loadNative(nativeSchema->dependencies[i]); + } + } + + if (shouldClearInitializer) { + // If this schema is not newly-allocated, it may already be in the wild, specifically in the + // dependency list of other schemas. Once the initializer is null, it is live, so we must do + // a release-store here. +#if __GNUC__ + __atomic_store_n(&result->lazyInitializer, nullptr, __ATOMIC_RELEASE); + __atomic_store_n(&result->defaultBrand.lazyInitializer, nullptr, __ATOMIC_RELEASE); +#elif _MSC_VER + std::atomic_thread_fence(std::memory_order_release); + *static_cast<_::RawSchema::Initializer const* volatile*>(&result->lazyInitializer) = nullptr; + *static_cast<_::RawBrandedSchema::Initializer const* volatile*>( + &result->defaultBrand.lazyInitializer) = nullptr; +#else +#error "Platform not supported" +#endif + } + + return result; +} + +_::RawSchema* SchemaLoader::Impl::loadEmpty( + uint64_t id, kj::StringPtr name, schema::Node::Which kind, bool isPlaceholder) { + word scratch[32]; + memset(scratch, 0, sizeof(scratch)); + MallocMessageBuilder builder(scratch); + auto node = builder.initRoot(); + node.setId(id); + node.setDisplayName(name); + switch (kind) { + case schema::Node::STRUCT: node.initStruct(); break; + case schema::Node::ENUM: node.initEnum(); break; + case schema::Node::INTERFACE: node.initInterface(); break; + + case schema::Node::FILE: + case schema::Node::CONST: + case schema::Node::ANNOTATION: + KJ_FAIL_REQUIRE("Not a type."); + break; + } + + return load(node, isPlaceholder); +} + +const _::RawBrandedSchema* SchemaLoader::Impl::makeBranded( + const _::RawSchema* schema, schema::Brand::Reader proto, + kj::Maybe> clientBrand) { + kj::StringPtr scopeName = + readMessageUnchecked(schema->encodedNode).getDisplayName(); + + auto srcScopes = proto.getScopes(); + + KJ_STACK_ARRAY(_::RawBrandedSchema::Scope, dstScopes, srcScopes.size(), 16, 32); + memset(dstScopes.begin(), 0, dstScopes.size() * sizeof(dstScopes[0])); + + uint dstScopeCount = 0; + for (auto srcScope: srcScopes) { + switch (srcScope.which()) { + case schema::Brand::Scope::BIND: { + auto srcBindings = srcScope.getBind(); + KJ_STACK_ARRAY(_::RawBrandedSchema::Binding, dstBindings, srcBindings.size(), 16, 32); + memset(dstBindings.begin(), 0, dstBindings.size() * sizeof(dstBindings[0])); + + for (auto j: kj::indices(srcBindings)) { + auto srcBinding = srcBindings[j]; + auto& dstBinding = dstBindings[j]; + + memset(&dstBinding, 0, sizeof(dstBinding)); + dstBinding.which = schema::Type::ANY_POINTER; + + switch (srcBinding.which()) { + case schema::Brand::Binding::UNBOUND: + break; + case schema::Brand::Binding::TYPE: { + makeDep(dstBinding, srcBinding.getType(), scopeName, clientBrand); + break; + } + } + } + + auto& dstScope = dstScopes[dstScopeCount++]; + dstScope.typeId = srcScope.getScopeId(); + dstScope.bindingCount = dstBindings.size(); + dstScope.bindings = copyDeduped(dstBindings).begin(); + break; + } + case schema::Brand::Scope::INHERIT: { + // Inherit the whole scope from the client -- or if the client doesn't have it, at least + // include an empty dstScope in the list just to show that this scope was specified as + // inherited, as opposed to being unspecified (which would be treated as all AnyPointer). + auto& dstScope = dstScopes[dstScopeCount++]; + dstScope.typeId = srcScope.getScopeId(); + + KJ_IF_MAYBE(b, clientBrand) { + for (auto& clientScope: *b) { + if (clientScope.typeId == dstScope.typeId) { + // Overwrite the whole thing. + dstScope = clientScope; + break; + } + } + } else { + dstScope.isUnbound = true; + } + break; + } + } + } + + dstScopes = dstScopes.slice(0, dstScopeCount); + + std::sort(dstScopes.begin(), dstScopes.end(), + [](const _::RawBrandedSchema::Scope& a, const _::RawBrandedSchema::Scope& b) { + return a.typeId < b.typeId; + }); + + return makeBranded(schema, copyDeduped(dstScopes)); +} + +const _::RawBrandedSchema* SchemaLoader::Impl::makeBranded( + const _::RawSchema* schema, kj::ArrayPtr bindings) { + // Note that even if `bindings` is empty, we never want to return defaultBrand here because + // defaultBrand has special status. Normally, the lack of bindings means all parameters are + // "unspecified", which means their bindings are unknown and should be treated as AnyPointer. + // But defaultBrand represents a special case where all parameters are still parameters -- they + // haven't been bound in the first place. defaultBrand is used to represent the unbranded generic + // type, while a no-binding brand is equivalent to binding all parameters to AnyPointer. + + if (bindings.size() == 0) { + return &schema->defaultBrand; + } + + auto& slot = brands[SchemaBindingsPair { schema, bindings.begin() }]; + + if (slot == nullptr) { + auto& brand = arena.allocate<_::RawBrandedSchema>(); + memset(&brand, 0, sizeof(brand)); + slot = &brand; + + brand.generic = schema; + brand.scopes = bindings.begin(); + brand.scopeCount = bindings.size(); + brand.lazyInitializer = &brandedInitializer; + } + + return slot; +} + +kj::ArrayPtr +SchemaLoader::Impl::makeBrandedDependencies( + const _::RawSchema* schema, + kj::Maybe> bindings) { + kj::StringPtr scopeName = + readMessageUnchecked(schema->encodedNode).getDisplayName(); + + kj::Vector<_::RawBrandedSchema::Dependency> deps; + + schema::Node::Reader node = readMessageUnchecked(schema->encodedNode); + +#define ADD_ENTRY(kind, index, make) \ + if (const _::RawBrandedSchema* dep = make) { \ + auto& slot = deps.add(); \ + memset(&slot, 0, sizeof(slot)); \ + slot.location = _::RawBrandedSchema::makeDepLocation( \ + _::RawBrandedSchema::DepKind::kind, index); \ + slot.schema = dep; \ + } + + switch (node.which()) { + case schema::Node::FILE: + case schema::Node::ENUM: + case schema::Node::ANNOTATION: + break; + + case schema::Node::CONST: + ADD_ENTRY(CONST_TYPE, 0, makeDepSchema( + node.getConst().getType(), scopeName, bindings)); + break; + + case schema::Node::STRUCT: { + auto fields = node.getStruct().getFields(); + for (auto i: kj::indices(fields)) { + auto field = fields[i]; + switch (field.which()) { + case schema::Field::SLOT: + ADD_ENTRY(FIELD, i, makeDepSchema( + field.getSlot().getType(), scopeName, bindings)) + break; + case schema::Field::GROUP: { + const _::RawSchema* group = loadEmpty( + field.getGroup().getTypeId(), + "(unknown group type)", schema::Node::STRUCT, true); + KJ_IF_MAYBE(b, bindings) { + ADD_ENTRY(FIELD, i, makeBranded(group, *b)); + } else { + ADD_ENTRY(FIELD, i, getUnbound(group)); + } + break; + } + } + } + break; + } + + case schema::Node::INTERFACE: { + auto interface = node.getInterface(); + { + auto superclasses = interface.getSuperclasses(); + for (auto i: kj::indices(superclasses)) { + auto superclass = superclasses[i]; + ADD_ENTRY(SUPERCLASS, i, makeDepSchema( + superclass.getId(), schema::Type::INTERFACE, schema::Node::INTERFACE, + superclass.getBrand(), scopeName, bindings)) + } + } + { + auto methods = interface.getMethods(); + for (auto i: kj::indices(methods)) { + auto method = methods[i]; + ADD_ENTRY(METHOD_PARAMS, i, makeDepSchema( + method.getParamStructType(), schema::Type::STRUCT, schema::Node::STRUCT, + method.getParamBrand(), scopeName, bindings)) + ADD_ENTRY(METHOD_RESULTS, i, makeDepSchema( + method.getResultStructType(), schema::Type::STRUCT, schema::Node::STRUCT, + method.getResultBrand(), scopeName, bindings)) + } + } + break; + } + } + +#undef ADD_ENTRY + + std::sort(deps.begin(), deps.end(), + [](const _::RawBrandedSchema::Dependency& a, const _::RawBrandedSchema::Dependency& b) { + return a.location < b.location; + }); + + return copyDeduped(deps.asPtr()); +} + +void SchemaLoader::Impl::makeDep(_::RawBrandedSchema::Binding& result, + schema::Type::Reader type, kj::StringPtr scopeName, + kj::Maybe> brandBindings) { + switch (type.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + result.which = static_cast(type.which()); + return; + + case schema::Type::STRUCT: { + auto structType = type.getStruct(); + makeDep(result, structType.getTypeId(), schema::Type::STRUCT, schema::Node::STRUCT, + structType.getBrand(), scopeName, brandBindings); + return; + } + case schema::Type::ENUM: { + auto enumType = type.getEnum(); + makeDep(result, enumType.getTypeId(), schema::Type::ENUM, schema::Node::ENUM, + enumType.getBrand(), scopeName, brandBindings); + return; + } + case schema::Type::INTERFACE: { + auto interfaceType = type.getInterface(); + makeDep(result, interfaceType.getTypeId(), schema::Type::INTERFACE, schema::Node::INTERFACE, + interfaceType.getBrand(), scopeName, brandBindings); + return; + } + + case schema::Type::LIST: { + makeDep(result, type.getList().getElementType(), scopeName, brandBindings); + ++result.listDepth; + return; + } + + case schema::Type::ANY_POINTER: { + result.which = static_cast(schema::Type::ANY_POINTER); + auto anyPointer = type.getAnyPointer(); + switch (anyPointer.which()) { + case schema::Type::AnyPointer::UNCONSTRAINED: + return; + case schema::Type::AnyPointer::PARAMETER: { + auto param = anyPointer.getParameter(); + uint64_t id = param.getScopeId(); + uint16_t index = param.getParameterIndex(); + + KJ_IF_MAYBE(b, brandBindings) { + // TODO(perf): We could binary search here, but... bleh. + for (auto& scope: *b) { + if (scope.typeId == id) { + if (scope.isUnbound) { + // Unbound brand parameter. + result.scopeId = id; + result.paramIndex = index; + return; + } else if (index >= scope.bindingCount) { + // Binding index out-of-range. Treat as AnyPointer. This is important to allow + // new type parameters to be added to existing types without breaking dependent + // schemas. + return; + } else { + result = scope.bindings[index]; + return; + } + } + } + return; + } else { + // Unbound brand parameter. + result.scopeId = id; + result.paramIndex = index; + return; + } + } + case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: + result.isImplicitParameter = true; + result.paramIndex = anyPointer.getImplicitMethodParameter().getParameterIndex(); + return; + } + KJ_UNREACHABLE; + } + } + + KJ_UNREACHABLE; +} + +void SchemaLoader::Impl::makeDep(_::RawBrandedSchema::Binding& result, + uint64_t typeId, schema::Type::Which whichType, schema::Node::Which expectedKind, + schema::Brand::Reader brand, kj::StringPtr scopeName, + kj::Maybe> brandBindings) { + const _::RawSchema* schema = loadEmpty(typeId, + kj::str("(unknown type; seen as dependency of ", scopeName, ")"), + expectedKind, true); + result.which = static_cast(whichType); + result.schema = makeBranded(schema, brand, brandBindings); +} + +const _::RawBrandedSchema* SchemaLoader::Impl::makeDepSchema( + schema::Type::Reader type, kj::StringPtr scopeName, + kj::Maybe> brandBindings) { + _::RawBrandedSchema::Binding binding; + memset(&binding, 0, sizeof(binding)); + makeDep(binding, type, scopeName, brandBindings); + return binding.schema; +} + +const _::RawBrandedSchema* SchemaLoader::Impl::makeDepSchema( + uint64_t typeId, schema::Type::Which whichType, schema::Node::Which expectedKind, + schema::Brand::Reader brand, kj::StringPtr scopeName, + kj::Maybe> brandBindings) { + _::RawBrandedSchema::Binding binding; + memset(&binding, 0, sizeof(binding)); + makeDep(binding, typeId, whichType, expectedKind, brand, scopeName, brandBindings); + return binding.schema; +} + +template +kj::ArrayPtr SchemaLoader::Impl::copyDeduped(kj::ArrayPtr values) { + if (values.size() == 0) { + return kj::arrayPtr(kj::implicitCast(nullptr), 0); + } + + auto bytes = values.asBytes(); + + auto iter = dedupTable.find(bytes); + if (iter != dedupTable.end()) { + return kj::arrayPtr(reinterpret_cast(iter->begin()), values.size()); + } + + // Need to make a new copy. + auto copy = arena.allocateArray(values.size()); + memcpy(copy.begin(), values.begin(), values.size() * sizeof(T)); + + KJ_ASSERT(dedupTable.insert(copy.asBytes()).second); + + return copy; +} + +template +kj::ArrayPtr SchemaLoader::Impl::copyDeduped(kj::ArrayPtr values) { + return copyDeduped(kj::ArrayPtr(values)); +} + +SchemaLoader::Impl::TryGetResult SchemaLoader::Impl::tryGet(uint64_t typeId) const { + auto iter = schemas.find(typeId); + if (iter == schemas.end()) { + return {nullptr, initializer.getCallback()}; + } else { + return {iter->second, initializer.getCallback()}; + } +} + +const _::RawBrandedSchema* SchemaLoader::Impl::getUnbound(const _::RawSchema* schema) { + if (!readMessageUnchecked(schema->encodedNode).getIsGeneric()) { + // Not a generic type, so just return the default brand. + return &schema->defaultBrand; + } + + auto& slot = unboundBrands[schema]; + if (slot == nullptr) { + slot = &arena.allocate<_::RawBrandedSchema>(); + memset(slot, 0, sizeof(*slot)); + slot->generic = schema; + auto deps = makeBrandedDependencies(schema, nullptr); + slot->dependencies = deps.begin(); + slot->dependencyCount = deps.size(); + } + + return slot; +} + +kj::Array SchemaLoader::Impl::getAllLoaded() const { + size_t count = 0; + for (auto& schema: schemas) { + if (schema.second->lazyInitializer == nullptr) ++count; + } + + kj::Array result = kj::heapArray(count); + size_t i = 0; + for (auto& schema: schemas) { + if (schema.second->lazyInitializer == nullptr) { + result[i++] = Schema(&schema.second->defaultBrand); + } + } + return result; +} + +void SchemaLoader::Impl::requireStructSize(uint64_t id, uint dataWordCount, uint pointerCount) { + auto& slot = structSizeRequirements[id]; + slot.dataWordCount = kj::max(slot.dataWordCount, dataWordCount); + slot.pointerCount = kj::max(slot.pointerCount, pointerCount); + + auto iter = schemas.find(id); + if (iter != schemas.end()) { + applyStructSizeRequirement(iter->second, dataWordCount, pointerCount); + } +} + +kj::ArrayPtr SchemaLoader::Impl::makeUncheckedNode(schema::Node::Reader node) { + size_t size = node.totalSize().wordCount + 1; + kj::ArrayPtr result = arena.allocateArray(size); + memset(result.begin(), 0, size * sizeof(word)); + copyToUnchecked(node, result); + return result; +} + +kj::ArrayPtr SchemaLoader::Impl::makeUncheckedNodeEnforcingSizeRequirements( + schema::Node::Reader node) { + if (node.isStruct()) { + auto iter = structSizeRequirements.find(node.getId()); + if (iter != structSizeRequirements.end()) { + auto requirement = iter->second; + auto structNode = node.getStruct(); + if (structNode.getDataWordCount() < requirement.dataWordCount || + structNode.getPointerCount() < requirement.pointerCount) { + return rewriteStructNodeWithSizes(node, requirement.dataWordCount, + requirement.pointerCount); + } + } + } + + return makeUncheckedNode(node); +} + +kj::ArrayPtr SchemaLoader::Impl::rewriteStructNodeWithSizes( + schema::Node::Reader node, uint dataWordCount, uint pointerCount) { + MallocMessageBuilder builder; + builder.setRoot(node); + + auto root = builder.getRoot(); + auto newStruct = root.getStruct(); + newStruct.setDataWordCount(kj::max(newStruct.getDataWordCount(), dataWordCount)); + newStruct.setPointerCount(kj::max(newStruct.getPointerCount(), pointerCount)); + + return makeUncheckedNode(root); +} + +void SchemaLoader::Impl::applyStructSizeRequirement( + _::RawSchema* raw, uint dataWordCount, uint pointerCount) { + auto node = readMessageUnchecked(raw->encodedNode); + + auto structNode = node.getStruct(); + if (structNode.getDataWordCount() < dataWordCount || + structNode.getPointerCount() < pointerCount) { + // Sizes need to be increased. Must rewrite. + kj::ArrayPtr words = rewriteStructNodeWithSizes(node, dataWordCount, pointerCount); + + // We don't need to re-validate the node because we know this change could not possibly have + // invalidated it. Just remake the unchecked message. + raw->encodedNode = words.begin(); + raw->encodedSize = words.size(); + } +} + +void SchemaLoader::InitializerImpl::init(const _::RawSchema* schema) const { + KJ_IF_MAYBE(c, callback) { + c->load(loader, schema->id); + } + + if (schema->lazyInitializer != nullptr) { + // The callback declined to load a schema. We need to disable the initializer so that it + // doesn't get invoked again later, as we can no longer modify this schema once it is in use. + + // Lock the loader for read to make sure no one is concurrently loading a replacement for this + // schema node. + auto lock = loader.impl.lockShared(); + + // Get the mutable version of the schema. + _::RawSchema* mutableSchema = lock->get()->tryGet(schema->id).schema; + KJ_ASSERT(mutableSchema == schema, + "A schema not belonging to this loader used its initializer."); + + // Disable the initializer. +#if __GNUC__ + __atomic_store_n(&mutableSchema->lazyInitializer, nullptr, __ATOMIC_RELEASE); + __atomic_store_n(&mutableSchema->defaultBrand.lazyInitializer, nullptr, __ATOMIC_RELEASE); +#elif _MSC_VER + std::atomic_thread_fence(std::memory_order_release); + *static_cast<_::RawSchema::Initializer const* volatile*>( + &mutableSchema->lazyInitializer) = nullptr; + *static_cast<_::RawBrandedSchema::Initializer const* volatile*>( + &mutableSchema->defaultBrand.lazyInitializer) = nullptr; +#else +#error "Platform not supported" +#endif + } +} + +void SchemaLoader::BrandedInitializerImpl::init(const _::RawBrandedSchema* schema) const { + schema->generic->ensureInitialized(); + + auto lock = loader.impl.lockExclusive(); + + if (schema->lazyInitializer == nullptr) { + // Never mind, someone beat us to it. + return; + } + + // Get the mutable version. + auto iter = lock->get()->brands.find(SchemaBindingsPair { schema->generic, schema->scopes }); + KJ_ASSERT(iter != lock->get()->brands.end()); + + _::RawBrandedSchema* mutableSchema = iter->second; + KJ_ASSERT(mutableSchema == schema); + + // Construct its dependency map. + auto deps = lock->get()->makeBrandedDependencies(mutableSchema->generic, + kj::arrayPtr(mutableSchema->scopes, mutableSchema->scopeCount)); + mutableSchema->dependencies = deps.begin(); + mutableSchema->dependencyCount = deps.size(); + + // It's initialized now, so disable the initializer. +#if __GNUC__ + __atomic_store_n(&mutableSchema->lazyInitializer, nullptr, __ATOMIC_RELEASE); +#elif _MSC_VER + std::atomic_thread_fence(std::memory_order_release); + *static_cast<_::RawBrandedSchema::Initializer const* volatile*>( + &mutableSchema->lazyInitializer) = nullptr; +#else +#error "Platform not supported" +#endif +} + +// ======================================================================================= + +SchemaLoader::SchemaLoader(): impl(kj::heap(*this)) {} +SchemaLoader::SchemaLoader(const LazyLoadCallback& callback) + : impl(kj::heap(*this, callback)) {} +SchemaLoader::~SchemaLoader() noexcept(false) {} + +Schema SchemaLoader::get(uint64_t id, schema::Brand::Reader brand, Schema scope) const { + KJ_IF_MAYBE(result, tryGet(id, brand, scope)) { + return *result; + } else { + KJ_FAIL_REQUIRE("no schema node loaded for id", kj::hex(id)); + } +} + +kj::Maybe SchemaLoader::tryGet( + uint64_t id, schema::Brand::Reader brand, Schema scope) const { + auto getResult = impl.lockShared()->get()->tryGet(id); + if (getResult.schema == nullptr || getResult.schema->lazyInitializer != nullptr) { + // This schema couldn't be found or has yet to be lazily loaded. If we have a lazy loader + // callback, invoke it now to try to get it to load this schema. + KJ_IF_MAYBE(c, getResult.callback) { + c->load(*this, id); + } + getResult = impl.lockShared()->get()->tryGet(id); + } + if (getResult.schema != nullptr && getResult.schema->lazyInitializer == nullptr) { + if (brand.getScopes().size() > 0) { + auto brandedSchema = impl.lockExclusive()->get()->makeBranded( + getResult.schema, brand, kj::arrayPtr(scope.raw->scopes, scope.raw->scopeCount)); + brandedSchema->ensureInitialized(); + return Schema(brandedSchema); + } else { + return Schema(&getResult.schema->defaultBrand); + } + } else { + return nullptr; + } +} + +Schema SchemaLoader::getUnbound(uint64_t id) const { + auto schema = get(id); + return Schema(impl.lockExclusive()->get()->getUnbound(schema.raw->generic)); +} + +Type SchemaLoader::getType(schema::Type::Reader proto, Schema scope) const { + switch (proto.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + return proto.which(); + + case schema::Type::STRUCT: { + auto structType = proto.getStruct(); + return get(structType.getTypeId(), structType.getBrand(), scope).asStruct(); + } + + case schema::Type::ENUM: { + auto enumType = proto.getEnum(); + return get(enumType.getTypeId(), enumType.getBrand(), scope).asEnum(); + } + + case schema::Type::INTERFACE: { + auto interfaceType = proto.getInterface(); + return get(interfaceType.getTypeId(), interfaceType.getBrand(), scope) + .asInterface(); + } + + case schema::Type::LIST: + return ListSchema::of(getType(proto.getList().getElementType(), scope)); + + case schema::Type::ANY_POINTER: { + auto anyPointer = proto.getAnyPointer(); + switch (anyPointer.which()) { + case schema::Type::AnyPointer::UNCONSTRAINED: + return schema::Type::ANY_POINTER; + case schema::Type::AnyPointer::PARAMETER: { + auto param = anyPointer.getParameter(); + return scope.getBrandBinding(param.getScopeId(), param.getParameterIndex()); + } + case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: + // We don't support binding implicit method params here. + return schema::Type::ANY_POINTER; + } + + KJ_UNREACHABLE; + } + } + + KJ_UNREACHABLE; +} + +Schema SchemaLoader::load(const schema::Node::Reader& reader) { + return Schema(&impl.lockExclusive()->get()->load(reader, false)->defaultBrand); +} + +Schema SchemaLoader::loadOnce(const schema::Node::Reader& reader) const { + auto locked = impl.lockExclusive(); + auto getResult = locked->get()->tryGet(reader.getId()); + if (getResult.schema == nullptr || getResult.schema->lazyInitializer != nullptr) { + // Doesn't exist yet, or the existing schema is a placeholder and therefore has not yet been + // seen publicly. Go ahead and load the incoming reader. + return Schema(&locked->get()->load(reader, false)->defaultBrand); + } else { + return Schema(&getResult.schema->defaultBrand); + } +} + +kj::Array SchemaLoader::getAllLoaded() const { + return impl.lockShared()->get()->getAllLoaded(); +} + +void SchemaLoader::loadNative(const _::RawSchema* nativeSchema) { + impl.lockExclusive()->get()->loadNative(nativeSchema); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-loader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-loader.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,173 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_LOADER_H_ +#define CAPNP_SCHEMA_LOADER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema.h" +#include +#include + +namespace capnp { + +class SchemaLoader { + // Class which can be used to construct Schema objects from schema::Nodes as defined in + // schema.capnp. + // + // It is a bad idea to use this class on untrusted input with exceptions disabled -- you may + // be exposing yourself to denial-of-service attacks, as attackers can easily construct schemas + // that are subtly inconsistent in a way that causes exceptions to be thrown either by + // SchemaLoader or by the dynamic API when the schemas are subsequently used. If you enable and + // properly catch exceptions, you should be OK -- assuming no bugs in the Cap'n Proto + // implementation, of course. + +public: + class LazyLoadCallback { + public: + virtual void load(const SchemaLoader& loader, uint64_t id) const = 0; + // Request that the schema node with the given ID be loaded into the given SchemaLoader. If + // the callback is able to find a schema for this ID, it should invoke `loadOnce()` on + // `loader` to load it. If no such node exists, it should simply do nothing and return. + // + // The callback is allowed to load schema nodes other than the one requested, e.g. because it + // expects they will be needed soon. + // + // If the `SchemaLoader` is used from multiple threads, the callback must be thread-safe. + // In particular, it's possible for multiple threads to invoke `load()` with the same ID. + // If the callback performs a large amount of work to look up IDs, it should be sure to + // de-dup these requests. + }; + + SchemaLoader(); + + SchemaLoader(const LazyLoadCallback& callback); + // Construct a SchemaLoader which will invoke the given callback when a schema node is requested + // that isn't already loaded. + + ~SchemaLoader() noexcept(false); + KJ_DISALLOW_COPY(SchemaLoader); + + Schema get(uint64_t id, schema::Brand::Reader brand = schema::Brand::Reader(), + Schema scope = Schema()) const; + // Gets the schema for the given ID, throwing an exception if it isn't present. + // + // The returned schema may be invalidated if load() is called with a new schema for the same ID. + // In general, you should not call load() while a schema from this loader is in-use. + // + // `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives + // parameter bindings for the target type's brand parameters that were specified at the reference + // site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains + // parameter references or indicates that some parameters will be inherited, these will be + // interpreted within / inherited from `scope`. + + kj::Maybe tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(), + Schema scope = Schema()) const; + // Like get() but doesn't throw. + + Schema getUnbound(uint64_t id) const; + // Gets a special version of the schema in which all brand parameters are "unbound". This means + // that if you look up a type via the Schema API, and it resolves to a brand parameter, the + // returned Type's getBrandParameter() method will return info about that parameter. Otherwise, + // normally, all brand parameters that aren't otherwise bound are assumed to simply be + // "AnyPointer". + + Type getType(schema::Type::Reader type, Schema scope = Schema()) const; + // Convenience method which interprets a schema::Type to produce a Type object. Implemented in + // terms of get(). + + Schema load(const schema::Node::Reader& reader); + // Loads the given schema node. Validates the node and throws an exception if invalid. This + // makes a copy of the schema, so the object passed in can be destroyed after this returns. + // + // If the node has any dependencies which are not already loaded, they will be initialized as + // stubs -- empty schemas of whichever kind is expected. + // + // If another schema for the given reader has already been seen, the loader will inspect both + // schemas to determine which one is newer, and use that that one. If the two versions are + // found to be incompatible, an exception is thrown. If the two versions differ but are + // compatible and the loader cannot determine which is newer (e.g., the only changes are renames), + // the existing schema will be preferred. Note that in any case, the loader will end up keeping + // around copies of both schemas, so you shouldn't repeatedly reload schemas into the same loader. + // + // The following properties of the schema node are validated: + // - Struct size and preferred list encoding are valid and consistent. + // - Struct members are fields or unions. + // - Union members are fields. + // - Field offsets are in-bounds. + // - Ordinals and codeOrders are sequential starting from zero. + // - Values are of the right union case to match their types. + // + // You should assume anything not listed above is NOT validated. In particular, things that are + // not validated now, but could be in the future, include but are not limited to: + // - Names. + // - Annotation values. (This is hard because the annotation declaration is not always + // available.) + // - Content of default/constant values of pointer type. (Validating these would require knowing + // their schema, but even if the schemas are available at validation time, they could be + // updated by a subsequent load(), invalidating existing values. Instead, these values are + // validated at the time they are used, as usual for Cap'n Proto objects.) + // + // Also note that unknown types are not considered invalid. Instead, the dynamic API returns + // a DynamicValue with type UNKNOWN for these. + + Schema loadOnce(const schema::Node::Reader& reader) const; + // Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast, + // `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe + // to call even while concurrently using schemas from this loader. It should be considered an + // error to call `loadOnce()` with two non-identical schemas that share the same ID, although + // this error may or may not actually be detected by the implementation. + + template + void loadCompiledTypeAndDependencies(); + // Load the schema for the given compiled-in type and all of its dependencies. + // + // If you want to be able to cast a DynamicValue built from this SchemaLoader to the compiled-in + // type using as(), you must call this method before constructing the DynamicValue. Otherwise, + // as() will throw an exception complaining about type mismatch. + + kj::Array getAllLoaded() const; + // Get a complete list of all loaded schema nodes. It is particularly useful to call this after + // loadCompiledTypeAndDependencies() in order to get a flat list of all of T's transitive + // dependencies. + +private: + class Validator; + class CompatibilityChecker; + class Impl; + class InitializerImpl; + class BrandedInitializerImpl; + kj::MutexGuarded> impl; + + void loadNative(const _::RawSchema* nativeSchema); +}; + +template +inline void SchemaLoader::loadCompiledTypeAndDependencies() { + loadNative(&_::rawSchema()); +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_LOADER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-parser-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-parser-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,185 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema-parser.h" +#include +#include "test-util.h" +#include +#include + +namespace capnp { +namespace { + +class FakeFileReader final: public SchemaFile::FileReader { +public: + void add(kj::StringPtr name, kj::StringPtr content) { + files[name] = content; + } + + bool exists(kj::StringPtr path) const override { + return files.count(path) > 0; + } + + kj::Array read(kj::StringPtr path) const override { + auto iter = files.find(path); + KJ_ASSERT(iter != files.end(), "FakeFileReader has no such file.", path); + auto result = kj::heapArray(iter->second.size()); + memcpy(result.begin(), iter->second.begin(), iter->second.size()); + return kj::mv(result); + } + +private: + std::map files; +}; + +static uint64_t getFieldTypeFileId(StructSchema::Field field) { + return field.getContainingStruct() + .getDependency(field.getProto().getSlot().getType().getStruct().getTypeId()) + .getProto().getScopeId(); +} + +TEST(SchemaParser, Basic) { + SchemaParser parser; + FakeFileReader reader; + + reader.add("src/foo/bar.capnp", + "@0x8123456789abcdef;\n" + "struct Bar {\n" + " baz @0: import \"baz.capnp\".Baz;\n" + " corge @1: import \"../qux/corge.capnp\".Corge;\n" + " grault @2: import \"/grault.capnp\".Grault;\n" + " garply @3: import \"/garply.capnp\".Garply;\n" + "}\n"); + reader.add("src/foo/baz.capnp", + "@0x823456789abcdef1;\n" + "struct Baz {}\n"); + reader.add("src/qux/corge.capnp", + "@0x83456789abcdef12;\n" + "struct Corge {}\n"); + reader.add("/usr/include/grault.capnp", + "@0x8456789abcdef123;\n" + "struct Grault {}\n"); + reader.add("/opt/include/grault.capnp", + "@0x8000000000000001;\n" + "struct WrongGrault {}\n"); + reader.add("/usr/local/include/garply.capnp", + "@0x856789abcdef1234;\n" + "struct Garply {}\n"); + + kj::StringPtr importPath[] = { + "/usr/include", "/usr/local/include", "/opt/include" + }; + + ParsedSchema barSchema = parser.parseFile(SchemaFile::newDiskFile( + "foo2/bar2.capnp", "src/foo/bar.capnp", importPath, reader)); + + auto barProto = barSchema.getProto(); + EXPECT_EQ(0x8123456789abcdefull, barProto.getId()); + EXPECT_EQ("foo2/bar2.capnp", barProto.getDisplayName()); + + auto barStruct = barSchema.getNested("Bar"); + auto barFields = barStruct.asStruct().getFields(); + ASSERT_EQ(4u, barFields.size()); + EXPECT_EQ("baz", barFields[0].getProto().getName()); + EXPECT_EQ(0x823456789abcdef1ull, getFieldTypeFileId(barFields[0])); + EXPECT_EQ("corge", barFields[1].getProto().getName()); + EXPECT_EQ(0x83456789abcdef12ull, getFieldTypeFileId(barFields[1])); + EXPECT_EQ("grault", barFields[2].getProto().getName()); + EXPECT_EQ(0x8456789abcdef123ull, getFieldTypeFileId(barFields[2])); + EXPECT_EQ("garply", barFields[3].getProto().getName()); + EXPECT_EQ(0x856789abcdef1234ull, getFieldTypeFileId(barFields[3])); + + auto bazSchema = parser.parseFile(SchemaFile::newDiskFile( + "not/used/because/already/loaded", + "src/foo/baz.capnp", importPath, reader)); + EXPECT_EQ(0x823456789abcdef1ull, bazSchema.getProto().getId()); + EXPECT_EQ("foo2/baz.capnp", bazSchema.getProto().getDisplayName()); + auto bazStruct = bazSchema.getNested("Baz").asStruct(); + EXPECT_EQ(bazStruct, barStruct.getDependency(bazStruct.getProto().getId())); + + auto corgeSchema = parser.parseFile(SchemaFile::newDiskFile( + "not/used/because/already/loaded", + "src/qux/corge.capnp", importPath, reader)); + EXPECT_EQ(0x83456789abcdef12ull, corgeSchema.getProto().getId()); + EXPECT_EQ("qux/corge.capnp", corgeSchema.getProto().getDisplayName()); + auto corgeStruct = corgeSchema.getNested("Corge").asStruct(); + EXPECT_EQ(corgeStruct, barStruct.getDependency(corgeStruct.getProto().getId())); + + auto graultSchema = parser.parseFile(SchemaFile::newDiskFile( + "not/used/because/already/loaded", + "/usr/include/grault.capnp", importPath, reader)); + EXPECT_EQ(0x8456789abcdef123ull, graultSchema.getProto().getId()); + EXPECT_EQ("grault.capnp", graultSchema.getProto().getDisplayName()); + auto graultStruct = graultSchema.getNested("Grault").asStruct(); + EXPECT_EQ(graultStruct, barStruct.getDependency(graultStruct.getProto().getId())); + + // Try importing the other grault.capnp directly. It'll get the display name we specify since + // it wasn't imported before. + auto wrongGraultSchema = parser.parseFile(SchemaFile::newDiskFile( + "weird/display/name.capnp", + "/opt/include/grault.capnp", importPath, reader)); + EXPECT_EQ(0x8000000000000001ull, wrongGraultSchema.getProto().getId()); + EXPECT_EQ("weird/display/name.capnp", wrongGraultSchema.getProto().getDisplayName()); +} + +TEST(SchemaParser, Constants) { + // This is actually a test of the full dynamic API stack for constants, because the schemas for + // constants are not actually accessible from the generated code API, so the only way to ever + // get a ConstSchema is by parsing it. + + SchemaParser parser; + FakeFileReader reader; + + reader.add("const.capnp", + "@0x8123456789abcdef;\n" + "const uint32Const :UInt32 = 1234;\n" + "const listConst :List(Float32) = [1.25, 2.5, 3e4];\n" + "const structConst :Foo = (bar = 123, baz = \"qux\");\n" + "struct Foo {\n" + " bar @0 :Int16;\n" + " baz @1 :Text;\n" + "}\n" + "const genericConst :TestGeneric(Text) = (value = \"text\");\n" + "struct TestGeneric(T) {\n" + " value @0 :T;\n" + "}\n"); + + ParsedSchema fileSchema = parser.parseFile(SchemaFile::newDiskFile( + "const.capnp", "const.capnp", nullptr, reader)); + + EXPECT_EQ(1234, fileSchema.getNested("uint32Const").asConst().as()); + + auto list = fileSchema.getNested("listConst").asConst().as(); + ASSERT_EQ(3u, list.size()); + EXPECT_EQ(1.25, list[0].as()); + EXPECT_EQ(2.5, list[1].as()); + EXPECT_EQ(3e4f, list[2].as()); + + auto structConst = fileSchema.getNested("structConst").asConst().as(); + EXPECT_EQ(123, structConst.get("bar").as()); + EXPECT_EQ("qux", structConst.get("baz").as()); + + auto genericConst = fileSchema.getNested("genericConst").asConst().as(); + EXPECT_EQ("text", genericConst.get("value").as()); +} + +} // namespace +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-parser.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-parser.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,492 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema-parser.h" +#include "message.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#else +#include +#endif + +namespace capnp { + +namespace { + +template +size_t findLargestElementBefore(const kj::Vector& vec, const T& key) { + KJ_REQUIRE(vec.size() > 0 && vec[0] <= key); + + size_t lower = 0; + size_t upper = vec.size(); + + while (upper - lower > 1) { + size_t mid = (lower + upper) / 2; + if (vec[mid] > key) { + upper = mid; + } else { + lower = mid; + } + } + + return lower; +} + +} // namespace + +// ======================================================================================= + +class SchemaParser::ModuleImpl final: public compiler::Module { +public: + ModuleImpl(const SchemaParser& parser, kj::Own&& file) + : parser(parser), file(kj::mv(file)) {} + + kj::StringPtr getSourceName() override { + return file->getDisplayName(); + } + + Orphan loadContent(Orphanage orphanage) override { + kj::Array content = file->readContent(); + + lineBreaks.get([&](kj::SpaceFor>& space) { + auto vec = space.construct(content.size() / 40); + vec->add(0); + for (const char* pos = content.begin(); pos < content.end(); ++pos) { + if (*pos == '\n') { + vec->add(pos + 1 - content.begin()); + } + } + return vec; + }); + + MallocMessageBuilder lexedBuilder; + auto statements = lexedBuilder.initRoot(); + compiler::lex(content, statements, *this); + + auto parsed = orphanage.newOrphan(); + compiler::parseFile(statements.getStatements(), parsed.get(), *this); + return parsed; + } + + kj::Maybe importRelative(kj::StringPtr importPath) override { + KJ_IF_MAYBE(importedFile, file->import(importPath)) { + return parser.getModuleImpl(kj::mv(*importedFile)); + } else { + return nullptr; + } + } + + kj::Maybe> embedRelative(kj::StringPtr embedPath) override { + KJ_IF_MAYBE(importedFile, file->import(embedPath)) { + return importedFile->get()->readContent().releaseAsBytes(); + } else { + return nullptr; + } + } + + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + auto& lines = lineBreaks.get( + [](kj::SpaceFor>& space) { + KJ_FAIL_REQUIRE("Can't report errors until loadContent() is called."); + return space.construct(); + }); + + // TODO(someday): This counts tabs as single characters. Do we care? + uint startLine = findLargestElementBefore(lines, startByte); + uint startCol = startByte - lines[startLine]; + uint endLine = findLargestElementBefore(lines, endByte); + uint endCol = endByte - lines[endLine]; + + file->reportError( + SchemaFile::SourcePos { startByte, startLine, startCol }, + SchemaFile::SourcePos { endByte, endLine, endCol }, + message); + + // We intentionally only set hadErrors true if reportError() didn't throw. + parser.hadErrors = true; + } + + bool hadErrors() override { + return parser.hadErrors; + } + +private: + const SchemaParser& parser; + kj::Own file; + + kj::Lazy> lineBreaks; + // Byte offsets of the first byte in each source line. The first element is always zero. + // Initialized the first time the module is loaded. +}; + +// ======================================================================================= + +namespace { + +struct SchemaFileHash { + inline bool operator()(const SchemaFile* f) const { + return f->hashCode(); + } +}; + +struct SchemaFileEq { + inline bool operator()(const SchemaFile* a, const SchemaFile* b) const { + return *a == *b; + } +}; + +} // namespace + +struct SchemaParser::Impl { + typedef std::unordered_map< + const SchemaFile*, kj::Own, SchemaFileHash, SchemaFileEq> FileMap; + kj::MutexGuarded fileMap; + compiler::Compiler compiler; +}; + +SchemaParser::SchemaParser(): impl(kj::heap()) {} +SchemaParser::~SchemaParser() noexcept(false) {} + +ParsedSchema SchemaParser::parseDiskFile( + kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath) const { + return parseFile(SchemaFile::newDiskFile(displayName, diskPath, importPath)); +} + +ParsedSchema SchemaParser::parseFile(kj::Own&& file) const { + KJ_DEFER(impl->compiler.clearWorkspace()); + uint64_t id = impl->compiler.add(getModuleImpl(kj::mv(file))); + impl->compiler.eagerlyCompile(id, + compiler::Compiler::NODE | compiler::Compiler::CHILDREN | + compiler::Compiler::DEPENDENCIES | compiler::Compiler::DEPENDENCY_DEPENDENCIES); + return ParsedSchema(impl->compiler.getLoader().get(id), *this); +} + +SchemaParser::ModuleImpl& SchemaParser::getModuleImpl(kj::Own&& file) const { + auto lock = impl->fileMap.lockExclusive(); + + auto insertResult = lock->insert(std::make_pair(file.get(), kj::Own())); + if (insertResult.second) { + // This is a newly-inserted entry. Construct the ModuleImpl. + insertResult.first->second = kj::heap(*this, kj::mv(file)); + } + return *insertResult.first->second; +} + +SchemaLoader& SchemaParser::getLoader() { + return impl->compiler.getLoader(); +} + +kj::Maybe ParsedSchema::findNested(kj::StringPtr name) const { + return parser->impl->compiler.lookup(getProto().getId(), name).map( + [this](uint64_t childId) { + return ParsedSchema(parser->impl->compiler.getLoader().get(childId), *parser); + }); +} + +ParsedSchema ParsedSchema::getNested(kj::StringPtr nestedName) const { + KJ_IF_MAYBE(nested, findNested(nestedName)) { + return *nested; + } else { + KJ_FAIL_REQUIRE("no such nested declaration", getProto().getDisplayName(), nestedName); + } +} + +// ======================================================================================= + +namespace { + +class MmapDisposer: public kj::ArrayDisposer { +protected: + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const { +#if _WIN32 + KJ_ASSERT(UnmapViewOfFile(firstElement)); +#else + munmap(firstElement, elementSize * elementCount); +#endif + } +}; + +KJ_CONSTEXPR(static const) MmapDisposer mmapDisposer = MmapDisposer(); + +static char* canonicalizePath(char* path) { + // Taken from some old C code of mine. + + // Preconditions: + // - path has already been determined to be relative, perhaps because the pointer actually points + // into the middle of some larger path string, in which case it must point to the character + // immediately after a '/'. + + // Invariants: + // - src points to the beginning of a path component. + // - dst points to the location where the path component should end up, if it is not special. + // - src == path or src[-1] == '/'. + // - dst == path or dst[-1] == '/'. + + char* src = path; + char* dst = path; + char* locked = dst; // dst cannot backtrack past this + char* partEnd; + bool hasMore; + + for (;;) { + while (*src == '/') { + // Skip duplicate slash. + ++src; + } + + partEnd = strchr(src, '/'); + hasMore = partEnd != NULL; + if (hasMore) { + *partEnd = '\0'; + } else { + partEnd = src + strlen(src); + } + + if (strcmp(src, ".") == 0) { + // Skip it. + } else if (strcmp(src, "..") == 0) { + if (dst > locked) { + // Backtrack over last path component. + --dst; + while (dst > locked && dst[-1] != '/') --dst; + } else { + locked += 3; + goto copy; + } + } else { + // Copy if needed. + copy: + if (dst < src) { + memmove(dst, src, partEnd - src); + dst += partEnd - src; + } else { + dst = partEnd; + } + *dst++ = '/'; + } + + if (hasMore) { + src = partEnd + 1; + } else { + // Oops, we have to remove the trailing '/'. + if (dst == path) { + // Oops, there is no trailing '/'. We have to return ".". + strcpy(path, "."); + return path + 1; + } else { + // Remove the trailing '/'. Note that this means that opening the file will work even + // if it is not a directory, where normally it should fail on non-directories when a + // trailing '/' is present. If this is a problem, we need to add some sort of special + // handling for this case where we stat() it separately to check if it is a directory, + // because Ekam findInput will not accept a trailing '/'. + --dst; + *dst = '\0'; + return dst; + } + } + } +} + +kj::String canonicalizePath(kj::StringPtr path) { + KJ_STACK_ARRAY(char, result, path.size() + 1, 128, 512); + strcpy(result.begin(), path.begin()); + + char* start = path.startsWith("/") ? result.begin() + 1 : result.begin(); + char* end = canonicalizePath(start); + return kj::heapString(result.slice(0, end - result.begin())); +} + +kj::String relativePath(kj::StringPtr base, kj::StringPtr add) { + if (add.size() > 0 && add[0] == '/') { + return kj::heapString(add); + } + + const char* pos = base.end(); + while (pos > base.begin() && pos[-1] != '/') { + --pos; + } + + return kj::str(base.slice(0, pos - base.begin()), add); +} + +kj::String joinPath(kj::StringPtr base, kj::StringPtr add) { + KJ_REQUIRE(!add.startsWith("/")); + + return kj::str(base, '/', add); +} + +} // namespace + +const SchemaFile::DiskFileReader SchemaFile::DiskFileReader::instance = + SchemaFile::DiskFileReader(); + +bool SchemaFile::DiskFileReader::exists(kj::StringPtr path) const { + return access(path.cStr(), F_OK) == 0; +} + +kj::Array SchemaFile::DiskFileReader::read(kj::StringPtr path) const { + int fd; + // We already established that the file exists, so this should not fail. + KJ_SYSCALL(fd = open(path.cStr(), O_RDONLY), path); + kj::AutoCloseFd closer(fd); + + struct stat stats; + KJ_SYSCALL(fstat(fd, &stats)); + + if (S_ISREG(stats.st_mode)) { + if (stats.st_size == 0) { + // mmap()ing zero bytes will fail. + return nullptr; + } + + // Regular file. Just mmap() it. +#if _WIN32 + HANDLE handle = reinterpret_cast(_get_osfhandle(fd)); + KJ_ASSERT(handle != INVALID_HANDLE_VALUE); + HANDLE mappingHandle = CreateFileMapping( + handle, NULL, PAGE_READONLY, 0, stats.st_size, NULL); + KJ_ASSERT(mappingHandle != INVALID_HANDLE_VALUE); + KJ_DEFER(KJ_ASSERT(CloseHandle(mappingHandle))); + const void* mapping = MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, stats.st_size); +#else // _WIN32 + const void* mapping = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) { + KJ_FAIL_SYSCALL("mmap", errno, path); + } +#endif // !_WIN32 + + return kj::Array( + reinterpret_cast(mapping), stats.st_size, mmapDisposer); + } else { + // This could be a stream of some sort, like a pipe. Fall back to read(). + // TODO(cleanup): This does a lot of copies. Not sure I care. + kj::Vector data(8192); + + char buffer[4096]; + for (;;) { + kj::miniposix::ssize_t n; + KJ_SYSCALL(n = ::read(fd, buffer, sizeof(buffer))); + if (n == 0) break; + data.addAll(buffer, buffer + n); + } + + return data.releaseAsArray(); + } +} + +// ------------------------------------------------------------------- + +class SchemaFile::DiskSchemaFile final: public SchemaFile { +public: + DiskSchemaFile(const FileReader& fileReader, kj::String displayName, + kj::String diskPath, kj::ArrayPtr importPath) + : fileReader(fileReader), + displayName(kj::mv(displayName)), + diskPath(kj::mv(diskPath)), + importPath(importPath) {} + + kj::StringPtr getDisplayName() const override { + return displayName; + } + + kj::Array readContent() const override { + return fileReader.read(diskPath); + } + + kj::Maybe> import(kj::StringPtr path) const override { + if (path.startsWith("/")) { + for (auto candidate: importPath) { + kj::String newDiskPath = canonicalizePath(joinPath(candidate, path.slice(1))); + if (fileReader.exists(newDiskPath)) { + return kj::implicitCast>(kj::heap( + fileReader, canonicalizePath(path.slice(1)), + kj::mv(newDiskPath), importPath)); + } + } + return nullptr; + } else { + kj::String newDiskPath = canonicalizePath(relativePath(diskPath, path)); + if (fileReader.exists(newDiskPath)) { + return kj::implicitCast>(kj::heap( + fileReader, canonicalizePath(relativePath(displayName, path)), + kj::mv(newDiskPath), importPath)); + } else { + return nullptr; + } + } + } + + bool operator==(const SchemaFile& other) const override { + return diskPath == kj::downcast(other).diskPath; + } + bool operator!=(const SchemaFile& other) const override { + return diskPath != kj::downcast(other).diskPath; + } + size_t hashCode() const override { + // djb hash with xor + // TODO(someday): Add hashing library to KJ. + size_t result = 5381; + for (char c: diskPath) { + result = (result * 33) ^ c; + } + return result; + } + + void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const override { + kj::getExceptionCallback().onRecoverableException(kj::Exception( + kj::Exception::Type::FAILED, kj::heapString(diskPath), start.line, + kj::heapString(message))); + } + +private: + const FileReader& fileReader; + kj::String displayName; + kj::String diskPath; + kj::ArrayPtr importPath; +}; + +kj::Own SchemaFile::newDiskFile( + kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath, + const FileReader& fileReader) { + return kj::heap(fileReader, canonicalizePath(displayName), + canonicalizePath(diskPath), importPath); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-parser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-parser.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,207 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_PARSER_H_ +#define CAPNP_SCHEMA_PARSER_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "schema-loader.h" +#include + +namespace capnp { + +class ParsedSchema; +class SchemaFile; + +class SchemaParser { + // Parses `.capnp` files to produce `Schema` objects. + // + // This class is thread-safe, hence all its methods are const. + +public: + SchemaParser(); + ~SchemaParser() noexcept(false); + + ParsedSchema parseDiskFile(kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath) const; + // Parse a file located on disk. Throws an exception if the file dosen't exist. + // + // Parameters: + // * `displayName`: The name that will appear in the file's schema node. (If the file has + // already been parsed, this will be ignored and the display name from the first time it was + // parsed will be kept.) + // * `diskPath`: The path to the file on disk. + // * `importPath`: Directories to search when resolving absolute imports within this file + // (imports that start with a `/`). Must remain valid until the SchemaParser is destroyed. + // (If the file has already been parsed, this will be ignored and the import path from the + // first time it was parsed will be kept.) + // + // This method is a shortcut, equivalent to: + // parser.parseFile(SchemaFile::newDiskFile(displayName, diskPath, importPath))`; + // + // This method throws an exception if any errors are encountered in the file or in anything the + // file depends on. Note that merely importing another file does not count as a dependency on + // anything in the imported file -- only the imported types which are actually used are + // "dependencies". + + ParsedSchema parseFile(kj::Own&& file) const; + // Advanced interface for parsing a file that may or may not be located in any global namespace. + // Most users will prefer `parseDiskFile()`. + // + // If the file has already been parsed (that is, a SchemaFile that compares equal to this one + // was parsed previously), the existing schema will be returned again. + // + // This method reports errors by calling SchemaFile::reportError() on the file where the error + // is located. If that call does not throw an exception, `parseFile()` may in fact return + // normally. In this case, the result is a best-effort attempt to compile the schema, but it + // may be invalid or corrupt, and using it for anything may cause exceptions to be thrown. + + template + inline void loadCompiledTypeAndDependencies() { + // See SchemaLoader::loadCompiledTypeAndDependencies(). + getLoader().loadCompiledTypeAndDependencies(); + } + +private: + struct Impl; + class ModuleImpl; + kj::Own impl; + mutable bool hadErrors = false; + + ModuleImpl& getModuleImpl(kj::Own&& file) const; + SchemaLoader& getLoader(); + + friend class ParsedSchema; +}; + +class ParsedSchema: public Schema { + // ParsedSchema is an extension of Schema which also has the ability to look up nested nodes + // by name. See `SchemaParser`. + +public: + inline ParsedSchema(): parser(nullptr) {} + + kj::Maybe findNested(kj::StringPtr name) const; + // Gets the nested node with the given name, or returns null if there is no such nested + // declaration. + + ParsedSchema getNested(kj::StringPtr name) const; + // Gets the nested node with the given name, or throws an exception if there is no such nested + // declaration. + +private: + inline ParsedSchema(Schema inner, const SchemaParser& parser): Schema(inner), parser(&parser) {} + + const SchemaParser* parser; + friend class SchemaParser; +}; + +// ======================================================================================= +// Advanced API + +class SchemaFile { + // Abstract interface representing a schema file. You can implement this yourself in order to + // gain more control over how the compiler resolves imports and reads files. For the + // common case of files on disk or other global filesystem-like namespaces, use + // `SchemaFile::newDiskFile()`. + +public: + class FileReader { + public: + virtual bool exists(kj::StringPtr path) const = 0; + virtual kj::Array read(kj::StringPtr path) const = 0; + }; + + class DiskFileReader final: public FileReader { + // Implementation of FileReader that uses the local disk. Files are read using mmap() if + // possible. + + public: + static const DiskFileReader instance; + + bool exists(kj::StringPtr path) const override; + kj::Array read(kj::StringPtr path) const override; + }; + + static kj::Own newDiskFile( + kj::StringPtr displayName, kj::StringPtr diskPath, + kj::ArrayPtr importPath, + const FileReader& fileReader = DiskFileReader::instance); + // Construct a SchemaFile representing a file on disk (or located in the filesystem-like + // namespace represented by `fileReader`). + // + // Parameters: + // * `displayName`: The name that will appear in the file's schema node. + // * `diskPath`: The path to the file on disk. + // * `importPath`: Directories to search when resolving absolute imports within this file + // (imports that start with a `/`). The array content must remain valid as long as the + // SchemaFile exists (which is at least as long as the SchemaParser that parses it exists). + // * `fileReader`: Allows you to use a filesystem other than the actual local disk. Although, + // if you find yourself using this, it may make more sense for you to implement SchemaFile + // yourself. + // + // The SchemaFile compares equal to any other SchemaFile that has exactly the same disk path, + // after canonicalization. + // + // The SchemaFile will throw an exception if any errors are reported. + + // ----------------------------------------------------------------- + // For more control, you can implement this interface. + + virtual kj::StringPtr getDisplayName() const = 0; + // Get the file's name, as it should appear in the schema. + + virtual kj::Array readContent() const = 0; + // Read the file's entire content and return it as a byte array. + + virtual kj::Maybe> import(kj::StringPtr path) const = 0; + // Resolve an import, relative to this file. + // + // `path` is exactly what appears between quotes after the `import` keyword in the source code. + // It is entirely up to the `SchemaFile` to decide how to map this to another file. Typically, + // a leading '/' means that the file is an "absolute" path and is searched for in some list of + // schema file repositories. On the other hand, a path that doesn't start with '/' is relative + // to the importing file. + + virtual bool operator==(const SchemaFile& other) const = 0; + virtual bool operator!=(const SchemaFile& other) const = 0; + virtual size_t hashCode() const = 0; + // Compare two SchemaFiles to see if they refer to the same underlying file. This is an + // optimization used to avoid the need to re-parse a file to check its ID. + + struct SourcePos { + uint byte; + uint line; + uint column; + }; + virtual void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const = 0; + // Report that the file contains an error at the given interval. + +private: + class DiskSchemaFile; +}; + +} // namespace capnp + +#endif // CAPNP_SCHEMA_PARSER_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,373 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema.h" +#include +#include "test-util.h" + +// TODO(cleanup): Auto-generate stringification functions for union discriminants. +namespace capnp { +namespace schema { +inline kj::String KJ_STRINGIFY(Type::Which which) { + return kj::str(static_cast(which)); +} +} // namespace schema +} // namespace capnp + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Schema, Structs) { + StructSchema schema = Schema::from(); + + EXPECT_EQ(typeId(), schema.getProto().getId()); + + EXPECT_TRUE(schema.getDependency(typeId()) == Schema::from()); + EXPECT_TRUE(schema.getDependency(typeId()) != schema); + EXPECT_TRUE(schema.getDependency(typeId()) == Schema::from()); + EXPECT_TRUE(schema.getDependency(typeId()) == schema); + EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId())); + + EXPECT_TRUE(schema.asStruct() == schema); + EXPECT_NONFATAL_FAILURE(schema.asEnum()); + EXPECT_NONFATAL_FAILURE(schema.asInterface()); + + ASSERT_EQ(schema.getFields().size(), schema.getProto().getStruct().getFields().size()); + StructSchema::Field field = schema.getFields()[0]; + EXPECT_EQ("voidField", field.getProto().getName()); + EXPECT_TRUE(field.getContainingStruct() == schema); + + StructSchema::Field lookup = schema.getFieldByName("voidField"); + EXPECT_TRUE(lookup == field); + EXPECT_TRUE(lookup != schema.getFields()[1]); + EXPECT_FALSE(lookup.getProto().getSlot().getHadExplicitDefault()); + + EXPECT_FALSE(schema.getFieldByName("int32Field").getProto().getSlot().getHadExplicitDefault()); + + EXPECT_TRUE(Schema::from().getFieldByName("int32Field") + .getProto().getSlot().getHadExplicitDefault()); + + EXPECT_TRUE(schema.findFieldByName("noSuchField") == nullptr); + + EXPECT_TRUE(schema.findFieldByName("int32Field") != nullptr); + EXPECT_TRUE(schema.findFieldByName("float32List") != nullptr); + EXPECT_TRUE(schema.findFieldByName("dataList") != nullptr); + EXPECT_TRUE(schema.findFieldByName("textField") != nullptr); + EXPECT_TRUE(schema.findFieldByName("structField") != nullptr); +} + +TEST(Schema, FieldLookupOutOfOrder) { + // Tests that name lookup works correctly when the fields are defined out-of-order in the schema + // file. + auto schema = Schema::from().asStruct(); + + EXPECT_EQ("qux", schema.getFields()[0].getProto().getName()); + EXPECT_EQ("grault", schema.getFields()[1].getProto().getName()); + EXPECT_EQ("bar", schema.getFields()[2].getProto().getName()); + EXPECT_EQ("foo", schema.getFields()[3].getProto().getName()); + EXPECT_EQ("corge", schema.getFields()[4].getProto().getName()); + EXPECT_EQ("waldo", schema.getFields()[5].getProto().getName()); + EXPECT_EQ("quux", schema.getFields()[6].getProto().getName()); + EXPECT_EQ("garply", schema.getFields()[7].getProto().getName()); + EXPECT_EQ("baz", schema.getFields()[8].getProto().getName()); + + EXPECT_EQ(3, schema.getFieldByName("foo").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(2, schema.getFieldByName("bar").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(8, schema.getFieldByName("baz").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(0, schema.getFieldByName("qux").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(6, schema.getFieldByName("quux").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(4, schema.getFieldByName("corge").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(1, schema.getFieldByName("grault").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(7, schema.getFieldByName("garply").getProto().getOrdinal().getExplicit()); + EXPECT_EQ(5, schema.getFieldByName("waldo").getProto().getOrdinal().getExplicit()); +} + +TEST(Schema, Unions) { + auto schema = Schema::from().asStruct(); + + EXPECT_TRUE(schema.findFieldByName("bit0") != nullptr); + EXPECT_TRUE(schema.findFieldByName("u1f0s8") == nullptr); + + auto union1 = schema.getFieldByName("union1"); + auto union1g = schema.getDependency(union1.getProto().getGroup().getTypeId()).asStruct(); + EXPECT_EQ(schema, union1g.getDependency(union1g.getProto().getScopeId())); + EXPECT_TRUE(union1g.findFieldByName("bin0") == nullptr); + + auto u1f0s8 = union1g.getFieldByName("u1f0s8"); + EXPECT_EQ("u1f0s8", u1f0s8.getProto().getName()); + EXPECT_TRUE(u1f0s8.getContainingStruct() == union1g); + + EXPECT_TRUE(union1g.findFieldByName("u1f1s8") != nullptr); + EXPECT_TRUE(union1g.findFieldByName("u1f0s32") != nullptr); + EXPECT_TRUE(union1g.findFieldByName("u1f0sp") != nullptr); + EXPECT_TRUE(union1g.findFieldByName("u1f1s1") != nullptr); + + EXPECT_TRUE(union1g.findFieldByName("u0f0s1") == nullptr); + EXPECT_TRUE(union1g.findFieldByName("u2f0s8") == nullptr); + EXPECT_TRUE(union1g.findFieldByName("noSuchField") == nullptr); +} + +TEST(Schema, Enums) { + EnumSchema schema = Schema::from(); + + EXPECT_EQ(typeId(), schema.getProto().getId()); + + EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId())); + EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId())); + + EXPECT_NONFATAL_FAILURE(schema.asStruct()); + EXPECT_NONFATAL_FAILURE(schema.asInterface()); + EXPECT_TRUE(schema.asEnum() == schema); + + ASSERT_EQ(schema.getEnumerants().size(), + schema.getProto().getEnum().getEnumerants().size()); + EnumSchema::Enumerant enumerant = schema.getEnumerants()[0]; + EXPECT_EQ("foo", enumerant.getProto().getName()); + EXPECT_TRUE(enumerant.getContainingEnum() == schema); + + EnumSchema::Enumerant lookup = schema.getEnumerantByName("foo"); + EXPECT_TRUE(lookup == enumerant); + EXPECT_TRUE(lookup != schema.getEnumerants()[1]); + + EXPECT_TRUE(schema.findEnumerantByName("noSuchEnumerant") == nullptr); + + EXPECT_TRUE(schema.findEnumerantByName("bar") != nullptr); + EXPECT_TRUE(schema.findEnumerantByName("qux") != nullptr); + EXPECT_TRUE(schema.findEnumerantByName("corge") != nullptr); + EXPECT_TRUE(schema.findEnumerantByName("grault") != nullptr); +} + +// TODO(someday): Test interface schemas when interfaces are implemented. + +TEST(Schema, Lists) { + EXPECT_EQ(schema::Type::VOID, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::BOOL, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::INT8, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::INT16, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::INT32, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::INT64, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::UINT8, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::UINT16, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::UINT32, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::UINT64, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::FLOAT32, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::FLOAT64, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::TEXT, Schema::from>().whichElementType()); + EXPECT_EQ(schema::Type::DATA, Schema::from>().whichElementType()); + + EXPECT_NONFATAL_FAILURE(Schema::from>().getStructElementType()); + EXPECT_NONFATAL_FAILURE(Schema::from>().getEnumElementType()); + EXPECT_NONFATAL_FAILURE(Schema::from>().getInterfaceElementType()); + EXPECT_NONFATAL_FAILURE(Schema::from>().getListElementType()); + + { + ListSchema schema = Schema::from>(); + EXPECT_EQ(schema::Type::STRUCT, schema.whichElementType()); + EXPECT_TRUE(schema.getStructElementType() == Schema::from()); + EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + EXPECT_NONFATAL_FAILURE(schema.getListElementType()); + } + + { + ListSchema schema = Schema::from>(); + EXPECT_EQ(schema::Type::ENUM, schema.whichElementType()); + EXPECT_TRUE(schema.getEnumElementType() == Schema::from()); + EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + EXPECT_NONFATAL_FAILURE(schema.getListElementType()); + } + + // TODO(someday): Test interfaces. + + { + ListSchema schema = Schema::from>>(); + EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); + EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); + EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + + ListSchema inner = schema.getListElementType(); + EXPECT_EQ(schema::Type::INT32, inner.whichElementType()); + } + + { + ListSchema schema = Schema::from>>(); + EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); + EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); + EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + + ListSchema inner = schema.getListElementType(); + EXPECT_EQ(schema::Type::STRUCT, inner.whichElementType()); + EXPECT_TRUE(inner.getStructElementType() == Schema::from()); + } + + { + ListSchema schema = Schema::from>>(); + EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); + EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); + EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + + ListSchema inner = schema.getListElementType(); + EXPECT_EQ(schema::Type::ENUM, inner.whichElementType()); + EXPECT_TRUE(inner.getEnumElementType() == Schema::from()); + } + + { + auto context = Schema::from(); + auto type = context.getFieldByName("enumList").getProto().getSlot().getType(); + + ListSchema schema = ListSchema::of(type.getList().getElementType(), context); + EXPECT_EQ(schema::Type::ENUM, schema.whichElementType()); + EXPECT_TRUE(schema.getEnumElementType() == Schema::from()); + EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); + EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); + EXPECT_NONFATAL_FAILURE(schema.getListElementType()); + } +} + +TEST(Schema, UnnamedUnion) { + StructSchema schema = Schema::from(); + + EXPECT_TRUE(schema.findFieldByName("") == nullptr); + + EXPECT_TRUE(schema.findFieldByName("foo") != nullptr); + EXPECT_TRUE(schema.findFieldByName("bar") != nullptr); + EXPECT_TRUE(schema.findFieldByName("before") != nullptr); + EXPECT_TRUE(schema.findFieldByName("after") != nullptr); +} + +TEST(Schema, NullSchemas) { + EXPECT_EQ(0xff, (uint)Schema().getProto().which()); + EXPECT_TRUE(StructSchema().getProto().isStruct()); + EXPECT_TRUE(EnumSchema().getProto().isEnum()); + EXPECT_TRUE(InterfaceSchema().getProto().isInterface()); + EXPECT_TRUE(ConstSchema().getProto().isConst()); + + EXPECT_EQ("(null schema)", Schema().getProto().getDisplayName()); + EXPECT_EQ("(null struct schema)", StructSchema().getProto().getDisplayName()); + EXPECT_EQ("(null enum schema)", EnumSchema().getProto().getDisplayName()); + EXPECT_EQ("(null interface schema)", InterfaceSchema().getProto().getDisplayName()); + EXPECT_EQ("(null const schema)", ConstSchema().getProto().getDisplayName()); + + EXPECT_TRUE(Schema::from() == InterfaceSchema()); + EXPECT_EQ(InterfaceSchema().getProto().getId(), typeId()); +} + +TEST(Schema, Interfaces) { + InterfaceSchema schema = Schema::from(); + + EXPECT_EQ(typeId(), schema.getProto().getId()); + + EXPECT_TRUE(schema.getDependency(typeId()) == + Schema::from()); + EXPECT_TRUE(schema.getDependency(typeId()) != schema); + EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId())); + + EXPECT_TRUE(schema.asInterface() == schema); + EXPECT_NONFATAL_FAILURE(schema.asStruct()); + EXPECT_NONFATAL_FAILURE(schema.asEnum()); + + ASSERT_EQ(schema.getMethods().size(), schema.getProto().getInterface().getMethods().size()); + InterfaceSchema::Method method = schema.getMethods()[0]; + EXPECT_EQ("callFoo", method.getProto().getName()); + EXPECT_TRUE(method.getContainingInterface() == schema); + + InterfaceSchema::Method lookup = schema.getMethodByName("callFoo"); + EXPECT_TRUE(lookup == method); + EXPECT_TRUE(lookup != schema.getMethods()[1]); + + EXPECT_TRUE(Schema::from().getFieldByName("int32Field") + .getProto().getSlot().getHadExplicitDefault()); + + EXPECT_TRUE(schema.findMethodByName("noSuchMethod") == nullptr); + + EXPECT_TRUE(schema.findMethodByName("callFooWhenResolved") != nullptr); + EXPECT_TRUE(schema.findMethodByName("neverReturn") != nullptr); + EXPECT_TRUE(schema.findMethodByName("hold") != nullptr); + EXPECT_TRUE(schema.findMethodByName("callHeld") != nullptr); + EXPECT_TRUE(schema.findMethodByName("getHeld") != nullptr); + + auto params = schema.getDependency(schema.getMethodByName("methodWithDefaults") + .getProto().getParamStructType()).asStruct(); + EXPECT_FALSE(params.getFieldByName("a").getProto().getSlot().getHadExplicitDefault()); + EXPECT_TRUE(params.getFieldByName("b").getProto().getSlot().getHadExplicitDefault()); + EXPECT_TRUE(params.getFieldByName("c").getProto().getSlot().getHadExplicitDefault()); +} + +TEST(Schema, Generics) { + StructSchema allTypes = Schema::from(); + StructSchema tap = Schema::from(); + StructSchema schema = Schema::from(); + + StructSchema branded; + + { + StructSchema::Field basic = schema.getFieldByName("basic"); + branded = basic.getType().asStruct(); + + StructSchema::Field foo = branded.getFieldByName("foo"); + EXPECT_TRUE(foo.getType().asStruct() == allTypes); + EXPECT_TRUE(foo.getType().asStruct() != tap); + + StructSchema instance2 = branded.getFieldByName("rev").getType().asStruct(); + StructSchema::Field foo2 = instance2.getFieldByName("foo"); + EXPECT_TRUE(foo2.getType().asStruct() == tap); + EXPECT_TRUE(foo2.getType().asStruct() != allTypes); + } + + { + StructSchema inner2 = schema.getFieldByName("inner2").getType().asStruct(); + + StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); + Type boundFoo = bound.getFieldByName("foo").getType(); + EXPECT_FALSE(boundFoo.isAnyPointer()); + EXPECT_TRUE(boundFoo.asStruct() == allTypes); + + StructSchema unbound = inner2.getFieldByName("innerUnbound").getType().asStruct(); + Type unboundFoo = unbound.getFieldByName("foo").getType(); + EXPECT_TRUE(unboundFoo.isAnyPointer()); + } + + { + InterfaceSchema cap = schema.getFieldByName("genericCap").getType().asInterface(); + InterfaceSchema::Method method = cap.getMethodByName("call"); + + StructSchema inner2 = method.getParamType(); + StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); + Type boundFoo = bound.getFieldByName("foo").getType(); + EXPECT_FALSE(boundFoo.isAnyPointer()); + EXPECT_TRUE(boundFoo.asStruct() == allTypes); + EXPECT_TRUE(inner2.getFieldByName("baz").getType().isText()); + + StructSchema results = method.getResultType(); + EXPECT_TRUE(results.getFieldByName("qux").getType().isData()); + + EXPECT_TRUE(results.getFieldByName("gen").getType().asStruct() == branded); + } +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,942 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "schema.h" +#include "message.h" +#include + +namespace capnp { + +namespace _ { // private + +// Null schemas generated using the below schema file with: +// +// capnp eval -Isrc null-schemas.capnp node --flat | +// hexdump -v -e '8/1 "0x%02x, "' -e '1/8 "\n"'; echo +// +// I totally don't understand hexdump format strings and came up with this command based on trial +// and error. +// +// @0x879863d4b2cc4a1e; +// +// using Node = import "/capnp/schema.capnp".Node; +// +// const node :Node = ( +// id = 0x0000000000000000, +// displayName = "(null schema)"); +// +// const struct :Node = ( +// id = 0x0000000000000001, +// displayName = "(null struct schema)", +// struct = ( +// dataWordCount = 0, +// pointerCount = 0, +// preferredListEncoding = empty)); +// +// const enum :Node = ( +// id = 0x0000000000000002, +// displayName = "(null enum schema)", +// enum = ()); +// +// const interface :Node = ( +// id = 0x0000000000000003, +// displayName = "(null interface schema)", +// interface = ()); +// +// const const :Node = ( +// id = 0x0000000000000004, +// displayName = "(null const schema)", +// const = (type = (void = void), value = (void = void))); + +static const AlignedData<13> NULL_SCHEMA_BYTES = {{ + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, // union discriminant intentionally mangled + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, +}}; +const RawSchema NULL_SCHEMA = { + 0x0000000000000000, NULL_SCHEMA_BYTES.words, 13, + nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr, + { &NULL_SCHEMA, nullptr, nullptr, 0, 0, nullptr } +}; + +static const AlignedData<14> NULL_STRUCT_SCHEMA_BYTES = {{ + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00, +}}; +const RawSchema NULL_STRUCT_SCHEMA = { + 0x0000000000000001, NULL_STRUCT_SCHEMA_BYTES.words, 14, + nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr, + { &NULL_STRUCT_SCHEMA, nullptr, nullptr, 0, 0, nullptr } +}; + +static const AlignedData<14> NULL_ENUM_SCHEMA_BYTES = {{ + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x65, 0x6e, + 0x75, 0x6d, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}}; +const RawSchema NULL_ENUM_SCHEMA = { + 0x0000000000000002, NULL_ENUM_SCHEMA_BYTES.words, 14, + nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr, + { &NULL_ENUM_SCHEMA, nullptr, nullptr, 0, 0, nullptr } +}; + +static const AlignedData<14> NULL_INTERFACE_SCHEMA_BYTES = {{ + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x29, 0x00, +}}; +const RawSchema NULL_INTERFACE_SCHEMA = { + 0x0000000000000003, NULL_INTERFACE_SCHEMA_BYTES.words, 14, + nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr, + { &NULL_INTERFACE_SCHEMA, nullptr, nullptr, 0, 0, nullptr } +}; + +static const AlignedData<20> NULL_CONST_SCHEMA_BYTES = {{ + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}}; +const RawSchema NULL_CONST_SCHEMA = { + 0x0000000000000004, NULL_CONST_SCHEMA_BYTES.words, 20, + nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr, + { &NULL_CONST_SCHEMA, nullptr, nullptr, 0, 0, nullptr } +}; + +} // namespace _ (private) + +// ======================================================================================= + +schema::Node::Reader Schema::getProto() const { + return readMessageUnchecked(raw->generic->encodedNode); +} + +kj::ArrayPtr Schema::asUncheckedMessage() const { + return kj::arrayPtr(raw->generic->encodedNode, raw->generic->encodedSize); +} + +Schema Schema::getDependency(uint64_t id, uint location) const { + { + // Binary search dependency list. + uint lower = 0; + uint upper = raw->dependencyCount; + + while (lower < upper) { + uint mid = (lower + upper) / 2; + + auto candidate = raw->dependencies[mid]; + if (candidate.location == location) { + candidate.schema->ensureInitialized(); + return Schema(candidate.schema); + } else if (candidate.location < location) { + lower = mid + 1; + } else { + upper = mid; + } + } + } + + { + uint lower = 0; + uint upper = raw->generic->dependencyCount; + + while (lower < upper) { + uint mid = (lower + upper) / 2; + + const _::RawSchema* candidate = raw->generic->dependencies[mid]; + + uint64_t candidateId = candidate->id; + if (candidateId == id) { + candidate->ensureInitialized(); + return Schema(&candidate->defaultBrand); + } else if (candidateId < id) { + lower = mid + 1; + } else { + upper = mid; + } + } + } + + KJ_FAIL_REQUIRE("Requested ID not found in dependency table.", kj::hex(id)) { + return Schema(); + } +} + +Schema::BrandArgumentList Schema::getBrandArgumentsAtScope(uint64_t scopeId) const { + KJ_REQUIRE(getProto().getIsGeneric(), "Not a generic type.", getProto().getDisplayName()); + + for (auto scope: kj::range(raw->scopes, raw->scopes + raw->scopeCount)) { + if (scope->typeId == scopeId) { + // OK, this scope matches the scope we're looking for. + if (scope->isUnbound) { + return BrandArgumentList(scopeId, true); + } else { + return BrandArgumentList(scopeId, scope->bindingCount, scope->bindings); + } + } + } + + // This scope is not listed in the scopes list. + return BrandArgumentList(scopeId, raw->isUnbound()); +} + +StructSchema Schema::asStruct() const { + KJ_REQUIRE(getProto().isStruct(), "Tried to use non-struct schema as a struct.", + getProto().getDisplayName()) { + return StructSchema(); + } + return StructSchema(*this); +} + +EnumSchema Schema::asEnum() const { + KJ_REQUIRE(getProto().isEnum(), "Tried to use non-enum schema as an enum.", + getProto().getDisplayName()) { + return EnumSchema(); + } + return EnumSchema(*this); +} + +InterfaceSchema Schema::asInterface() const { + KJ_REQUIRE(getProto().isInterface(), "Tried to use non-interface schema as an interface.", + getProto().getDisplayName()) { + return InterfaceSchema(); + } + return InterfaceSchema(*this); +} + +ConstSchema Schema::asConst() const { + KJ_REQUIRE(getProto().isConst(), "Tried to use non-constant schema as a constant.", + getProto().getDisplayName()) { + return ConstSchema(); + } + return ConstSchema(*this); +} + +kj::StringPtr Schema::getShortDisplayName() const { + auto proto = getProto(); + return proto.getDisplayName().slice(proto.getDisplayNamePrefixLength()); +} + +void Schema::requireUsableAs(const _::RawSchema* expected) const { + KJ_REQUIRE(raw->generic == expected || + (expected != nullptr && raw->generic->canCastTo == expected), + "This schema is not compatible with the requested native type."); +} + +uint32_t Schema::getSchemaOffset(const schema::Value::Reader& value) const { + const word* ptr; + + switch (value.which()) { + case schema::Value::TEXT: + ptr = reinterpret_cast(value.getText().begin()); + break; + case schema::Value::DATA: + ptr = reinterpret_cast(value.getData().begin()); + break; + case schema::Value::STRUCT: + ptr = value.getStruct().getAs<_::UncheckedMessage>(); + break; + case schema::Value::LIST: + ptr = value.getList().getAs<_::UncheckedMessage>(); + break; + case schema::Value::ANY_POINTER: + ptr = value.getAnyPointer().getAs<_::UncheckedMessage>(); + break; + default: + KJ_FAIL_ASSERT("getDefaultValueSchemaOffset() can only be called on struct, list, " + "and any-pointer fields."); + } + + return ptr - raw->generic->encodedNode; +} + +Type Schema::getBrandBinding(uint64_t scopeId, uint index) const { + return getBrandArgumentsAtScope(scopeId)[index]; +} + +Type Schema::interpretType(schema::Type::Reader proto, uint location) const { + switch (proto.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + return proto.which(); + + case schema::Type::STRUCT: { + auto structType = proto.getStruct(); + return getDependency(structType.getTypeId(), location).asStruct(); + } + + case schema::Type::ENUM: { + auto enumType = proto.getEnum(); + return getDependency(enumType.getTypeId(), location).asEnum(); + } + + case schema::Type::INTERFACE: { + auto interfaceType = proto.getInterface(); + return getDependency(interfaceType.getTypeId(), location).asInterface(); + } + + case schema::Type::LIST: + return ListSchema::of(interpretType(proto.getList().getElementType(), location)); + + case schema::Type::ANY_POINTER: { + auto anyPointer = proto.getAnyPointer(); + switch (anyPointer.which()) { + case schema::Type::AnyPointer::UNCONSTRAINED: + return anyPointer.getUnconstrained().which(); + case schema::Type::AnyPointer::PARAMETER: { + auto param = anyPointer.getParameter(); + return getBrandBinding(param.getScopeId(), param.getParameterIndex()); + } + case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER: + return Type(Type::ImplicitParameter { + anyPointer.getImplicitMethodParameter().getParameterIndex() }); + } + + KJ_UNREACHABLE; + } + } + + KJ_UNREACHABLE; +} + +Type Schema::BrandArgumentList::operator[](uint index) const { + if (isUnbound) { + return Type::BrandParameter { scopeId, index }; + } + + if (index >= size_) { + // Binding index out-of-range. Treat as AnyPointer. This is important to allow new + // type parameters to be added to existing types without breaking dependent + // schemas. + return schema::Type::ANY_POINTER; + } + + auto& binding = bindings[index]; + Type result; + if (binding.which == (uint)schema::Type::ANY_POINTER) { + if (binding.scopeId != 0) { + result = Type::BrandParameter { binding.scopeId, binding.paramIndex }; + } else if (binding.isImplicitParameter) { + result = Type::ImplicitParameter { binding.paramIndex }; + } else { + result = static_cast(binding.paramIndex); + } + } else if (binding.schema == nullptr) { + // Builtin / primitive type. + result = static_cast(binding.which); + } else { + binding.schema->ensureInitialized(); + result = Type(static_cast(binding.which), binding.schema); + } + + return result.wrapInList(binding.listDepth); +} + +kj::StringPtr KJ_STRINGIFY(const Schema& schema) { + return schema.getProto().getDisplayName(); +} + +// ======================================================================================= + +namespace { + +template +auto findSchemaMemberByName(const _::RawSchema* raw, kj::StringPtr name, List&& list) + -> kj::Maybe { + uint lower = 0; + uint upper = raw->memberCount; + + while (lower < upper) { + uint mid = (lower + upper) / 2; + + uint16_t memberIndex = raw->membersByName[mid]; + + auto candidate = list[memberIndex]; + kj::StringPtr candidateName = candidate.getProto().getName(); + if (candidateName == name) { + return candidate; + } else if (candidateName < name) { + lower = mid + 1; + } else { + upper = mid; + } + } + + return nullptr; +} + +} // namespace + +StructSchema::FieldList StructSchema::getFields() const { + return FieldList(*this, getProto().getStruct().getFields()); +} + +StructSchema::FieldSubset StructSchema::getUnionFields() const { + auto proto = getProto().getStruct(); + return FieldSubset(*this, proto.getFields(), + raw->generic->membersByDiscriminant, proto.getDiscriminantCount()); +} + +StructSchema::FieldSubset StructSchema::getNonUnionFields() const { + auto proto = getProto().getStruct(); + auto fields = proto.getFields(); + auto offset = proto.getDiscriminantCount(); + auto size = fields.size() - offset; + return FieldSubset(*this, fields, raw->generic->membersByDiscriminant + offset, size); +} + +kj::Maybe StructSchema::findFieldByName(kj::StringPtr name) const { + return findSchemaMemberByName(raw->generic, name, getFields()); +} + +StructSchema::Field StructSchema::getFieldByName(kj::StringPtr name) const { + KJ_IF_MAYBE(member, findFieldByName(name)) { + return *member; + } else { + KJ_FAIL_REQUIRE("struct has no such member", name); + } +} + +kj::Maybe StructSchema::getFieldByDiscriminant(uint16_t discriminant) const { + auto unionFields = getUnionFields(); + + if (discriminant >= unionFields.size()) { + return nullptr; + } else { + return unionFields[discriminant]; + } +} + +Type StructSchema::Field::getType() const { + auto proto = getProto(); + uint location = _::RawBrandedSchema::makeDepLocation(_::RawBrandedSchema::DepKind::FIELD, index); + + switch (proto.which()) { + case schema::Field::SLOT: + return parent.interpretType(proto.getSlot().getType(), location); + + case schema::Field::GROUP: + return parent.getDependency(proto.getGroup().getTypeId(), location).asStruct(); + } + KJ_UNREACHABLE; +} + +uint32_t StructSchema::Field::getDefaultValueSchemaOffset() const { + return parent.getSchemaOffset(proto.getSlot().getDefaultValue()); +} + +kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field) { + return field.getProto().getName(); +} + +// ------------------------------------------------------------------- + +EnumSchema::EnumerantList EnumSchema::getEnumerants() const { + return EnumerantList(*this, getProto().getEnum().getEnumerants()); +} + +kj::Maybe EnumSchema::findEnumerantByName(kj::StringPtr name) const { + return findSchemaMemberByName(raw->generic, name, getEnumerants()); +} + +EnumSchema::Enumerant EnumSchema::getEnumerantByName(kj::StringPtr name) const { + KJ_IF_MAYBE(enumerant, findEnumerantByName(name)) { + return *enumerant; + } else { + KJ_FAIL_REQUIRE("enum has no such enumerant", name); + } +} + +// ------------------------------------------------------------------- + +InterfaceSchema::MethodList InterfaceSchema::getMethods() const { + return MethodList(*this, getProto().getInterface().getMethods()); +} + +kj::Maybe InterfaceSchema::findMethodByName(kj::StringPtr name) const { + uint counter = 0; + return findMethodByName(name, counter); +} + +static constexpr uint MAX_SUPERCLASSES = 64; + +kj::Maybe InterfaceSchema::findMethodByName( + kj::StringPtr name, uint& counter) const { + // Security: Don't let someone DOS us with a dynamic schema containing cyclic inheritance. + KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") { + return nullptr; + } + + auto result = findSchemaMemberByName(raw->generic, name, getMethods()); + + if (result == nullptr) { + // Search superclasses. + // TODO(perf): This may be somewhat slow, and in the case of lots of diamond dependencies it + // could get pathological. Arguably we should generate a flat list of transitive + // superclasses to search and store it in the RawSchema. It's problematic, though, because + // this means that a dynamically-loaded RawSchema cannot be correctly constructed until all + // superclasses have been loaded, which imposes an ordering requirement on SchemaLoader or + // requires updating subclasses whenever a new superclass is loaded. + auto superclasses = getProto().getInterface().getSuperclasses(); + for (auto i: kj::indices(superclasses)) { + auto superclass = superclasses[i]; + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::SUPERCLASS, i); + result = getDependency(superclass.getId(), location) + .asInterface().findMethodByName(name, counter); + if (result != nullptr) { + break; + } + } + } + + return result; +} + +InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) const { + KJ_IF_MAYBE(method, findMethodByName(name)) { + return *method; + } else { + KJ_FAIL_REQUIRE("interface has no such method", name); + } +} + +InterfaceSchema::SuperclassList InterfaceSchema::getSuperclasses() const { + return SuperclassList(*this, getProto().getInterface().getSuperclasses()); +} + +bool InterfaceSchema::extends(InterfaceSchema other) const { + if (other.raw->generic == &_::NULL_INTERFACE_SCHEMA) { + // We consider all interfaces to extend the null schema. + return true; + } + uint counter = 0; + return extends(other, counter); +} + +bool InterfaceSchema::extends(InterfaceSchema other, uint& counter) const { + // Security: Don't let someone DOS us with a dynamic schema containing cyclic inheritance. + KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") { + return false; + } + + if (other == *this) { + return true; + } + + // TODO(perf): This may be somewhat slow. See findMethodByName() for discussion. + auto superclasses = getProto().getInterface().getSuperclasses(); + for (auto i: kj::indices(superclasses)) { + auto superclass = superclasses[i]; + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::SUPERCLASS, i); + if (getDependency(superclass.getId(), location).asInterface().extends(other, counter)) { + return true; + } + } + + return false; +} + +kj::Maybe InterfaceSchema::findSuperclass(uint64_t typeId) const { + if (typeId == _::NULL_INTERFACE_SCHEMA.id) { + // We consider all interfaces to extend the null schema. + return InterfaceSchema(); + } + uint counter = 0; + return findSuperclass(typeId, counter); +} + +kj::Maybe InterfaceSchema::findSuperclass(uint64_t typeId, uint& counter) const { + // Security: Don't let someone DOS us with a dynamic schema containing cyclic inheritance. + KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") { + return nullptr; + } + + if (typeId == raw->generic->id) { + return *this; + } + + // TODO(perf): This may be somewhat slow. See findMethodByName() for discussion. + auto superclasses = getProto().getInterface().getSuperclasses(); + for (auto i: kj::indices(superclasses)) { + auto superclass = superclasses[i]; + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::SUPERCLASS, i); + KJ_IF_MAYBE(result, getDependency(superclass.getId(), location).asInterface() + .findSuperclass(typeId, counter)) { + return *result; + } + } + + return nullptr; +} + +StructSchema InterfaceSchema::Method::getParamType() const { + auto proto = getProto(); + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::METHOD_PARAMS, ordinal); + return parent.getDependency(proto.getParamStructType(), location).asStruct(); +} + +StructSchema InterfaceSchema::Method::getResultType() const { + auto proto = getProto(); + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::METHOD_RESULTS, ordinal); + return parent.getDependency(proto.getResultStructType(), location).asStruct(); +} + +InterfaceSchema InterfaceSchema::SuperclassList::operator[](uint index) const { + auto superclass = list[index]; + uint location = _::RawBrandedSchema::makeDepLocation( + _::RawBrandedSchema::DepKind::SUPERCLASS, index); + return parent.getDependency(superclass.getId(), location).asInterface(); +} + +// ------------------------------------------------------------------- + +uint32_t ConstSchema::getValueSchemaOffset() const { + return getSchemaOffset(getProto().getConst().getValue()); +} + +Type ConstSchema::getType() const { + return interpretType(getProto().getConst().getType(), + _::RawBrandedSchema::makeDepLocation(_::RawBrandedSchema::DepKind::CONST_TYPE, 0)); +} + +// ======================================================================================= + +ListSchema ListSchema::of(schema::Type::Which primitiveType) { + switch (primitiveType) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + break; + + case schema::Type::STRUCT: + case schema::Type::ENUM: + case schema::Type::INTERFACE: + case schema::Type::LIST: + KJ_FAIL_REQUIRE("Must use one of the other ListSchema::of() overloads for complex types."); + break; + + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("List(AnyPointer) not supported."); + break; + } + + return ListSchema(primitiveType); +} + +ListSchema ListSchema::of(schema::Type::Reader elementType, Schema context) { + // This method is deprecated because it can only be implemented in terms of other deprecated + // methods. Temporarily disable warnings for those other deprecated methods. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + switch (elementType.which()) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + return of(elementType.which()); + + case schema::Type::STRUCT: + return of(context.getDependency(elementType.getStruct().getTypeId()).asStruct()); + + case schema::Type::ENUM: + return of(context.getDependency(elementType.getEnum().getTypeId()).asEnum()); + + case schema::Type::INTERFACE: + return of(context.getDependency(elementType.getInterface().getTypeId()).asInterface()); + + case schema::Type::LIST: + return of(of(elementType.getList().getElementType(), context)); + + case schema::Type::ANY_POINTER: + KJ_FAIL_REQUIRE("List(AnyPointer) not supported."); + return ListSchema(); + } + + // Unknown type is acceptable. + return ListSchema(elementType.which()); +#pragma GCC diagnostic pop +} + +// ======================================================================================= + +StructSchema Type::asStruct() const { + KJ_REQUIRE(isStruct(), "Tried to interpret a non-struct type as a struct.") { + return StructSchema(); + } + KJ_ASSERT(schema != nullptr); + return StructSchema(Schema(schema)); +} +EnumSchema Type::asEnum() const { + KJ_REQUIRE(isEnum(), "Tried to interpret a non-enum type as an enum.") { + return EnumSchema(); + } + KJ_ASSERT(schema != nullptr); + return EnumSchema(Schema(schema)); +} +InterfaceSchema Type::asInterface() const { + KJ_REQUIRE(isInterface(), "Tried to interpret a non-interface type as an interface.") { + return InterfaceSchema(); + } + KJ_ASSERT(schema != nullptr); + return InterfaceSchema(Schema(schema)); +} +ListSchema Type::asList() const { + KJ_REQUIRE(isList(), "Type::asList(): Not a list.") { + return ListSchema::of(schema::Type::VOID); + } + Type elementType = *this; + --elementType.listDepth; + return ListSchema::of(elementType); +} + +kj::Maybe Type::getBrandParameter() const { + KJ_REQUIRE(isAnyPointer(), "Type::getBrandParameter() can only be called on AnyPointer types."); + + if (scopeId == 0) { + return nullptr; + } else { + return BrandParameter { scopeId, paramIndex }; + } +} + +kj::Maybe Type::getImplicitParameter() const { + KJ_REQUIRE(isAnyPointer(), + "Type::getImplicitParameter() can only be called on AnyPointer types."); + + if (isImplicitParam) { + return ImplicitParameter { paramIndex }; + } else { + return nullptr; + } +} + +bool Type::operator==(const Type& other) const { + if (baseType != other.baseType || listDepth != other.listDepth) { + return false; + } + + switch (baseType) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + return true; + + case schema::Type::STRUCT: + case schema::Type::ENUM: + case schema::Type::INTERFACE: + return schema == other.schema; + + case schema::Type::LIST: + KJ_UNREACHABLE; + + case schema::Type::ANY_POINTER: + return scopeId == other.scopeId && isImplicitParam == other.isImplicitParam && + // Trying to comply with strict aliasing rules. Hopefully the compiler realizes that + // both branches compile to the same instructions and can optimize it away. + (scopeId != 0 || isImplicitParam ? paramIndex == other.paramIndex + : anyPointerKind == other.anyPointerKind); + } + + KJ_UNREACHABLE; +} + +size_t Type::hashCode() const { + switch (baseType) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + return (static_cast(baseType) << 3) + listDepth; + + case schema::Type::STRUCT: + case schema::Type::ENUM: + case schema::Type::INTERFACE: + return reinterpret_cast(schema) + listDepth; + + case schema::Type::LIST: + KJ_UNREACHABLE; + + case schema::Type::ANY_POINTER: { + // Trying to comply with strict aliasing rules. Hopefully the compiler realizes that + // both branches compile to the same instructions and can optimize it away. + size_t val = scopeId != 0 || isImplicitParam ? + paramIndex : static_cast(anyPointerKind); + return (val << 1 | isImplicitParam) ^ scopeId; + } + } + + KJ_UNREACHABLE; +} + +void Type::requireUsableAs(Type expected) const { + KJ_REQUIRE(baseType == expected.baseType && listDepth == expected.listDepth, + "This type is not compatible with the requested native type."); + + switch (baseType) { + case schema::Type::VOID: + case schema::Type::BOOL: + case schema::Type::INT8: + case schema::Type::INT16: + case schema::Type::INT32: + case schema::Type::INT64: + case schema::Type::UINT8: + case schema::Type::UINT16: + case schema::Type::UINT32: + case schema::Type::UINT64: + case schema::Type::FLOAT32: + case schema::Type::FLOAT64: + case schema::Type::TEXT: + case schema::Type::DATA: + case schema::Type::ANY_POINTER: + break; + + case schema::Type::STRUCT: + case schema::Type::ENUM: + case schema::Type::INTERFACE: + Schema(schema).requireUsableAs(expected.schema->generic); + break; + + case schema::Type::LIST: + KJ_UNREACHABLE; + } +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,498 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +using Cxx = import "/capnp/c++.capnp"; + +@0xa93fc509624c72d9; +$Cxx.namespace("capnp::schema"); + +using Id = UInt64; +# The globally-unique ID of a file, type, or annotation. + +struct Node { + id @0 :Id; + + displayName @1 :Text; + # Name to present to humans to identify this Node. You should not attempt to parse this. Its + # format could change. It is not guaranteed to be unique. + # + # (On Zooko's triangle, this is the node's nickname.) + + displayNamePrefixLength @2 :UInt32; + # If you want a shorter version of `displayName` (just naming this node, without its surrounding + # scope), chop off this many characters from the beginning of `displayName`. + + scopeId @3 :Id; + # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back + # at this node, but robust code should avoid relying on this (and, in fact, group nodes are not + # listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is + # zero if the node has no parent, which is normally only the case with files, but should be + # allowed for any kind of node (in order to make runtime type generation easier). + + parameters @32 :List(Parameter); + # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. + + isGeneric @33 :Bool; + # True if this node is generic, meaning that it or one of its parent scopes has a non-empty + # `parameters`. + + struct Parameter { + # Information about one of the node's parameters. + + name @0 :Text; + } + + nestedNodes @4 :List(NestedNode); + # List of nodes nested within this node, along with the names under which they were declared. + + struct NestedNode { + name @0 :Text; + # Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically. + # + # (On Zooko's triangle, this is the node's petname according to its parent scope.) + + id @1 :Id; + # ID of the nested node. Typically, the target node's scopeId points back to this node, but + # robust code should avoid relying on this. + } + + annotations @5 :List(Annotation); + # Annotations applied to this node. + + union { + # Info specific to each kind of node. + + file @6 :Void; + + struct :group { + dataWordCount @7 :UInt16; + # Size of the data section, in words. + + pointerCount @8 :UInt16; + # Size of the pointer section, in pointers (which are one word each). + + preferredListEncoding @9 :ElementSize; + # The preferred element size to use when encoding a list of this struct. If this is anything + # other than `inlineComposite` then the struct is one word or less in size and is a candidate + # for list packing optimization. + + isGroup @10 :Bool; + # If true, then this "struct" node is actually not an independent node, but merely represents + # some named union or group within a particular parent struct. This node's scopeId refers + # to the parent struct, which may itself be a union/group in yet another struct. + # + # All group nodes share the same dataWordCount and pointerCount as the top-level + # struct, and their fields live in the same ordinal and offset spaces as all other fields in + # the struct. + # + # Note that a named union is considered a special kind of group -- in fact, a named union + # is exactly equivalent to a group that contains nothing but an unnamed union. + + discriminantCount @11 :UInt16; + # Number of fields in this struct which are members of an anonymous union, and thus may + # overlap. If this is non-zero, then a 16-bit discriminant is present indicating which + # of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be + # two or more. + # + # Note that the fields of an unnamed union are considered fields of the scope containing the + # union -- an unnamed union is not its own group. So, a top-level struct may contain a + # non-zero discriminant count. Named unions, on the other hand, are equivalent to groups + # containing unnamed unions. So, a named union has its own independent schema node, with + # `isGroup` = true. + + discriminantOffset @12 :UInt32; + # If `discriminantCount` is non-zero, this is the offset of the union discriminant, in + # multiples of 16 bits. + + fields @13 :List(Field); + # Fields defined within this scope (either the struct's top-level fields, or the fields of + # a particular group; see `isGroup`). + # + # The fields are sorted by ordinal number, but note that because groups share the same + # ordinal space, the field's index in this list is not necessarily exactly its ordinal. + # On the other hand, the field's position in this list does remain the same even as the + # protocol evolves, since it is not possible to insert or remove an earlier ordinal. + # Therefore, for most use cases, if you want to identify a field by number, it may make the + # most sense to use the field's index in this list rather than its ordinal. + } + + enum :group { + enumerants@14 :List(Enumerant); + # Enumerants ordered by numeric value (ordinal). + } + + interface :group { + methods @15 :List(Method); + # Methods ordered by ordinal. + + superclasses @31 :List(Superclass); + # Superclasses of this interface. + } + + const :group { + type @16 :Type; + value @17 :Value; + } + + annotation :group { + type @18 :Type; + + targetsFile @19 :Bool; + targetsConst @20 :Bool; + targetsEnum @21 :Bool; + targetsEnumerant @22 :Bool; + targetsStruct @23 :Bool; + targetsField @24 :Bool; + targetsUnion @25 :Bool; + targetsGroup @26 :Bool; + targetsInterface @27 :Bool; + targetsMethod @28 :Bool; + targetsParam @29 :Bool; + targetsAnnotation @30 :Bool; + } + } +} + +struct Field { + # Schema for a field of a struct. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Indicates where this member appeared in the code, relative to other members. + # Code ordering may have semantic relevance -- programmers tend to place related fields + # together. So, using code ordering makes sense in human-readable formats where ordering is + # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum + # value is count(members) - 1. Fields that are members of a union are only ordered relative to + # the other members of that union, so the maximum value there is count(union.members). + + annotations @2 :List(Annotation); + + const noDiscriminant :UInt16 = 0xffff; + + discriminantValue @3 :UInt16 = Field.noDiscriminant; + # If the field is in a union, this is the value which the union's discriminant should take when + # the field is active. If the field is not in a union, this is 0xffff. + + union { + slot :group { + # A regular, non-group, non-fixed-list field. + + offset @4 :UInt32; + # Offset, in units of the field's size, from the beginning of the section in which the field + # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the + # beginning of the data section. + + type @5 :Type; + defaultValue @6 :Value; + + hadExplicitDefault @10 :Bool; + # Whether the default value was specified explicitly. Non-explicit default values are always + # zero or empty values. Usually, whether the default value was explicit shouldn't matter. + # The main use case for this flag is for structs representing method parameters: + # explicitly-defaulted parameters may be allowed to be omitted when calling the method. + } + + group :group { + # A group. + + typeId @7 :Id; + # The ID of the group's node. + } + } + + ordinal :union { + implicit @8 :Void; + explicit @9 :UInt16; + # The original ordinal number given to the field. You probably should NOT use this; if you need + # a numeric identifier for a field, use its position within the field array for its scope. + # The ordinal is given here mainly just so that the original schema text can be reproduced given + # the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job. + } +} + +struct Enumerant { + # Schema for member of an enum. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the enumerants were declared in the code. + # Like Struct.Field.codeOrder. + + annotations @2 :List(Annotation); +} + +struct Superclass { + id @0 :Id; + brand @1 :Brand; +} + +struct Method { + # Schema for method of an interface. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the methods were declared in the code. + # Like Struct.Field.codeOrder. + + implicitParameters @7 :List(Node.Parameter); + # The parameters listed in [] (typically, type / generic parameters), whose bindings are intended + # to be inferred rather than specified explicitly, although not all languages support this. + + paramStructType @2 :Id; + # ID of the parameter struct type. If a named parameter list was specified in the method + # declaration (rather than a single struct parameter type) then a corresponding struct type is + # auto-generated. Such an auto-generated type will not be listed in the interface's + # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. + # (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes + # this a situation where you can't just climb the scope chain to find where a particular + # generic parameter was introduced. Making the `scopeId` zero was a mistake.) + + paramBrand @5 :Brand; + # Brand of param struct type. + + resultStructType @3 :Id; + # ID of the return struct type; similar to `paramStructType`. + + resultBrand @6 :Brand; + # Brand of result struct type. + + annotations @4 :List(Annotation); +} + +struct Type { + # Represents a type expression. + + union { + # The ordinals intentionally match those of Value. + + void @0 :Void; + bool @1 :Void; + int8 @2 :Void; + int16 @3 :Void; + int32 @4 :Void; + int64 @5 :Void; + uint8 @6 :Void; + uint16 @7 :Void; + uint32 @8 :Void; + uint64 @9 :Void; + float32 @10 :Void; + float64 @11 :Void; + text @12 :Void; + data @13 :Void; + + list :group { + elementType @14 :Type; + } + + enum :group { + typeId @15 :Id; + brand @21 :Brand; + } + struct :group { + typeId @16 :Id; + brand @22 :Brand; + } + interface :group { + typeId @17 :Id; + brand @23 :Brand; + } + + anyPointer :union { + unconstrained :union { + # A regular AnyPointer. + # + # The name "unconstrained" means as opposed to constraining it to match a type parameter. + # In retrospect this name is probably a poor choice given that it may still be constrained + # to be a struct, list, or capability. + + anyKind @18 :Void; # truly AnyPointer + struct @25 :Void; # AnyStruct + list @26 :Void; # AnyList + capability @27 :Void; # Capability + } + + parameter :group { + # This is actually a reference to a type parameter defined within this scope. + + scopeId @19 :Id; + # ID of the generic type whose parameter we're referencing. This should be a parent of the + # current scope. + + parameterIndex @20 :UInt16; + # Index of the parameter within the generic type's parameter list. + } + + implicitMethodParameter :group { + # This is actually a reference to an implicit (generic) parameter of a method. The only + # legal context for this type to appear is inside Method.paramBrand or Method.resultBrand. + + parameterIndex @24 :UInt16; + } + } + } +} + +struct Brand { + # Specifies bindings for parameters of generics. Since these bindings turn a generic into a + # non-generic, we call it the "brand". + + scopes @0 :List(Scope); + # For each of the target type and each of its parent scopes, a parameterization may be included + # in this list. If no parameterization is included for a particular relevant scope, then either + # that scope has no parameters or all parameters should be considered to be `AnyPointer`. + + struct Scope { + scopeId @0 :Id; + # ID of the scope to which these params apply. + + union { + bind @1 :List(Binding); + # List of parameter bindings. + + inherit @2 :Void; + # The place where this Brand appears is actually within this scope or a sub-scope, + # and the bindings for this scope should be inherited from the reference point. + } + } + + struct Binding { + union { + unbound @0 :Void; + type @1 :Type; + + # TODO(someday): Allow non-type parameters? Unsure if useful. + } + } +} + +struct Value { + # Represents a value, e.g. a field default value, constant value, or annotation value. + + union { + # The ordinals intentionally match those of Type. + + void @0 :Void; + bool @1 :Bool; + int8 @2 :Int8; + int16 @3 :Int16; + int32 @4 :Int32; + int64 @5 :Int64; + uint8 @6 :UInt8; + uint16 @7 :UInt16; + uint32 @8 :UInt32; + uint64 @9 :UInt64; + float32 @10 :Float32; + float64 @11 :Float64; + text @12 :Text; + data @13 :Data; + + list @14 :AnyPointer; + + enum @15 :UInt16; + struct @16 :AnyPointer; + + interface @17 :Void; + # The only interface value that can be represented statically is "null", whose methods always + # throw exceptions. + + anyPointer @18 :AnyPointer; + } +} + +struct Annotation { + # Describes an annotation applied to a declaration. Note AnnotationNode describes the + # annotation's declaration, while this describes a use of the annotation. + + id @0 :Id; + # ID of the annotation node. + + brand @2 :Brand; + # Brand of the annotation. + # + # Note that the annotation itself is not allowed to be parameterized, but its scope might be. + + value @1 :Value; +} + +enum ElementSize { + # Possible element sizes for encoded lists. These correspond exactly to the possible values of + # the 3-bit element size component of a list pointer. + + empty @0; # aka "void", but that's a keyword. + bit @1; + byte @2; + twoBytes @3; + fourBytes @4; + eightBytes @5; + pointer @6; + inlineComposite @7; +} + +struct CapnpVersion { + major @0 :UInt16; + minor @1 :UInt8; + micro @2 :UInt8; +} + +struct CodeGeneratorRequest { + capnpVersion @2 :CapnpVersion; + # Version of the `capnp` executable. Generally, code generators should ignore this, but the code + # generators that ship with `capnp` itself will print a warning if this mismatches since that + # probably indicates something is misconfigured. + # + # The first version of 'capnp' to set this was 0.6.0. So, if it's missing, the compiler version + # is older than that. + + nodes @0 :List(Node); + # All nodes parsed by the compiler, including for the files on the command line and their + # imports. + + requestedFiles @1 :List(RequestedFile); + # Files which were listed on the command line. + + struct RequestedFile { + id @0 :Id; + # ID of the file. + + filename @1 :Text; + # Name of the file as it appeared on the command-line (minus the src-prefix). You may use + # this to decide where to write the output. + + imports @2 :List(Import); + # List of all imported paths seen in this file. + + struct Import { + id @0 :Id; + # ID of the imported file. + + name @1 :Text; + # Name which *this* file used to refer to the foreign file. This may be a relative name. + # This information is provided because it might be useful for code generation, e.g. to + # generate #include directives in C++. We don't put this in Node.file because this + # information is only meaningful at compile time anyway. + # + # (On Zooko's triangle, this is the import's petname according to the importing file.) + } + } +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema.capnp.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema.capnp.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,3674 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: schema.capnp + +#include "schema.capnp.h" + +namespace capnp { +namespace schemas { +static const ::capnp::_::AlignedData<221> b_e682ab4cf923a417 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 19, 0, 0, 0, 1, 0, 5, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 6, 0, 7, 0, 0, 0, 6, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 23, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 177, 163, 15, 241, 204, 27, 82, 185, + 9, 0, 0, 0, 82, 0, 0, 0, + 66, 194, 15, 250, 187, 85, 191, 222, + 9, 0, 0, 0, 90, 0, 0, 0, + 80, 97, 114, 97, 109, 101, 116, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 78, 101, 115, 116, 101, 100, 78, 111, + 100, 101, 0, 0, 0, 0, 0, 0, + 56, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 1, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 1, 0, 0, 3, 0, 1, 0, + 128, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 125, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 124, 1, 0, 0, 3, 0, 1, 0, + 136, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 1, 0, 0, 194, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 136, 1, 0, 0, 3, 0, 1, 0, + 148, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 145, 1, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 140, 1, 0, 0, 3, 0, 1, 0, + 152, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 149, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 1, 0, 0, 3, 0, 1, 0, + 176, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 173, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 172, 1, 0, 0, 3, 0, 1, 0, + 200, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 197, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 1, 0, 0, 3, 0, 1, 0, + 204, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 254, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 53, 68, 251, 55, 155, 177, 160, 158, + 201, 1, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 0, 253, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 152, 245, 51, 67, 54, 179, 74, 181, + 177, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 252, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 143, 33, 194, 240, 207, 83, 39, 232, + 153, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 251, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 32, 148, 13, 122, 172, 165, 138, 177, + 133, 1, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 250, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 144, 2, 10, 64, 212, 25, 22, 236, + 109, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 89, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 1, 0, 0, 3, 0, 1, 0, + 116, 1, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 32, 1, 0, 0, + 0, 0, 1, 0, 33, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 1, 0, 0, 3, 0, 1, 0, + 124, 1, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 112, 108, 97, 121, 78, + 97, 109, 101, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 112, 108, 97, 121, 78, + 97, 109, 101, 80, 114, 101, 102, 105, + 120, 76, 101, 110, 103, 116, 104, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 99, 111, 112, 101, 73, 100, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 101, 115, 116, 101, 100, 78, 111, + 100, 101, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 66, 194, 15, 250, 187, 85, 191, 222, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 66, 117, 37, 171, 13, 149, 200, 241, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 108, 101, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 117, 99, 116, 0, 0, + 101, 110, 117, 109, 0, 0, 0, 0, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 99, 111, 110, 115, 116, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 101, 116, 101, + 114, 115, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 177, 163, 15, 241, 204, 27, 82, 185, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 115, 71, 101, 110, 101, 114, 105, + 99, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e682ab4cf923a417 = b_e682ab4cf923a417.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_e682ab4cf923a417[] = { + &s_9ea0b19b37fb4435, + &s_b18aa5ac7a0d9420, + &s_b54ab3364333f598, + &s_b9521bccf10fa3b1, + &s_debf55bbfa0fc242, + &s_e82753cff0c2218f, + &s_ec1619d4400a0290, + &s_f1c8950dab257542, +}; +static const uint16_t m_e682ab4cf923a417[] = {11, 5, 10, 1, 2, 8, 6, 0, 9, 13, 4, 12, 3, 7}; +static const uint16_t i_e682ab4cf923a417[] = {6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 12, 13}; +const ::capnp::_::RawSchema s_e682ab4cf923a417 = { + 0xe682ab4cf923a417, b_e682ab4cf923a417.words, 221, d_e682ab4cf923a417, m_e682ab4cf923a417, + 8, 14, i_e682ab4cf923a417, nullptr, nullptr, { &s_e682ab4cf923a417, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<34> b_b9521bccf10fa3b1 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 177, 163, 15, 241, 204, 27, 82, 185, + 24, 0, 0, 0, 1, 0, 0, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 80, 97, 114, 97, 109, 101, 116, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b9521bccf10fa3b1 = b_b9521bccf10fa3b1.words; +#if !CAPNP_LITE +static const uint16_t m_b9521bccf10fa3b1[] = {0}; +static const uint16_t i_b9521bccf10fa3b1[] = {0}; +const ::capnp::_::RawSchema s_b9521bccf10fa3b1 = { + 0xb9521bccf10fa3b1, b_b9521bccf10fa3b1.words, 34, nullptr, m_b9521bccf10fa3b1, + 0, 1, i_b9521bccf10fa3b1, nullptr, nullptr, { &s_b9521bccf10fa3b1, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_debf55bbfa0fc242 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 66, 194, 15, 250, 187, 85, 191, 222, + 24, 0, 0, 0, 1, 0, 1, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 26, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 78, 101, 115, 116, 101, 100, 78, 111, + 100, 101, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_debf55bbfa0fc242 = b_debf55bbfa0fc242.words; +#if !CAPNP_LITE +static const uint16_t m_debf55bbfa0fc242[] = {1, 0}; +static const uint16_t i_debf55bbfa0fc242[] = {0, 1}; +const ::capnp::_::RawSchema s_debf55bbfa0fc242 = { + 0xdebf55bbfa0fc242, b_debf55bbfa0fc242.words, 49, nullptr, m_debf55bbfa0fc242, + 0, 2, i_debf55bbfa0fc242, nullptr, nullptr, { &s_debf55bbfa0fc242, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<134> b_9ea0b19b37fb4435 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 53, 68, 251, 55, 155, 177, 160, 158, + 24, 0, 0, 0, 1, 0, 5, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 6, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 143, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 115, 116, 114, 117, 99, 116, 0, 0, + 28, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 0, 0, 0, 3, 0, 1, 0, + 192, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 12, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 189, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 188, 0, 0, 0, 3, 0, 1, 0, + 200, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 13, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 0, 0, 178, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 200, 0, 0, 0, 3, 0, 1, 0, + 212, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 224, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 209, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 204, 0, 0, 0, 3, 0, 1, 0, + 216, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 15, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 213, 0, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 216, 0, 0, 0, 3, 0, 1, 0, + 228, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 225, 0, 0, 0, 154, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 228, 0, 0, 0, 3, 0, 1, 0, + 240, 0, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 237, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 232, 0, 0, 0, 3, 0, 1, 0, + 4, 1, 0, 0, 2, 0, 1, 0, + 100, 97, 116, 97, 87, 111, 114, 100, + 67, 111, 117, 110, 116, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 111, 105, 110, 116, 101, 114, 67, + 111, 117, 110, 116, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 114, 101, 102, 101, 114, 114, 101, + 100, 76, 105, 115, 116, 69, 110, 99, + 111, 100, 105, 110, 103, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 38, 25, 82, 186, 125, 143, 149, 209, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 115, 71, 114, 111, 117, 112, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 99, 114, 105, 109, 105, + 110, 97, 110, 116, 67, 111, 117, 110, + 116, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 99, 114, 105, 109, 105, + 110, 97, 110, 116, 79, 102, 102, 115, + 101, 116, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 101, 108, 100, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9ea0b19b37fb4435 = b_9ea0b19b37fb4435.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9ea0b19b37fb4435[] = { + &s_9aad50a41f4af45f, + &s_d1958f7dba521926, + &s_e682ab4cf923a417, +}; +static const uint16_t m_9ea0b19b37fb4435[] = {0, 4, 5, 6, 3, 1, 2}; +static const uint16_t i_9ea0b19b37fb4435[] = {0, 1, 2, 3, 4, 5, 6}; +const ::capnp::_::RawSchema s_9ea0b19b37fb4435 = { + 0x9ea0b19b37fb4435, b_9ea0b19b37fb4435.words, 134, d_9ea0b19b37fb4435, m_9ea0b19b37fb4435, + 3, 7, i_9ea0b19b37fb4435, nullptr, nullptr, { &s_9ea0b19b37fb4435, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<37> b_b54ab3364333f598 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 152, 245, 51, 67, 54, 179, 74, 181, + 24, 0, 0, 0, 1, 0, 5, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 6, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 234, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 101, 110, 117, 109, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 40, 0, 0, 0, 2, 0, 1, 0, + 101, 110, 117, 109, 101, 114, 97, 110, + 116, 115, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 77, 154, 84, 220, 235, 124, 138, 151, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b54ab3364333f598 = b_b54ab3364333f598.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_b54ab3364333f598[] = { + &s_978a7cebdc549a4d, + &s_e682ab4cf923a417, +}; +static const uint16_t m_b54ab3364333f598[] = {0}; +static const uint16_t i_b54ab3364333f598[] = {0}; +const ::capnp::_::RawSchema s_b54ab3364333f598 = { + 0xb54ab3364333f598, b_b54ab3364333f598.words, 37, d_b54ab3364333f598, m_b54ab3364333f598, + 2, 1, i_b54ab3364333f598, nullptr, nullptr, { &s_b54ab3364333f598, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<57> b_e82753cff0c2218f = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 143, 33, 194, 240, 207, 83, 39, 232, + 24, 0, 0, 0, 1, 0, 5, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 6, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 64, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 31, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 61, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 60, 0, 0, 0, 3, 0, 1, 0, + 88, 0, 0, 0, 2, 0, 1, 0, + 109, 101, 116, 104, 111, 100, 115, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 128, 77, 51, 59, 226, 204, 0, 149, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 117, 112, 101, 114, 99, 108, 97, + 115, 115, 101, 115, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 248, 215, 164, 208, 158, 42, 150, 169, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_e82753cff0c2218f = b_e82753cff0c2218f.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_e82753cff0c2218f[] = { + &s_9500cce23b334d80, + &s_a9962a9ed0a4d7f8, + &s_e682ab4cf923a417, +}; +static const uint16_t m_e82753cff0c2218f[] = {0, 1}; +static const uint16_t i_e82753cff0c2218f[] = {0, 1}; +const ::capnp::_::RawSchema s_e82753cff0c2218f = { + 0xe82753cff0c2218f, b_e82753cff0c2218f.words, 57, d_e82753cff0c2218f, m_e82753cff0c2218f, + 3, 2, i_e82753cff0c2218f, nullptr, nullptr, { &s_e82753cff0c2218f, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<47> b_b18aa5ac7a0d9420 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 32, 148, 13, 122, 172, 165, 138, 177, + 24, 0, 0, 0, 1, 0, 5, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 6, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 99, 111, 110, 115, 116, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 155, 12, 176, 215, 210, 220, 35, 206, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_b18aa5ac7a0d9420 = b_b18aa5ac7a0d9420.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_b18aa5ac7a0d9420[] = { + &s_ce23dcd2d7b00c9b, + &s_d07378ede1f9cc60, + &s_e682ab4cf923a417, +}; +static const uint16_t m_b18aa5ac7a0d9420[] = {0, 1}; +static const uint16_t i_b18aa5ac7a0d9420[] = {0, 1}; +const ::capnp::_::RawSchema s_b18aa5ac7a0d9420 = { + 0xb18aa5ac7a0d9420, b_b18aa5ac7a0d9420.words, 47, d_b18aa5ac7a0d9420, m_b18aa5ac7a0d9420, + 3, 2, i_b18aa5ac7a0d9420, nullptr, nullptr, { &s_b18aa5ac7a0d9420, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<228> b_ec1619d4400a0290 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 144, 2, 10, 64, 212, 25, 22, 236, + 24, 0, 0, 0, 1, 0, 5, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 6, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 26, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 223, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 78, 111, 100, 101, 46, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 18, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 93, 1, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 1, 0, 0, 3, 0, 1, 0, + 100, 1, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 112, 0, 0, 0, + 0, 0, 1, 0, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 1, 0, 0, 3, 0, 1, 0, + 108, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 113, 0, 0, 0, + 0, 0, 1, 0, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 1, 0, 0, 3, 0, 1, 0, + 116, 1, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 1, 0, 21, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 1, 0, 0, 3, 0, 1, 0, + 124, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 115, 0, 0, 0, + 0, 0, 1, 0, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 121, 1, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 124, 1, 0, 0, 3, 0, 1, 0, + 136, 1, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 116, 0, 0, 0, + 0, 0, 1, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 133, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 132, 1, 0, 0, 3, 0, 1, 0, + 144, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 1, 0, 24, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 141, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 140, 1, 0, 0, 3, 0, 1, 0, + 152, 1, 0, 0, 2, 0, 1, 0, + 7, 0, 0, 0, 118, 0, 0, 0, + 0, 0, 1, 0, 25, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 149, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 148, 1, 0, 0, 3, 0, 1, 0, + 160, 1, 0, 0, 2, 0, 1, 0, + 8, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 1, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 157, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 156, 1, 0, 0, 3, 0, 1, 0, + 168, 1, 0, 0, 2, 0, 1, 0, + 9, 0, 0, 0, 120, 0, 0, 0, + 0, 0, 1, 0, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 165, 1, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 168, 1, 0, 0, 3, 0, 1, 0, + 180, 1, 0, 0, 2, 0, 1, 0, + 10, 0, 0, 0, 121, 0, 0, 0, + 0, 0, 1, 0, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 177, 1, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 1, 0, 0, 3, 0, 1, 0, + 188, 1, 0, 0, 2, 0, 1, 0, + 11, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 1, 0, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 1, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 1, 0, 0, 3, 0, 1, 0, + 196, 1, 0, 0, 2, 0, 1, 0, + 12, 0, 0, 0, 123, 0, 0, 0, + 0, 0, 1, 0, 30, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 1, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 196, 1, 0, 0, 3, 0, 1, 0, + 208, 1, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 70, + 105, 108, 101, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 67, + 111, 110, 115, 116, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 69, + 110, 117, 109, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 69, + 110, 117, 109, 101, 114, 97, 110, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 83, + 116, 114, 117, 99, 116, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 70, + 105, 101, 108, 100, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 85, + 110, 105, 111, 110, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 71, + 114, 111, 117, 112, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 73, + 110, 116, 101, 114, 102, 97, 99, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 77, + 101, 116, 104, 111, 100, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 80, + 97, 114, 97, 109, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 97, 114, 103, 101, 116, 115, 65, + 110, 110, 111, 116, 97, 116, 105, 111, + 110, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ec1619d4400a0290 = b_ec1619d4400a0290.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_ec1619d4400a0290[] = { + &s_d07378ede1f9cc60, + &s_e682ab4cf923a417, +}; +static const uint16_t m_ec1619d4400a0290[] = {12, 2, 3, 4, 6, 1, 8, 9, 10, 11, 5, 7, 0}; +static const uint16_t i_ec1619d4400a0290[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +const ::capnp::_::RawSchema s_ec1619d4400a0290 = { + 0xec1619d4400a0290, b_ec1619d4400a0290.words, 228, d_ec1619d4400a0290, m_ec1619d4400a0290, + 2, 13, i_ec1619d4400a0290, nullptr, nullptr, { &s_ec1619d4400a0290, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<114> b_9aad50a41f4af45f = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 19, 0, 0, 0, 1, 0, 3, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 4, 0, 7, 0, 0, 0, 2, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 202, 0, 0, 0, + 33, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 143, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 70, 105, 101, 108, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 18, 199, 254, 124, 190, 76, 177, 151, + 1, 0, 0, 0, 122, 0, 0, 0, + 110, 111, 68, 105, 115, 99, 114, 105, + 109, 105, 110, 97, 110, 116, 0, 0, + 28, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 176, 0, 0, 0, 3, 0, 1, 0, + 188, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 185, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 184, 0, 0, 0, 3, 0, 1, 0, + 196, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 193, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 3, 0, 1, 0, + 220, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 217, 0, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 3, 0, 1, 0, + 232, 0, 0, 0, 2, 0, 1, 0, + 4, 0, 255, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 111, 116, 180, 107, 71, 5, 35, 196, + 229, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 254, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 17, 29, 219, 104, 219, 205, 252, 202, + 205, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 230, 11, 135, 135, 194, 213, 144, 187, + 181, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 111, 100, 101, 79, 114, 100, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 66, 117, 37, 171, 13, 149, 200, 241, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 105, 115, 99, 114, 105, 109, 105, + 110, 97, 110, 116, 86, 97, 108, 117, + 101, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 108, 111, 116, 0, 0, 0, 0, + 103, 114, 111, 117, 112, 0, 0, 0, + 111, 114, 100, 105, 110, 97, 108, 0, } +}; +::capnp::word const* const bp_9aad50a41f4af45f = b_9aad50a41f4af45f.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9aad50a41f4af45f[] = { + &s_bb90d5c287870be6, + &s_c42305476bb4746f, + &s_cafccddb68db1d11, + &s_f1c8950dab257542, +}; +static const uint16_t m_9aad50a41f4af45f[] = {2, 1, 3, 5, 0, 6, 4}; +static const uint16_t i_9aad50a41f4af45f[] = {4, 5, 0, 1, 2, 3, 6}; +const ::capnp::_::RawSchema s_9aad50a41f4af45f = { + 0x9aad50a41f4af45f, b_9aad50a41f4af45f.words, 114, d_9aad50a41f4af45f, m_9aad50a41f4af45f, + 4, 7, i_9aad50a41f4af45f, nullptr, nullptr, { &s_9aad50a41f4af45f, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<25> b_97b14cbe7cfec712 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 18, 199, 254, 124, 190, 76, 177, 151, + 25, 0, 0, 0, 4, 0, 0, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 0, 0, 0, 3, 0, 1, 0, + 44, 0, 0, 0, 2, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 70, 105, 101, 108, 100, + 46, 110, 111, 68, 105, 115, 99, 114, + 105, 109, 105, 110, 97, 110, 116, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_97b14cbe7cfec712 = b_97b14cbe7cfec712.words; +#if !CAPNP_LITE +const ::capnp::_::RawSchema s_97b14cbe7cfec712 = { + 0x97b14cbe7cfec712, b_97b14cbe7cfec712.words, 25, nullptr, nullptr, + 0, 0, nullptr, nullptr, nullptr, { &s_97b14cbe7cfec712, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<80> b_c42305476bb4746f = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 111, 116, 180, 107, 71, 5, 35, 196, + 25, 0, 0, 0, 1, 0, 3, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 4, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 70, 105, 101, 108, 100, + 46, 115, 108, 111, 116, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 3, 0, 1, 0, + 104, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 3, 0, 1, 0, + 108, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 0, 0, 0, 3, 0, 1, 0, + 116, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 128, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 0, 0, 0, 154, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 0, 0, 0, 3, 0, 1, 0, + 128, 0, 0, 0, 2, 0, 1, 0, + 111, 102, 102, 115, 101, 116, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 101, 102, 97, 117, 108, 116, 86, + 97, 108, 117, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 155, 12, 176, 215, 210, 220, 35, 206, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 104, 97, 100, 69, 120, 112, 108, 105, + 99, 105, 116, 68, 101, 102, 97, 117, + 108, 116, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c42305476bb4746f = b_c42305476bb4746f.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c42305476bb4746f[] = { + &s_9aad50a41f4af45f, + &s_ce23dcd2d7b00c9b, + &s_d07378ede1f9cc60, +}; +static const uint16_t m_c42305476bb4746f[] = {2, 3, 0, 1}; +static const uint16_t i_c42305476bb4746f[] = {0, 1, 2, 3}; +const ::capnp::_::RawSchema s_c42305476bb4746f = { + 0xc42305476bb4746f, b_c42305476bb4746f.words, 80, d_c42305476bb4746f, m_c42305476bb4746f, + 3, 4, i_c42305476bb4746f, nullptr, nullptr, { &s_c42305476bb4746f, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<32> b_cafccddb68db1d11 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 17, 29, 219, 104, 219, 205, 252, 202, + 25, 0, 0, 0, 1, 0, 3, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 4, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 70, 105, 101, 108, 100, + 46, 103, 114, 111, 117, 112, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 20, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 73, 100, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_cafccddb68db1d11 = b_cafccddb68db1d11.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_cafccddb68db1d11[] = { + &s_9aad50a41f4af45f, +}; +static const uint16_t m_cafccddb68db1d11[] = {0}; +static const uint16_t i_cafccddb68db1d11[] = {0}; +const ::capnp::_::RawSchema s_cafccddb68db1d11 = { + 0xcafccddb68db1d11, b_cafccddb68db1d11.words, 32, d_cafccddb68db1d11, m_cafccddb68db1d11, + 1, 1, i_cafccddb68db1d11, nullptr, nullptr, { &s_cafccddb68db1d11, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<50> b_bb90d5c287870be6 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 230, 11, 135, 135, 194, 213, 144, 187, + 25, 0, 0, 0, 1, 0, 3, 0, + 95, 244, 74, 31, 164, 80, 173, 154, + 4, 0, 7, 0, 1, 0, 2, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 10, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 70, 105, 101, 108, 100, + 46, 111, 114, 100, 105, 110, 97, 108, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 6, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 0, 3, 0, 1, 0, + 60, 0, 0, 0, 2, 0, 1, 0, + 105, 109, 112, 108, 105, 99, 105, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 120, 112, 108, 105, 99, 105, 116, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_bb90d5c287870be6 = b_bb90d5c287870be6.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_bb90d5c287870be6[] = { + &s_9aad50a41f4af45f, +}; +static const uint16_t m_bb90d5c287870be6[] = {1, 0}; +static const uint16_t i_bb90d5c287870be6[] = {0, 1}; +const ::capnp::_::RawSchema s_bb90d5c287870be6 = { + 0xbb90d5c287870be6, b_bb90d5c287870be6.words, 50, d_bb90d5c287870be6, m_bb90d5c287870be6, + 1, 2, i_bb90d5c287870be6, nullptr, nullptr, { &s_bb90d5c287870be6, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<69> b_978a7cebdc549a4d = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 77, 154, 84, 220, 235, 124, 138, 151, + 19, 0, 0, 0, 1, 0, 1, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 234, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 69, 110, 117, 109, 101, + 114, 97, 110, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 0, 3, 0, 1, 0, + 108, 0, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 111, 100, 101, 79, 114, 100, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 66, 117, 37, 171, 13, 149, 200, 241, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_978a7cebdc549a4d = b_978a7cebdc549a4d.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_978a7cebdc549a4d[] = { + &s_f1c8950dab257542, +}; +static const uint16_t m_978a7cebdc549a4d[] = {2, 1, 0}; +static const uint16_t i_978a7cebdc549a4d[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_978a7cebdc549a4d = { + 0x978a7cebdc549a4d, b_978a7cebdc549a4d.words, 69, d_978a7cebdc549a4d, m_978a7cebdc549a4d, + 1, 3, i_978a7cebdc549a4d, nullptr, nullptr, { &s_978a7cebdc549a4d, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<48> b_a9962a9ed0a4d7f8 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 248, 215, 164, 208, 158, 42, 150, 169, + 19, 0, 0, 0, 1, 0, 1, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 83, 117, 112, 101, 114, + 99, 108, 97, 115, 115, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 110, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_a9962a9ed0a4d7f8 = b_a9962a9ed0a4d7f8.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_a9962a9ed0a4d7f8[] = { + &s_903455f06065422b, +}; +static const uint16_t m_a9962a9ed0a4d7f8[] = {1, 0}; +static const uint16_t i_a9962a9ed0a4d7f8[] = {0, 1}; +const ::capnp::_::RawSchema s_a9962a9ed0a4d7f8 = { + 0xa9962a9ed0a4d7f8, b_a9962a9ed0a4d7f8.words, 48, d_a9962a9ed0a4d7f8, m_a9962a9ed0a4d7f8, + 1, 2, i_a9962a9ed0a4d7f8, nullptr, nullptr, { &s_a9962a9ed0a4d7f8, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<155> b_9500cce23b334d80 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 128, 77, 51, 59, 226, 204, 0, 149, + 19, 0, 0, 0, 1, 0, 3, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 5, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 210, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 199, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 77, 101, 116, 104, 111, + 100, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 32, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 209, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 204, 0, 0, 0, 3, 0, 1, 0, + 216, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 213, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 212, 0, 0, 0, 3, 0, 1, 0, + 224, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 221, 0, 0, 0, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 3, 0, 1, 0, + 232, 0, 0, 0, 2, 0, 1, 0, + 5, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 229, 0, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 232, 0, 0, 0, 3, 0, 1, 0, + 244, 0, 0, 0, 2, 0, 1, 0, + 7, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 241, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 3, 0, 1, 0, + 12, 1, 0, 0, 2, 0, 1, 0, + 4, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 1, 0, 0, 3, 0, 1, 0, + 20, 1, 0, 0, 2, 0, 1, 0, + 6, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 1, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 1, 0, 0, 3, 0, 1, 0, + 28, 1, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 1, 0, 0, 154, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 1, 0, 0, 3, 0, 1, 0, + 56, 1, 0, 0, 2, 0, 1, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 111, 100, 101, 79, 114, 100, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 83, 116, 114, + 117, 99, 116, 84, 121, 112, 101, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 117, 108, 116, 83, 116, + 114, 117, 99, 116, 84, 121, 112, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 110, 111, 116, 97, 116, 105, + 111, 110, 115, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 66, 117, 37, 171, 13, 149, 200, 241, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 66, 114, 97, + 110, 100, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 115, 117, 108, 116, 66, 114, + 97, 110, 100, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 109, 112, 108, 105, 99, 105, 116, + 80, 97, 114, 97, 109, 101, 116, 101, + 114, 115, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 177, 163, 15, 241, 204, 27, 82, 185, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9500cce23b334d80 = b_9500cce23b334d80.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9500cce23b334d80[] = { + &s_903455f06065422b, + &s_b9521bccf10fa3b1, + &s_f1c8950dab257542, +}; +static const uint16_t m_9500cce23b334d80[] = {4, 1, 7, 0, 5, 2, 6, 3}; +static const uint16_t i_9500cce23b334d80[] = {0, 1, 2, 3, 4, 5, 6, 7}; +const ::capnp::_::RawSchema s_9500cce23b334d80 = { + 0x9500cce23b334d80, b_9500cce23b334d80.words, 155, d_9500cce23b334d80, m_9500cce23b334d80, + 3, 8, i_9500cce23b334d80, nullptr, nullptr, { &s_9500cce23b334d80, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<269> b_d07378ede1f9cc60 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 19, 0, 0, 0, 1, 0, 3, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 1, 0, 7, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 194, 0, 0, 0, + 29, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 47, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 76, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 3, 0, 1, 0, + 12, 2, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 0, 0, 3, 0, 1, 0, + 16, 2, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 2, 0, 0, 3, 0, 1, 0, + 20, 2, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 2, 0, 0, 3, 0, 1, 0, + 24, 2, 0, 0, 2, 0, 1, 0, + 4, 0, 251, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 2, 0, 0, 3, 0, 1, 0, + 28, 2, 0, 0, 2, 0, 1, 0, + 5, 0, 250, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 2, 0, 0, 3, 0, 1, 0, + 32, 2, 0, 0, 2, 0, 1, 0, + 6, 0, 249, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 24, 2, 0, 0, 3, 0, 1, 0, + 36, 2, 0, 0, 2, 0, 1, 0, + 7, 0, 248, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 2, 0, 0, 3, 0, 1, 0, + 40, 2, 0, 0, 2, 0, 1, 0, + 8, 0, 247, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 2, 0, 0, 3, 0, 1, 0, + 44, 2, 0, 0, 2, 0, 1, 0, + 9, 0, 246, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 2, 0, 0, 3, 0, 1, 0, + 48, 2, 0, 0, 2, 0, 1, 0, + 10, 0, 245, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 2, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 2, 0, 0, 3, 0, 1, 0, + 52, 2, 0, 0, 2, 0, 1, 0, + 11, 0, 244, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 2, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 2, 0, 0, 3, 0, 1, 0, + 56, 2, 0, 0, 2, 0, 1, 0, + 12, 0, 243, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 53, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 2, 0, 0, 3, 0, 1, 0, + 60, 2, 0, 0, 2, 0, 1, 0, + 13, 0, 242, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 52, 2, 0, 0, 3, 0, 1, 0, + 64, 2, 0, 0, 2, 0, 1, 0, + 14, 0, 241, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 151, 234, 96, 10, 37, 57, 231, 135, + 61, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 240, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 169, 135, 127, 26, 113, 120, 14, 158, + 37, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 239, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 211, 198, 76, 239, 96, 111, 58, 172, + 13, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 238, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 191, 12, 251, 247, 105, 202, 139, 237, + 245, 1, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 237, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 241, 73, 62, 162, 232, 63, 87, 194, + 225, 1, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 111, 105, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 111, 111, 108, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 56, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 49, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 51, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 54, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 49, 54, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 51, 50, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 54, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 51, 50, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 54, 52, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 101, 120, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 97, 116, 97, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 105, 115, 116, 0, 0, 0, 0, + 101, 110, 117, 109, 0, 0, 0, 0, + 115, 116, 114, 117, 99, 116, 0, 0, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d07378ede1f9cc60 = b_d07378ede1f9cc60.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_d07378ede1f9cc60[] = { + &s_87e739250a60ea97, + &s_9e0e78711a7f87a9, + &s_ac3a6f60ef4cc6d3, + &s_c2573fe8a23e49f1, + &s_ed8bca69f7fb0cbf, +}; +static const uint16_t m_d07378ede1f9cc60[] = {18, 1, 13, 15, 10, 11, 3, 4, 5, 2, 17, 14, 16, 12, 7, 8, 9, 6, 0}; +static const uint16_t i_d07378ede1f9cc60[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; +const ::capnp::_::RawSchema s_d07378ede1f9cc60 = { + 0xd07378ede1f9cc60, b_d07378ede1f9cc60.words, 269, d_d07378ede1f9cc60, m_d07378ede1f9cc60, + 5, 19, i_d07378ede1f9cc60, nullptr, nullptr, { &s_d07378ede1f9cc60, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<33> b_87e739250a60ea97 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 151, 234, 96, 10, 37, 57, 231, 135, + 24, 0, 0, 0, 1, 0, 3, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 234, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 108, 105, 115, 116, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 24, 0, 0, 0, 2, 0, 1, 0, + 101, 108, 101, 109, 101, 110, 116, 84, + 121, 112, 101, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_87e739250a60ea97 = b_87e739250a60ea97.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_87e739250a60ea97[] = { + &s_d07378ede1f9cc60, +}; +static const uint16_t m_87e739250a60ea97[] = {0}; +static const uint16_t i_87e739250a60ea97[] = {0}; +const ::capnp::_::RawSchema s_87e739250a60ea97 = { + 0x87e739250a60ea97, b_87e739250a60ea97.words, 33, d_87e739250a60ea97, m_87e739250a60ea97, + 1, 1, i_87e739250a60ea97, nullptr, nullptr, { &s_87e739250a60ea97, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<47> b_9e0e78711a7f87a9 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 169, 135, 127, 26, 113, 120, 14, 158, + 24, 0, 0, 0, 1, 0, 3, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 234, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 101, 110, 117, 109, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 21, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 73, 100, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 110, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9e0e78711a7f87a9 = b_9e0e78711a7f87a9.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9e0e78711a7f87a9[] = { + &s_903455f06065422b, + &s_d07378ede1f9cc60, +}; +static const uint16_t m_9e0e78711a7f87a9[] = {1, 0}; +static const uint16_t i_9e0e78711a7f87a9[] = {0, 1}; +const ::capnp::_::RawSchema s_9e0e78711a7f87a9 = { + 0x9e0e78711a7f87a9, b_9e0e78711a7f87a9.words, 47, d_9e0e78711a7f87a9, m_9e0e78711a7f87a9, + 2, 2, i_9e0e78711a7f87a9, nullptr, nullptr, { &s_9e0e78711a7f87a9, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<47> b_ac3a6f60ef4cc6d3 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 211, 198, 76, 239, 96, 111, 58, 172, + 24, 0, 0, 0, 1, 0, 3, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 115, 116, 114, 117, 99, 116, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 73, 100, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 110, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ac3a6f60ef4cc6d3 = b_ac3a6f60ef4cc6d3.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_ac3a6f60ef4cc6d3[] = { + &s_903455f06065422b, + &s_d07378ede1f9cc60, +}; +static const uint16_t m_ac3a6f60ef4cc6d3[] = {1, 0}; +static const uint16_t i_ac3a6f60ef4cc6d3[] = {0, 1}; +const ::capnp::_::RawSchema s_ac3a6f60ef4cc6d3 = { + 0xac3a6f60ef4cc6d3, b_ac3a6f60ef4cc6d3.words, 47, d_ac3a6f60ef4cc6d3, m_ac3a6f60ef4cc6d3, + 2, 2, i_ac3a6f60ef4cc6d3, nullptr, nullptr, { &s_ac3a6f60ef4cc6d3, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<48> b_ed8bca69f7fb0cbf = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 191, 12, 251, 247, 105, 202, 139, 237, + 24, 0, 0, 0, 1, 0, 3, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 18, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 116, 121, 112, 101, 73, 100, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 110, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ed8bca69f7fb0cbf = b_ed8bca69f7fb0cbf.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_ed8bca69f7fb0cbf[] = { + &s_903455f06065422b, + &s_d07378ede1f9cc60, +}; +static const uint16_t m_ed8bca69f7fb0cbf[] = {1, 0}; +static const uint16_t i_ed8bca69f7fb0cbf[] = {0, 1}; +const ::capnp::_::RawSchema s_ed8bca69f7fb0cbf = { + 0xed8bca69f7fb0cbf, b_ed8bca69f7fb0cbf.words, 48, d_ed8bca69f7fb0cbf, m_ed8bca69f7fb0cbf, + 2, 2, i_ed8bca69f7fb0cbf, nullptr, nullptr, { &s_ed8bca69f7fb0cbf, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<46> b_c2573fe8a23e49f1 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 241, 73, 62, 162, 232, 63, 87, 194, + 24, 0, 0, 0, 1, 0, 3, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 1, 0, 7, 0, 1, 0, 3, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 26, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 86, 54, 89, 254, 121, 95, 59, 142, + 69, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 133, 74, 97, 244, 36, 247, 209, 157, + 49, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 253, 255, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 116, 226, 86, 12, 18, 201, 239, 186, + 29, 0, 0, 0, 194, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 110, 99, 111, 110, 115, 116, 114, + 97, 105, 110, 101, 100, 0, 0, 0, + 112, 97, 114, 97, 109, 101, 116, 101, + 114, 0, 0, 0, 0, 0, 0, 0, + 105, 109, 112, 108, 105, 99, 105, 116, + 77, 101, 116, 104, 111, 100, 80, 97, + 114, 97, 109, 101, 116, 101, 114, 0, } +}; +::capnp::word const* const bp_c2573fe8a23e49f1 = b_c2573fe8a23e49f1.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c2573fe8a23e49f1[] = { + &s_8e3b5f79fe593656, + &s_9dd1f724f4614a85, + &s_baefc9120c56e274, + &s_d07378ede1f9cc60, +}; +static const uint16_t m_c2573fe8a23e49f1[] = {2, 1, 0}; +static const uint16_t i_c2573fe8a23e49f1[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_c2573fe8a23e49f1 = { + 0xc2573fe8a23e49f1, b_c2573fe8a23e49f1.words, 46, d_c2573fe8a23e49f1, m_c2573fe8a23e49f1, + 4, 3, i_c2573fe8a23e49f1, nullptr, nullptr, { &s_c2573fe8a23e49f1, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<81> b_8e3b5f79fe593656 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 86, 54, 89, 254, 121, 95, 59, 142, + 35, 0, 0, 0, 1, 0, 3, 0, + 241, 73, 62, 162, 232, 63, 87, 194, + 1, 0, 7, 0, 1, 0, 4, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 138, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 46, 117, 110, 99, 111, 110, + 115, 116, 114, 97, 105, 110, 101, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 18, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 3, 0, 1, 0, + 104, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 25, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 3, 0, 1, 0, + 108, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 0, 0, 0, 3, 0, 1, 0, + 112, 0, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 109, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 0, 0, 0, 3, 0, 1, 0, + 120, 0, 0, 0, 2, 0, 1, 0, + 97, 110, 121, 75, 105, 110, 100, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 117, 99, 116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 105, 115, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 97, 98, 105, 108, 105, + 116, 121, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_8e3b5f79fe593656 = b_8e3b5f79fe593656.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_8e3b5f79fe593656[] = { + &s_c2573fe8a23e49f1, +}; +static const uint16_t m_8e3b5f79fe593656[] = {0, 3, 2, 1}; +static const uint16_t i_8e3b5f79fe593656[] = {0, 1, 2, 3}; +const ::capnp::_::RawSchema s_8e3b5f79fe593656 = { + 0x8e3b5f79fe593656, b_8e3b5f79fe593656.words, 81, d_8e3b5f79fe593656, m_8e3b5f79fe593656, + 1, 4, i_8e3b5f79fe593656, nullptr, nullptr, { &s_8e3b5f79fe593656, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<50> b_9dd1f724f4614a85 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 133, 74, 97, 244, 36, 247, 209, 157, + 35, 0, 0, 0, 1, 0, 3, 0, + 241, 73, 62, 162, 232, 63, 87, 194, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 106, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 46, 112, 97, 114, 97, 109, + 101, 116, 101, 114, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 0, 0, 0, 3, 0, 1, 0, + 56, 0, 0, 0, 2, 0, 1, 0, + 115, 99, 111, 112, 101, 73, 100, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 97, 114, 97, 109, 101, 116, 101, + 114, 73, 110, 100, 101, 120, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_9dd1f724f4614a85 = b_9dd1f724f4614a85.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_9dd1f724f4614a85[] = { + &s_c2573fe8a23e49f1, +}; +static const uint16_t m_9dd1f724f4614a85[] = {1, 0}; +static const uint16_t i_9dd1f724f4614a85[] = {0, 1}; +const ::capnp::_::RawSchema s_9dd1f724f4614a85 = { + 0x9dd1f724f4614a85, b_9dd1f724f4614a85.words, 50, d_9dd1f724f4614a85, m_9dd1f724f4614a85, + 1, 2, i_9dd1f724f4614a85, nullptr, nullptr, { &s_9dd1f724f4614a85, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<37> b_baefc9120c56e274 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 116, 226, 86, 12, 18, 201, 239, 186, + 35, 0, 0, 0, 1, 0, 3, 0, + 241, 73, 62, 162, 232, 63, 87, 194, + 1, 0, 7, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 218, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 84, 121, 112, 101, 46, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 46, 105, 109, 112, 108, 105, + 99, 105, 116, 77, 101, 116, 104, 111, + 100, 80, 97, 114, 97, 109, 101, 116, + 101, 114, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 1, 0, 24, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 1, 0, + 24, 0, 0, 0, 2, 0, 1, 0, + 112, 97, 114, 97, 109, 101, 116, 101, + 114, 73, 110, 100, 101, 120, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_baefc9120c56e274 = b_baefc9120c56e274.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_baefc9120c56e274[] = { + &s_c2573fe8a23e49f1, +}; +static const uint16_t m_baefc9120c56e274[] = {0}; +static const uint16_t i_baefc9120c56e274[] = {0}; +const ::capnp::_::RawSchema s_baefc9120c56e274 = { + 0xbaefc9120c56e274, b_baefc9120c56e274.words, 37, d_baefc9120c56e274, m_baefc9120c56e274, + 1, 1, i_baefc9120c56e274, nullptr, nullptr, { &s_baefc9120c56e274, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<43> b_903455f06065422b = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 19, 0, 0, 0, 1, 0, 0, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 202, 0, 0, 0, + 33, 0, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 66, 114, 97, 110, 100, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 1, 0, 1, 0, + 201, 107, 99, 169, 133, 52, 215, 171, + 9, 0, 0, 0, 50, 0, 0, 0, + 252, 231, 158, 150, 22, 205, 99, 200, + 5, 0, 0, 0, 66, 0, 0, 0, + 83, 99, 111, 112, 101, 0, 0, 0, + 66, 105, 110, 100, 105, 110, 103, 0, + 4, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 3, 0, 1, 0, + 36, 0, 0, 0, 2, 0, 1, 0, + 115, 99, 111, 112, 101, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 201, 107, 99, 169, 133, 52, 215, 171, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_903455f06065422b = b_903455f06065422b.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_903455f06065422b[] = { + &s_abd73485a9636bc9, +}; +static const uint16_t m_903455f06065422b[] = {0}; +static const uint16_t i_903455f06065422b[] = {0}; +const ::capnp::_::RawSchema s_903455f06065422b = { + 0x903455f06065422b, b_903455f06065422b.words, 43, d_903455f06065422b, m_903455f06065422b, + 1, 1, i_903455f06065422b, nullptr, nullptr, { &s_903455f06065422b, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<67> b_abd73485a9636bc9 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 201, 107, 99, 169, 133, 52, 215, 171, + 25, 0, 0, 0, 1, 0, 2, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 1, 0, 7, 0, 0, 0, 2, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 66, 114, 97, 110, 100, + 46, 83, 99, 111, 112, 101, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 96, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 93, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 0, 0, 0, 3, 0, 1, 0, + 100, 0, 0, 0, 2, 0, 1, 0, + 115, 99, 111, 112, 101, 73, 100, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 105, 110, 100, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 252, 231, 158, 150, 22, 205, 99, 200, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 104, 101, 114, 105, 116, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_abd73485a9636bc9 = b_abd73485a9636bc9.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_abd73485a9636bc9[] = { + &s_c863cd16969ee7fc, +}; +static const uint16_t m_abd73485a9636bc9[] = {1, 2, 0}; +static const uint16_t i_abd73485a9636bc9[] = {1, 2, 0}; +const ::capnp::_::RawSchema s_abd73485a9636bc9 = { + 0xabd73485a9636bc9, b_abd73485a9636bc9.words, 67, d_abd73485a9636bc9, m_abd73485a9636bc9, + 1, 3, i_abd73485a9636bc9, nullptr, nullptr, { &s_abd73485a9636bc9, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<49> b_c863cd16969ee7fc = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 252, 231, 158, 150, 22, 205, 99, 200, + 25, 0, 0, 0, 1, 0, 1, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 1, 0, 7, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 10, 1, 0, 0, + 37, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 66, 114, 97, 110, 100, + 46, 66, 105, 110, 100, 105, 110, 103, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 117, 110, 98, 111, 117, 110, 100, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 121, 112, 101, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 96, 204, 249, 225, 237, 120, 115, 208, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_c863cd16969ee7fc = b_c863cd16969ee7fc.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_c863cd16969ee7fc[] = { + &s_d07378ede1f9cc60, +}; +static const uint16_t m_c863cd16969ee7fc[] = {1, 0}; +static const uint16_t i_c863cd16969ee7fc[] = {0, 1}; +const ::capnp::_::RawSchema s_c863cd16969ee7fc = { + 0xc863cd16969ee7fc, b_c863cd16969ee7fc.words, 49, d_c863cd16969ee7fc, m_c863cd16969ee7fc, + 1, 2, i_c863cd16969ee7fc, nullptr, nullptr, { &s_c863cd16969ee7fc, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<305> b_ce23dcd2d7b00c9b = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 155, 12, 176, 215, 210, 220, 35, 206, + 19, 0, 0, 0, 1, 0, 2, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 1, 0, 7, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 202, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 47, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 86, 97, 108, 117, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 76, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 255, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 3, 0, 1, 0, + 12, 2, 0, 0, 2, 0, 1, 0, + 1, 0, 254, 255, 16, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 0, 0, 3, 0, 1, 0, + 16, 2, 0, 0, 2, 0, 1, 0, + 2, 0, 253, 255, 2, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 2, 0, 0, 3, 0, 1, 0, + 20, 2, 0, 0, 2, 0, 1, 0, + 3, 0, 252, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 2, 0, 0, 3, 0, 1, 0, + 24, 2, 0, 0, 2, 0, 1, 0, + 4, 0, 251, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 2, 0, 0, 3, 0, 1, 0, + 28, 2, 0, 0, 2, 0, 1, 0, + 5, 0, 250, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 25, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 20, 2, 0, 0, 3, 0, 1, 0, + 32, 2, 0, 0, 2, 0, 1, 0, + 6, 0, 249, 255, 2, 0, 0, 0, + 0, 0, 1, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 2, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 24, 2, 0, 0, 3, 0, 1, 0, + 36, 2, 0, 0, 2, 0, 1, 0, + 7, 0, 248, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 33, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 2, 0, 0, 3, 0, 1, 0, + 40, 2, 0, 0, 2, 0, 1, 0, + 8, 0, 247, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 37, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32, 2, 0, 0, 3, 0, 1, 0, + 44, 2, 0, 0, 2, 0, 1, 0, + 9, 0, 246, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 2, 0, 0, 3, 0, 1, 0, + 48, 2, 0, 0, 2, 0, 1, 0, + 10, 0, 245, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 2, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 2, 0, 0, 3, 0, 1, 0, + 52, 2, 0, 0, 2, 0, 1, 0, + 11, 0, 244, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 2, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 44, 2, 0, 0, 3, 0, 1, 0, + 56, 2, 0, 0, 2, 0, 1, 0, + 12, 0, 243, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 53, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 2, 0, 0, 3, 0, 1, 0, + 60, 2, 0, 0, 2, 0, 1, 0, + 13, 0, 242, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 52, 2, 0, 0, 3, 0, 1, 0, + 64, 2, 0, 0, 2, 0, 1, 0, + 14, 0, 241, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 61, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 56, 2, 0, 0, 3, 0, 1, 0, + 68, 2, 0, 0, 2, 0, 1, 0, + 15, 0, 240, 255, 1, 0, 0, 0, + 0, 0, 1, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 65, 2, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 60, 2, 0, 0, 3, 0, 1, 0, + 72, 2, 0, 0, 2, 0, 1, 0, + 16, 0, 239, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 2, 0, 0, 58, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 2, 0, 0, 3, 0, 1, 0, + 76, 2, 0, 0, 2, 0, 1, 0, + 17, 0, 238, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 2, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 2, 0, 0, 3, 0, 1, 0, + 84, 2, 0, 0, 2, 0, 1, 0, + 18, 0, 237, 255, 0, 0, 0, 0, + 0, 0, 1, 0, 18, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 2, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 2, 0, 0, 3, 0, 1, 0, + 92, 2, 0, 0, 2, 0, 1, 0, + 118, 111, 105, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 111, 111, 108, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 56, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 49, 54, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 51, 50, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 54, 52, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 56, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 49, 54, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 51, 50, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 117, 105, 110, 116, 54, 52, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 51, 50, 0, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 108, 111, 97, 116, 54, 52, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 116, 101, 120, 116, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 100, 97, 116, 97, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 108, 105, 115, 116, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 110, 117, 109, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 114, 117, 99, 116, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 110, 116, 101, 114, 102, 97, 99, + 101, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 97, 110, 121, 80, 111, 105, 110, 116, + 101, 114, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ce23dcd2d7b00c9b = b_ce23dcd2d7b00c9b.words; +#if !CAPNP_LITE +static const uint16_t m_ce23dcd2d7b00c9b[] = {18, 1, 13, 15, 10, 11, 3, 4, 5, 2, 17, 14, 16, 12, 7, 8, 9, 6, 0}; +static const uint16_t i_ce23dcd2d7b00c9b[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; +const ::capnp::_::RawSchema s_ce23dcd2d7b00c9b = { + 0xce23dcd2d7b00c9b, b_ce23dcd2d7b00c9b.words, 305, nullptr, m_ce23dcd2d7b00c9b, + 0, 19, i_ce23dcd2d7b00c9b, nullptr, nullptr, { &s_ce23dcd2d7b00c9b, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<63> b_f1c8950dab257542 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 66, 117, 37, 171, 13, 149, 200, 241, + 19, 0, 0, 0, 1, 0, 1, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 242, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 65, 110, 110, 111, 116, + 97, 116, 105, 111, 110, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 118, 97, 108, 117, 101, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 155, 12, 176, 215, 210, 220, 35, 206, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 98, 114, 97, 110, 100, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 43, 66, 101, 96, 240, 85, 52, 144, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_f1c8950dab257542 = b_f1c8950dab257542.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_f1c8950dab257542[] = { + &s_903455f06065422b, + &s_ce23dcd2d7b00c9b, +}; +static const uint16_t m_f1c8950dab257542[] = {2, 0, 1}; +static const uint16_t i_f1c8950dab257542[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_f1c8950dab257542 = { + 0xf1c8950dab257542, b_f1c8950dab257542.words, 63, d_f1c8950dab257542, m_f1c8950dab257542, + 2, 3, i_f1c8950dab257542, nullptr, nullptr, { &s_f1c8950dab257542, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<54> b_d1958f7dba521926 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 38, 25, 82, 186, 125, 143, 149, 209, + 19, 0, 0, 0, 2, 0, 0, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 250, 0, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 199, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 69, 108, 101, 109, 101, + 110, 116, 83, 105, 122, 101, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 32, 0, 0, 0, 1, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 89, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 65, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, + 61, 0, 0, 0, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 90, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 101, 109, 112, 116, 121, 0, 0, 0, + 98, 105, 116, 0, 0, 0, 0, 0, + 98, 121, 116, 101, 0, 0, 0, 0, + 116, 119, 111, 66, 121, 116, 101, 115, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 111, 117, 114, 66, 121, 116, 101, + 115, 0, 0, 0, 0, 0, 0, 0, + 101, 105, 103, 104, 116, 66, 121, 116, + 101, 115, 0, 0, 0, 0, 0, 0, + 112, 111, 105, 110, 116, 101, 114, 0, + 105, 110, 108, 105, 110, 101, 67, 111, + 109, 112, 111, 115, 105, 116, 101, 0, } +}; +::capnp::word const* const bp_d1958f7dba521926 = b_d1958f7dba521926.words; +#if !CAPNP_LITE +static const uint16_t m_d1958f7dba521926[] = {1, 2, 5, 0, 4, 7, 6, 3}; +const ::capnp::_::RawSchema s_d1958f7dba521926 = { + 0xd1958f7dba521926, b_d1958f7dba521926.words, 54, nullptr, m_d1958f7dba521926, + 0, 8, nullptr, nullptr, nullptr, { &s_d1958f7dba521926, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +CAPNP_DEFINE_ENUM(ElementSize_d1958f7dba521926, d1958f7dba521926); +static const ::capnp::_::AlignedData<63> b_d85d305b7d839963 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 99, 153, 131, 125, 91, 48, 93, 216, + 19, 0, 0, 0, 1, 0, 1, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 2, 1, 0, 0, + 33, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 29, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 67, 97, 112, 110, 112, + 86, 101, 114, 115, 105, 111, 110, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 68, 0, 0, 0, 3, 0, 1, 0, + 80, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 77, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 109, 97, 106, 111, 114, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 109, 105, 110, 111, 114, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 109, 105, 99, 114, 111, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_d85d305b7d839963 = b_d85d305b7d839963.words; +#if !CAPNP_LITE +static const uint16_t m_d85d305b7d839963[] = {0, 2, 1}; +static const uint16_t i_d85d305b7d839963[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_d85d305b7d839963 = { + 0xd85d305b7d839963, b_d85d305b7d839963.words, 63, nullptr, m_d85d305b7d839963, + 0, 3, i_d85d305b7d839963, nullptr, nullptr, { &s_d85d305b7d839963, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<78> b_bfc546f6210ad7ce = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 206, 215, 10, 33, 246, 70, 197, 191, + 19, 0, 0, 0, 1, 0, 0, 0, + 217, 114, 76, 98, 9, 197, 63, 169, + 3, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 66, 1, 0, 0, + 37, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 49, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 67, 111, 100, 101, 71, + 101, 110, 101, 114, 97, 116, 111, 114, + 82, 101, 113, 117, 101, 115, 116, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 98, 0, 129, 46, 176, 14, 234, 207, + 1, 0, 0, 0, 114, 0, 0, 0, + 82, 101, 113, 117, 101, 115, 116, 101, + 100, 70, 105, 108, 101, 0, 0, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 92, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 89, 0, 0, 0, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 0, 0, 0, 3, 0, 1, 0, + 116, 0, 0, 0, 2, 0, 1, 0, + 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 113, 0, 0, 0, 106, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 112, 0, 0, 0, 3, 0, 1, 0, + 124, 0, 0, 0, 2, 0, 1, 0, + 110, 111, 100, 101, 115, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 23, 164, 35, 249, 76, 171, 130, 230, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 114, 101, 113, 117, 101, 115, 116, 101, + 100, 70, 105, 108, 101, 115, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 98, 0, 129, 46, 176, 14, 234, 207, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 86, 101, 114, + 115, 105, 111, 110, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 99, 153, 131, 125, 91, 48, 93, 216, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_bfc546f6210ad7ce = b_bfc546f6210ad7ce.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_bfc546f6210ad7ce[] = { + &s_cfea0eb02e810062, + &s_d85d305b7d839963, + &s_e682ab4cf923a417, +}; +static const uint16_t m_bfc546f6210ad7ce[] = {2, 0, 1}; +static const uint16_t i_bfc546f6210ad7ce[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_bfc546f6210ad7ce = { + 0xbfc546f6210ad7ce, b_bfc546f6210ad7ce.words, 78, d_bfc546f6210ad7ce, m_bfc546f6210ad7ce, + 3, 3, i_bfc546f6210ad7ce, nullptr, nullptr, { &s_bfc546f6210ad7ce, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<74> b_cfea0eb02e810062 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 98, 0, 129, 46, 176, 14, 234, 207, + 40, 0, 0, 0, 1, 0, 1, 0, + 206, 215, 10, 33, 246, 70, 197, 191, + 2, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 178, 1, 0, 0, + 45, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 175, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 67, 111, 100, 101, 71, + 101, 110, 101, 114, 97, 116, 111, 114, + 82, 101, 113, 117, 101, 115, 116, 46, + 82, 101, 113, 117, 101, 115, 116, 101, + 100, 70, 105, 108, 101, 0, 0, 0, + 4, 0, 0, 0, 1, 0, 1, 0, + 229, 87, 35, 18, 147, 65, 80, 174, + 1, 0, 0, 0, 58, 0, 0, 0, + 73, 109, 112, 111, 114, 116, 0, 0, + 12, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 3, 0, 1, 0, + 76, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 3, 0, 1, 0, + 84, 0, 0, 0, 2, 0, 1, 0, + 2, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 81, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 76, 0, 0, 0, 3, 0, 1, 0, + 104, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 102, 105, 108, 101, 110, 97, 109, 101, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 105, 109, 112, 111, 114, 116, 115, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 1, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 229, 87, 35, 18, 147, 65, 80, 174, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_cfea0eb02e810062 = b_cfea0eb02e810062.words; +#if !CAPNP_LITE +static const ::capnp::_::RawSchema* const d_cfea0eb02e810062[] = { + &s_ae504193122357e5, +}; +static const uint16_t m_cfea0eb02e810062[] = {1, 0, 2}; +static const uint16_t i_cfea0eb02e810062[] = {0, 1, 2}; +const ::capnp::_::RawSchema s_cfea0eb02e810062 = { + 0xcfea0eb02e810062, b_cfea0eb02e810062.words, 74, d_cfea0eb02e810062, m_cfea0eb02e810062, + 1, 3, i_cfea0eb02e810062, nullptr, nullptr, { &s_cfea0eb02e810062, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +static const ::capnp::_::AlignedData<52> b_ae504193122357e5 = { + { 0, 0, 0, 0, 5, 0, 6, 0, + 229, 87, 35, 18, 147, 65, 80, 174, + 54, 0, 0, 0, 1, 0, 1, 0, + 98, 0, 129, 46, 176, 14, 234, 207, + 1, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 0, 0, 234, 1, 0, 0, + 49, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 99, 97, 112, 110, 112, 47, 115, 99, + 104, 101, 109, 97, 46, 99, 97, 112, + 110, 112, 58, 67, 111, 100, 101, 71, + 101, 110, 101, 114, 97, 116, 111, 114, + 82, 101, 113, 117, 101, 115, 116, 46, + 82, 101, 113, 117, 101, 115, 116, 101, + 100, 70, 105, 108, 101, 46, 73, 109, + 112, 111, 114, 116, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, + 8, 0, 0, 0, 3, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 41, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 3, 0, 1, 0, + 48, 0, 0, 0, 2, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 40, 0, 0, 0, 3, 0, 1, 0, + 52, 0, 0, 0, 2, 0, 1, 0, + 105, 100, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 110, 97, 109, 101, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, } +}; +::capnp::word const* const bp_ae504193122357e5 = b_ae504193122357e5.words; +#if !CAPNP_LITE +static const uint16_t m_ae504193122357e5[] = {0, 1}; +static const uint16_t i_ae504193122357e5[] = {0, 1}; +const ::capnp::_::RawSchema s_ae504193122357e5 = { + 0xae504193122357e5, b_ae504193122357e5.words, 52, nullptr, m_ae504193122357e5, + 0, 2, i_ae504193122357e5, nullptr, nullptr, { &s_ae504193122357e5, nullptr, nullptr, 0, 0, nullptr } +}; +#endif // !CAPNP_LITE +} // namespace schemas +} // namespace capnp + +// ======================================================================================= + +namespace capnp { +namespace schema { + +// Node +constexpr uint16_t Node::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Parameter +constexpr uint16_t Node::Parameter::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Parameter::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Parameter::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Parameter::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::NestedNode +constexpr uint16_t Node::NestedNode::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::NestedNode::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::NestedNode::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::NestedNode::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Struct +constexpr uint16_t Node::Struct::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Struct::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Struct::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Struct::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Enum +constexpr uint16_t Node::Enum::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Enum::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Enum::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Enum::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Interface +constexpr uint16_t Node::Interface::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Interface::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Interface::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Interface::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Const +constexpr uint16_t Node::Const::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Const::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Const::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Const::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Node::Annotation +constexpr uint16_t Node::Annotation::_capnpPrivate::dataWordSize; +constexpr uint16_t Node::Annotation::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Node::Annotation::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Node::Annotation::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Field +constexpr uint16_t Field::_capnpPrivate::dataWordSize; +constexpr uint16_t Field::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Field::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Field::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +#ifndef _MSC_VER +constexpr ::uint16_t Field::NO_DISCRIMINANT; +#endif +// Field::Slot +constexpr uint16_t Field::Slot::_capnpPrivate::dataWordSize; +constexpr uint16_t Field::Slot::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Field::Slot::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Field::Slot::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Field::Group +constexpr uint16_t Field::Group::_capnpPrivate::dataWordSize; +constexpr uint16_t Field::Group::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Field::Group::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Field::Group::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Field::Ordinal +constexpr uint16_t Field::Ordinal::_capnpPrivate::dataWordSize; +constexpr uint16_t Field::Ordinal::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Field::Ordinal::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Field::Ordinal::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Enumerant +constexpr uint16_t Enumerant::_capnpPrivate::dataWordSize; +constexpr uint16_t Enumerant::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Enumerant::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Enumerant::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Superclass +constexpr uint16_t Superclass::_capnpPrivate::dataWordSize; +constexpr uint16_t Superclass::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Superclass::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Superclass::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Method +constexpr uint16_t Method::_capnpPrivate::dataWordSize; +constexpr uint16_t Method::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Method::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Method::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type +constexpr uint16_t Type::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::List +constexpr uint16_t Type::List::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::List::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::List::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::List::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::Enum +constexpr uint16_t Type::Enum::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::Enum::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::Enum::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::Enum::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::Struct +constexpr uint16_t Type::Struct::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::Struct::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::Struct::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::Struct::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::Interface +constexpr uint16_t Type::Interface::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::Interface::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::Interface::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::Interface::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::AnyPointer +constexpr uint16_t Type::AnyPointer::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::AnyPointer::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::AnyPointer::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::AnyPointer::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::AnyPointer::Unconstrained +constexpr uint16_t Type::AnyPointer::Unconstrained::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::AnyPointer::Unconstrained::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::AnyPointer::Unconstrained::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::AnyPointer::Unconstrained::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::AnyPointer::Parameter +constexpr uint16_t Type::AnyPointer::Parameter::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::AnyPointer::Parameter::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::AnyPointer::Parameter::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::AnyPointer::Parameter::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Type::AnyPointer::ImplicitMethodParameter +constexpr uint16_t Type::AnyPointer::ImplicitMethodParameter::_capnpPrivate::dataWordSize; +constexpr uint16_t Type::AnyPointer::ImplicitMethodParameter::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Type::AnyPointer::ImplicitMethodParameter::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Type::AnyPointer::ImplicitMethodParameter::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Brand +constexpr uint16_t Brand::_capnpPrivate::dataWordSize; +constexpr uint16_t Brand::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Brand::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Brand::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Brand::Scope +constexpr uint16_t Brand::Scope::_capnpPrivate::dataWordSize; +constexpr uint16_t Brand::Scope::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Brand::Scope::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Brand::Scope::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Brand::Binding +constexpr uint16_t Brand::Binding::_capnpPrivate::dataWordSize; +constexpr uint16_t Brand::Binding::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Brand::Binding::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Brand::Binding::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Value +constexpr uint16_t Value::_capnpPrivate::dataWordSize; +constexpr uint16_t Value::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Value::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Value::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// Annotation +constexpr uint16_t Annotation::_capnpPrivate::dataWordSize; +constexpr uint16_t Annotation::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind Annotation::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* Annotation::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// CapnpVersion +constexpr uint16_t CapnpVersion::_capnpPrivate::dataWordSize; +constexpr uint16_t CapnpVersion::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind CapnpVersion::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* CapnpVersion::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// CodeGeneratorRequest +constexpr uint16_t CodeGeneratorRequest::_capnpPrivate::dataWordSize; +constexpr uint16_t CodeGeneratorRequest::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind CodeGeneratorRequest::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* CodeGeneratorRequest::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// CodeGeneratorRequest::RequestedFile +constexpr uint16_t CodeGeneratorRequest::RequestedFile::_capnpPrivate::dataWordSize; +constexpr uint16_t CodeGeneratorRequest::RequestedFile::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind CodeGeneratorRequest::RequestedFile::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* CodeGeneratorRequest::RequestedFile::_capnpPrivate::schema; +#endif // !CAPNP_LITE + +// CodeGeneratorRequest::RequestedFile::Import +constexpr uint16_t CodeGeneratorRequest::RequestedFile::Import::_capnpPrivate::dataWordSize; +constexpr uint16_t CodeGeneratorRequest::RequestedFile::Import::_capnpPrivate::pointerCount; +#if !CAPNP_LITE +constexpr ::capnp::Kind CodeGeneratorRequest::RequestedFile::Import::_capnpPrivate::kind; +constexpr ::capnp::_::RawSchema const* CodeGeneratorRequest::RequestedFile::Import::_capnpPrivate::schema; +#endif // !CAPNP_LITE + + +} // namespace +} // namespace + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema.capnp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema.capnp.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,7861 @@ +// Generated by Cap'n Proto compiler, DO NOT EDIT +// source: schema.capnp + +#ifndef CAPNP_INCLUDED_a93fc509624c72d9_ +#define CAPNP_INCLUDED_a93fc509624c72d9_ + +#include + +#if CAPNP_VERSION != 6000 +#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library." +#endif + + +namespace capnp { +namespace schemas { + +CAPNP_DECLARE_SCHEMA(e682ab4cf923a417); +CAPNP_DECLARE_SCHEMA(b9521bccf10fa3b1); +CAPNP_DECLARE_SCHEMA(debf55bbfa0fc242); +CAPNP_DECLARE_SCHEMA(9ea0b19b37fb4435); +CAPNP_DECLARE_SCHEMA(b54ab3364333f598); +CAPNP_DECLARE_SCHEMA(e82753cff0c2218f); +CAPNP_DECLARE_SCHEMA(b18aa5ac7a0d9420); +CAPNP_DECLARE_SCHEMA(ec1619d4400a0290); +CAPNP_DECLARE_SCHEMA(9aad50a41f4af45f); +CAPNP_DECLARE_SCHEMA(97b14cbe7cfec712); +CAPNP_DECLARE_SCHEMA(c42305476bb4746f); +CAPNP_DECLARE_SCHEMA(cafccddb68db1d11); +CAPNP_DECLARE_SCHEMA(bb90d5c287870be6); +CAPNP_DECLARE_SCHEMA(978a7cebdc549a4d); +CAPNP_DECLARE_SCHEMA(a9962a9ed0a4d7f8); +CAPNP_DECLARE_SCHEMA(9500cce23b334d80); +CAPNP_DECLARE_SCHEMA(d07378ede1f9cc60); +CAPNP_DECLARE_SCHEMA(87e739250a60ea97); +CAPNP_DECLARE_SCHEMA(9e0e78711a7f87a9); +CAPNP_DECLARE_SCHEMA(ac3a6f60ef4cc6d3); +CAPNP_DECLARE_SCHEMA(ed8bca69f7fb0cbf); +CAPNP_DECLARE_SCHEMA(c2573fe8a23e49f1); +CAPNP_DECLARE_SCHEMA(8e3b5f79fe593656); +CAPNP_DECLARE_SCHEMA(9dd1f724f4614a85); +CAPNP_DECLARE_SCHEMA(baefc9120c56e274); +CAPNP_DECLARE_SCHEMA(903455f06065422b); +CAPNP_DECLARE_SCHEMA(abd73485a9636bc9); +CAPNP_DECLARE_SCHEMA(c863cd16969ee7fc); +CAPNP_DECLARE_SCHEMA(ce23dcd2d7b00c9b); +CAPNP_DECLARE_SCHEMA(f1c8950dab257542); +CAPNP_DECLARE_SCHEMA(d1958f7dba521926); +enum class ElementSize_d1958f7dba521926: uint16_t { + EMPTY, + BIT, + BYTE, + TWO_BYTES, + FOUR_BYTES, + EIGHT_BYTES, + POINTER, + INLINE_COMPOSITE, +}; +CAPNP_DECLARE_ENUM(ElementSize, d1958f7dba521926); +CAPNP_DECLARE_SCHEMA(d85d305b7d839963); +CAPNP_DECLARE_SCHEMA(bfc546f6210ad7ce); +CAPNP_DECLARE_SCHEMA(cfea0eb02e810062); +CAPNP_DECLARE_SCHEMA(ae504193122357e5); + +} // namespace schemas +} // namespace capnp + +namespace capnp { +namespace schema { + +struct Node { + Node() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + FILE, + STRUCT, + ENUM, + INTERFACE, + CONST, + ANNOTATION, + }; + struct Parameter; + struct NestedNode; + struct Struct; + struct Enum; + struct Interface; + struct Const; + struct Annotation; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e682ab4cf923a417, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Parameter { + Parameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b9521bccf10fa3b1, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::NestedNode { + NestedNode() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(debf55bbfa0fc242, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Struct { + Struct() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9ea0b19b37fb4435, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Enum { + Enum() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b54ab3364333f598, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Interface { + Interface() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(e82753cff0c2218f, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Const { + Const() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(b18aa5ac7a0d9420, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Node::Annotation { + Annotation() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ec1619d4400a0290, 5, 6) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field { + Field() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + SLOT, + GROUP, + }; + static constexpr ::uint16_t NO_DISCRIMINANT = 65535u; + struct Slot; + struct Group; + struct Ordinal; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9aad50a41f4af45f, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Slot { + Slot() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c42305476bb4746f, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Group { + Group() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(cafccddb68db1d11, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Field::Ordinal { + Ordinal() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + IMPLICIT, + EXPLICIT, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bb90d5c287870be6, 3, 4) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Enumerant { + Enumerant() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(978a7cebdc549a4d, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Superclass { + Superclass() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(a9962a9ed0a4d7f8, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Method { + Method() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9500cce23b334d80, 3, 5) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type { + Type() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + VOID, + BOOL, + INT8, + INT16, + INT32, + INT64, + UINT8, + UINT16, + UINT32, + UINT64, + FLOAT32, + FLOAT64, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + INTERFACE, + ANY_POINTER, + }; + struct List; + struct Enum; + struct Struct; + struct Interface; + struct AnyPointer; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d07378ede1f9cc60, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::List { + List() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(87e739250a60ea97, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Enum { + Enum() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9e0e78711a7f87a9, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Struct { + Struct() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ac3a6f60ef4cc6d3, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::Interface { + Interface() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ed8bca69f7fb0cbf, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer { + AnyPointer() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNCONSTRAINED, + PARAMETER, + IMPLICIT_METHOD_PARAMETER, + }; + struct Unconstrained; + struct Parameter; + struct ImplicitMethodParameter; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c2573fe8a23e49f1, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::Unconstrained { + Unconstrained() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + ANY_KIND, + STRUCT, + LIST, + CAPABILITY, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(8e3b5f79fe593656, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::Parameter { + Parameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(9dd1f724f4614a85, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Type::AnyPointer::ImplicitMethodParameter { + ImplicitMethodParameter() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(baefc9120c56e274, 3, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand { + Brand() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Scope; + struct Binding; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(903455f06065422b, 0, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand::Scope { + Scope() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + BIND, + INHERIT, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(abd73485a9636bc9, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Brand::Binding { + Binding() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + UNBOUND, + TYPE, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(c863cd16969ee7fc, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Value { + Value() = delete; + + class Reader; + class Builder; + class Pipeline; + enum Which: uint16_t { + VOID, + BOOL, + INT8, + INT16, + INT32, + INT64, + UINT8, + UINT16, + UINT32, + UINT64, + FLOAT32, + FLOAT64, + TEXT, + DATA, + LIST, + ENUM, + STRUCT, + INTERFACE, + ANY_POINTER, + }; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ce23dcd2d7b00c9b, 2, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct Annotation { + Annotation() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(f1c8950dab257542, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +typedef ::capnp::schemas::ElementSize_d1958f7dba521926 ElementSize; + +struct CapnpVersion { + CapnpVersion() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(d85d305b7d839963, 1, 0) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest { + CodeGeneratorRequest() = delete; + + class Reader; + class Builder; + class Pipeline; + struct RequestedFile; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(bfc546f6210ad7ce, 0, 3) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest::RequestedFile { + RequestedFile() = delete; + + class Reader; + class Builder; + class Pipeline; + struct Import; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(cfea0eb02e810062, 1, 2) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +struct CodeGeneratorRequest::RequestedFile::Import { + Import() = delete; + + class Reader; + class Builder; + class Pipeline; + + struct _capnpPrivate { + CAPNP_DECLARE_STRUCT_HEADER(ae504193122357e5, 1, 1) + #if !CAPNP_LITE + static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; } + #endif // !CAPNP_LITE + }; +}; + +// ======================================================================================= + +class Node::Reader { +public: + typedef Node Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint64_t getId() const; + + inline bool hasDisplayName() const; + inline ::capnp::Text::Reader getDisplayName() const; + + inline ::uint32_t getDisplayNamePrefixLength() const; + + inline ::uint64_t getScopeId() const; + + inline bool hasNestedNodes() const; + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader getNestedNodes() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline bool isFile() const; + inline ::capnp::Void getFile() const; + + inline bool isStruct() const; + inline typename Struct::Reader getStruct() const; + + inline bool isEnum() const; + inline typename Enum::Reader getEnum() const; + + inline bool isInterface() const; + inline typename Interface::Reader getInterface() const; + + inline bool isConst() const; + inline typename Const::Reader getConst() const; + + inline bool isAnnotation() const; + inline typename Annotation::Reader getAnnotation() const; + + inline bool hasParameters() const; + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getParameters() const; + + inline bool getIsGeneric() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Builder { +public: + typedef Node Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasDisplayName(); + inline ::capnp::Text::Builder getDisplayName(); + inline void setDisplayName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initDisplayName(unsigned int size); + inline void adoptDisplayName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownDisplayName(); + + inline ::uint32_t getDisplayNamePrefixLength(); + inline void setDisplayNamePrefixLength( ::uint32_t value); + + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline bool hasNestedNodes(); + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder getNestedNodes(); + inline void setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder initNestedNodes(unsigned int size); + inline void adoptNestedNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> disownNestedNodes(); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline bool isFile(); + inline ::capnp::Void getFile(); + inline void setFile( ::capnp::Void value = ::capnp::VOID); + + inline bool isStruct(); + inline typename Struct::Builder getStruct(); + inline typename Struct::Builder initStruct(); + + inline bool isEnum(); + inline typename Enum::Builder getEnum(); + inline typename Enum::Builder initEnum(); + + inline bool isInterface(); + inline typename Interface::Builder getInterface(); + inline typename Interface::Builder initInterface(); + + inline bool isConst(); + inline typename Const::Builder getConst(); + inline typename Const::Builder initConst(); + + inline bool isAnnotation(); + inline typename Annotation::Builder getAnnotation(); + inline typename Annotation::Builder initAnnotation(); + + inline bool hasParameters(); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getParameters(); + inline void setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initParameters(unsigned int size); + inline void adoptParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownParameters(); + + inline bool getIsGeneric(); + inline void setIsGeneric(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Pipeline { +public: + typedef Node Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Parameter::Reader { +public: + typedef Parameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Parameter::Builder { +public: + typedef Parameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Parameter::Pipeline { +public: + typedef Parameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::NestedNode::Reader { +public: + typedef NestedNode Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint64_t getId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::NestedNode::Builder { +public: + typedef NestedNode Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::NestedNode::Pipeline { +public: + typedef NestedNode Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Struct::Reader { +public: + typedef Struct Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getDataWordCount() const; + + inline ::uint16_t getPointerCount() const; + + inline ::capnp::schema::ElementSize getPreferredListEncoding() const; + + inline bool getIsGroup() const; + + inline ::uint16_t getDiscriminantCount() const; + + inline ::uint32_t getDiscriminantOffset() const; + + inline bool hasFields() const; + inline ::capnp::List< ::capnp::schema::Field>::Reader getFields() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Struct::Builder { +public: + typedef Struct Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getDataWordCount(); + inline void setDataWordCount( ::uint16_t value); + + inline ::uint16_t getPointerCount(); + inline void setPointerCount( ::uint16_t value); + + inline ::capnp::schema::ElementSize getPreferredListEncoding(); + inline void setPreferredListEncoding( ::capnp::schema::ElementSize value); + + inline bool getIsGroup(); + inline void setIsGroup(bool value); + + inline ::uint16_t getDiscriminantCount(); + inline void setDiscriminantCount( ::uint16_t value); + + inline ::uint32_t getDiscriminantOffset(); + inline void setDiscriminantOffset( ::uint32_t value); + + inline bool hasFields(); + inline ::capnp::List< ::capnp::schema::Field>::Builder getFields(); + inline void setFields( ::capnp::List< ::capnp::schema::Field>::Reader value); + inline ::capnp::List< ::capnp::schema::Field>::Builder initFields(unsigned int size); + inline void adoptFields(::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> disownFields(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Struct::Pipeline { +public: + typedef Struct Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Enum::Reader { +public: + typedef Enum Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasEnumerants() const; + inline ::capnp::List< ::capnp::schema::Enumerant>::Reader getEnumerants() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Enum::Builder { +public: + typedef Enum Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasEnumerants(); + inline ::capnp::List< ::capnp::schema::Enumerant>::Builder getEnumerants(); + inline void setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value); + inline ::capnp::List< ::capnp::schema::Enumerant>::Builder initEnumerants(unsigned int size); + inline void adoptEnumerants(::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> disownEnumerants(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Enum::Pipeline { +public: + typedef Enum Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Interface::Reader { +public: + typedef Interface Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasMethods() const; + inline ::capnp::List< ::capnp::schema::Method>::Reader getMethods() const; + + inline bool hasSuperclasses() const; + inline ::capnp::List< ::capnp::schema::Superclass>::Reader getSuperclasses() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Interface::Builder { +public: + typedef Interface Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasMethods(); + inline ::capnp::List< ::capnp::schema::Method>::Builder getMethods(); + inline void setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value); + inline ::capnp::List< ::capnp::schema::Method>::Builder initMethods(unsigned int size); + inline void adoptMethods(::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> disownMethods(); + + inline bool hasSuperclasses(); + inline ::capnp::List< ::capnp::schema::Superclass>::Builder getSuperclasses(); + inline void setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value); + inline ::capnp::List< ::capnp::schema::Superclass>::Builder initSuperclasses(unsigned int size); + inline void adoptSuperclasses(::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> disownSuperclasses(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Interface::Pipeline { +public: + typedef Interface Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Const::Reader { +public: + typedef Const Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool hasValue() const; + inline ::capnp::schema::Value::Reader getValue() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Const::Builder { +public: + typedef Const Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool hasValue(); + inline ::capnp::schema::Value::Builder getValue(); + inline void setValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Const::Pipeline { +public: + typedef Const Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); + inline ::capnp::schema::Value::Pipeline getValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Node::Annotation::Reader { +public: + typedef Annotation Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool getTargetsFile() const; + + inline bool getTargetsConst() const; + + inline bool getTargetsEnum() const; + + inline bool getTargetsEnumerant() const; + + inline bool getTargetsStruct() const; + + inline bool getTargetsField() const; + + inline bool getTargetsUnion() const; + + inline bool getTargetsGroup() const; + + inline bool getTargetsInterface() const; + + inline bool getTargetsMethod() const; + + inline bool getTargetsParam() const; + + inline bool getTargetsAnnotation() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Node::Annotation::Builder { +public: + typedef Annotation Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool getTargetsFile(); + inline void setTargetsFile(bool value); + + inline bool getTargetsConst(); + inline void setTargetsConst(bool value); + + inline bool getTargetsEnum(); + inline void setTargetsEnum(bool value); + + inline bool getTargetsEnumerant(); + inline void setTargetsEnumerant(bool value); + + inline bool getTargetsStruct(); + inline void setTargetsStruct(bool value); + + inline bool getTargetsField(); + inline void setTargetsField(bool value); + + inline bool getTargetsUnion(); + inline void setTargetsUnion(bool value); + + inline bool getTargetsGroup(); + inline void setTargetsGroup(bool value); + + inline bool getTargetsInterface(); + inline void setTargetsInterface(bool value); + + inline bool getTargetsMethod(); + inline void setTargetsMethod(bool value); + + inline bool getTargetsParam(); + inline void setTargetsParam(bool value); + + inline bool getTargetsAnnotation(); + inline void setTargetsAnnotation(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Node::Annotation::Pipeline { +public: + typedef Annotation Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Reader { +public: + typedef Field Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline ::uint16_t getDiscriminantValue() const; + + inline bool isSlot() const; + inline typename Slot::Reader getSlot() const; + + inline bool isGroup() const; + inline typename Group::Reader getGroup() const; + + inline typename Ordinal::Reader getOrdinal() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Builder { +public: + typedef Field Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline ::uint16_t getDiscriminantValue(); + inline void setDiscriminantValue( ::uint16_t value); + + inline bool isSlot(); + inline typename Slot::Builder getSlot(); + inline typename Slot::Builder initSlot(); + + inline bool isGroup(); + inline typename Group::Builder getGroup(); + inline typename Group::Builder initGroup(); + + inline typename Ordinal::Builder getOrdinal(); + inline typename Ordinal::Builder initOrdinal(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Pipeline { +public: + typedef Field Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline typename Ordinal::Pipeline getOrdinal(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Slot::Reader { +public: + typedef Slot Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint32_t getOffset() const; + + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + + inline bool hasDefaultValue() const; + inline ::capnp::schema::Value::Reader getDefaultValue() const; + + inline bool getHadExplicitDefault() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Slot::Builder { +public: + typedef Slot Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint32_t getOffset(); + inline void setOffset( ::uint32_t value); + + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + + inline bool hasDefaultValue(); + inline ::capnp::schema::Value::Builder getDefaultValue(); + inline void setDefaultValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initDefaultValue(); + inline void adoptDefaultValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownDefaultValue(); + + inline bool getHadExplicitDefault(); + inline void setHadExplicitDefault(bool value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Slot::Pipeline { +public: + typedef Slot Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getType(); + inline ::capnp::schema::Value::Pipeline getDefaultValue(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Group::Reader { +public: + typedef Group Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Group::Builder { +public: + typedef Group Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Group::Pipeline { +public: + typedef Group Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Field::Ordinal::Reader { +public: + typedef Ordinal Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isImplicit() const; + inline ::capnp::Void getImplicit() const; + + inline bool isExplicit() const; + inline ::uint16_t getExplicit() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Field::Ordinal::Builder { +public: + typedef Ordinal Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isImplicit(); + inline ::capnp::Void getImplicit(); + inline void setImplicit( ::capnp::Void value = ::capnp::VOID); + + inline bool isExplicit(); + inline ::uint16_t getExplicit(); + inline void setExplicit( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Field::Ordinal::Pipeline { +public: + typedef Ordinal Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Enumerant::Reader { +public: + typedef Enumerant Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Enumerant::Builder { +public: + typedef Enumerant Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Enumerant::Pipeline { +public: + typedef Enumerant Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Superclass::Reader { +public: + typedef Superclass Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Superclass::Builder { +public: + typedef Superclass Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Superclass::Pipeline { +public: + typedef Superclass Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Method::Reader { +public: + typedef Method Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + + inline ::uint16_t getCodeOrder() const; + + inline ::uint64_t getParamStructType() const; + + inline ::uint64_t getResultStructType() const; + + inline bool hasAnnotations() const; + inline ::capnp::List< ::capnp::schema::Annotation>::Reader getAnnotations() const; + + inline bool hasParamBrand() const; + inline ::capnp::schema::Brand::Reader getParamBrand() const; + + inline bool hasResultBrand() const; + inline ::capnp::schema::Brand::Reader getResultBrand() const; + + inline bool hasImplicitParameters() const; + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader getImplicitParameters() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Method::Builder { +public: + typedef Method Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + + inline ::uint16_t getCodeOrder(); + inline void setCodeOrder( ::uint16_t value); + + inline ::uint64_t getParamStructType(); + inline void setParamStructType( ::uint64_t value); + + inline ::uint64_t getResultStructType(); + inline void setResultStructType( ::uint64_t value); + + inline bool hasAnnotations(); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder getAnnotations(); + inline void setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value); + inline ::capnp::List< ::capnp::schema::Annotation>::Builder initAnnotations(unsigned int size); + inline void adoptAnnotations(::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> disownAnnotations(); + + inline bool hasParamBrand(); + inline ::capnp::schema::Brand::Builder getParamBrand(); + inline void setParamBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initParamBrand(); + inline void adoptParamBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownParamBrand(); + + inline bool hasResultBrand(); + inline ::capnp::schema::Brand::Builder getResultBrand(); + inline void setResultBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initResultBrand(); + inline void adoptResultBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownResultBrand(); + + inline bool hasImplicitParameters(); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder getImplicitParameters(); + inline void setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value); + inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder initImplicitParameters(unsigned int size); + inline void adoptImplicitParameters(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> disownImplicitParameters(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Method::Pipeline { +public: + typedef Method Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getParamBrand(); + inline ::capnp::schema::Brand::Pipeline getResultBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Reader { +public: + typedef Type Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isVoid() const; + inline ::capnp::Void getVoid() const; + + inline bool isBool() const; + inline ::capnp::Void getBool() const; + + inline bool isInt8() const; + inline ::capnp::Void getInt8() const; + + inline bool isInt16() const; + inline ::capnp::Void getInt16() const; + + inline bool isInt32() const; + inline ::capnp::Void getInt32() const; + + inline bool isInt64() const; + inline ::capnp::Void getInt64() const; + + inline bool isUint8() const; + inline ::capnp::Void getUint8() const; + + inline bool isUint16() const; + inline ::capnp::Void getUint16() const; + + inline bool isUint32() const; + inline ::capnp::Void getUint32() const; + + inline bool isUint64() const; + inline ::capnp::Void getUint64() const; + + inline bool isFloat32() const; + inline ::capnp::Void getFloat32() const; + + inline bool isFloat64() const; + inline ::capnp::Void getFloat64() const; + + inline bool isText() const; + inline ::capnp::Void getText() const; + + inline bool isData() const; + inline ::capnp::Void getData() const; + + inline bool isList() const; + inline typename List::Reader getList() const; + + inline bool isEnum() const; + inline typename Enum::Reader getEnum() const; + + inline bool isStruct() const; + inline typename Struct::Reader getStruct() const; + + inline bool isInterface() const; + inline typename Interface::Reader getInterface() const; + + inline bool isAnyPointer() const; + inline typename AnyPointer::Reader getAnyPointer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Builder { +public: + typedef Type Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isVoid(); + inline ::capnp::Void getVoid(); + inline void setVoid( ::capnp::Void value = ::capnp::VOID); + + inline bool isBool(); + inline ::capnp::Void getBool(); + inline void setBool( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt8(); + inline ::capnp::Void getInt8(); + inline void setInt8( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt16(); + inline ::capnp::Void getInt16(); + inline void setInt16( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt32(); + inline ::capnp::Void getInt32(); + inline void setInt32( ::capnp::Void value = ::capnp::VOID); + + inline bool isInt64(); + inline ::capnp::Void getInt64(); + inline void setInt64( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint8(); + inline ::capnp::Void getUint8(); + inline void setUint8( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint16(); + inline ::capnp::Void getUint16(); + inline void setUint16( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint32(); + inline ::capnp::Void getUint32(); + inline void setUint32( ::capnp::Void value = ::capnp::VOID); + + inline bool isUint64(); + inline ::capnp::Void getUint64(); + inline void setUint64( ::capnp::Void value = ::capnp::VOID); + + inline bool isFloat32(); + inline ::capnp::Void getFloat32(); + inline void setFloat32( ::capnp::Void value = ::capnp::VOID); + + inline bool isFloat64(); + inline ::capnp::Void getFloat64(); + inline void setFloat64( ::capnp::Void value = ::capnp::VOID); + + inline bool isText(); + inline ::capnp::Void getText(); + inline void setText( ::capnp::Void value = ::capnp::VOID); + + inline bool isData(); + inline ::capnp::Void getData(); + inline void setData( ::capnp::Void value = ::capnp::VOID); + + inline bool isList(); + inline typename List::Builder getList(); + inline typename List::Builder initList(); + + inline bool isEnum(); + inline typename Enum::Builder getEnum(); + inline typename Enum::Builder initEnum(); + + inline bool isStruct(); + inline typename Struct::Builder getStruct(); + inline typename Struct::Builder initStruct(); + + inline bool isInterface(); + inline typename Interface::Builder getInterface(); + inline typename Interface::Builder initInterface(); + + inline bool isAnyPointer(); + inline typename AnyPointer::Builder getAnyPointer(); + inline typename AnyPointer::Builder initAnyPointer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Pipeline { +public: + typedef Type Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::List::Reader { +public: + typedef List Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasElementType() const; + inline ::capnp::schema::Type::Reader getElementType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::List::Builder { +public: + typedef List Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasElementType(); + inline ::capnp::schema::Type::Builder getElementType(); + inline void setElementType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initElementType(); + inline void adoptElementType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownElementType(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::List::Pipeline { +public: + typedef List Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Type::Pipeline getElementType(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Enum::Reader { +public: + typedef Enum Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Enum::Builder { +public: + typedef Enum Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Enum::Pipeline { +public: + typedef Enum Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Struct::Reader { +public: + typedef Struct Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Struct::Builder { +public: + typedef Struct Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Struct::Pipeline { +public: + typedef Struct Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::Interface::Reader { +public: + typedef Interface Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::Interface::Builder { +public: + typedef Interface Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getTypeId(); + inline void setTypeId( ::uint64_t value); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::Interface::Pipeline { +public: + typedef Interface Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Reader { +public: + typedef AnyPointer Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnconstrained() const; + inline typename Unconstrained::Reader getUnconstrained() const; + + inline bool isParameter() const; + inline typename Parameter::Reader getParameter() const; + + inline bool isImplicitMethodParameter() const; + inline typename ImplicitMethodParameter::Reader getImplicitMethodParameter() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Builder { +public: + typedef AnyPointer Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnconstrained(); + inline typename Unconstrained::Builder getUnconstrained(); + inline typename Unconstrained::Builder initUnconstrained(); + + inline bool isParameter(); + inline typename Parameter::Builder getParameter(); + inline typename Parameter::Builder initParameter(); + + inline bool isImplicitMethodParameter(); + inline typename ImplicitMethodParameter::Builder getImplicitMethodParameter(); + inline typename ImplicitMethodParameter::Builder initImplicitMethodParameter(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Pipeline { +public: + typedef AnyPointer Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Unconstrained::Reader { +public: + typedef Unconstrained Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isAnyKind() const; + inline ::capnp::Void getAnyKind() const; + + inline bool isStruct() const; + inline ::capnp::Void getStruct() const; + + inline bool isList() const; + inline ::capnp::Void getList() const; + + inline bool isCapability() const; + inline ::capnp::Void getCapability() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Unconstrained::Builder { +public: + typedef Unconstrained Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isAnyKind(); + inline ::capnp::Void getAnyKind(); + inline void setAnyKind( ::capnp::Void value = ::capnp::VOID); + + inline bool isStruct(); + inline ::capnp::Void getStruct(); + inline void setStruct( ::capnp::Void value = ::capnp::VOID); + + inline bool isList(); + inline ::capnp::Void getList(); + inline void setList( ::capnp::Void value = ::capnp::VOID); + + inline bool isCapability(); + inline ::capnp::Void getCapability(); + inline void setCapability( ::capnp::Void value = ::capnp::VOID); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Unconstrained::Pipeline { +public: + typedef Unconstrained Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::Parameter::Reader { +public: + typedef Parameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getScopeId() const; + + inline ::uint16_t getParameterIndex() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::Parameter::Builder { +public: + typedef Parameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline ::uint16_t getParameterIndex(); + inline void setParameterIndex( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::Parameter::Pipeline { +public: + typedef Parameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Type::AnyPointer::ImplicitMethodParameter::Reader { +public: + typedef ImplicitMethodParameter Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getParameterIndex() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Type::AnyPointer::ImplicitMethodParameter::Builder { +public: + typedef ImplicitMethodParameter Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getParameterIndex(); + inline void setParameterIndex( ::uint16_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Type::AnyPointer::ImplicitMethodParameter::Pipeline { +public: + typedef ImplicitMethodParameter Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Reader { +public: + typedef Brand Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasScopes() const; + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader getScopes() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Builder { +public: + typedef Brand Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasScopes(); + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder getScopes(); + inline void setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value); + inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder initScopes(unsigned int size); + inline void adoptScopes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> disownScopes(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Pipeline { +public: + typedef Brand Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Scope::Reader { +public: + typedef Scope Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline ::uint64_t getScopeId() const; + + inline bool isBind() const; + inline bool hasBind() const; + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader getBind() const; + + inline bool isInherit() const; + inline ::capnp::Void getInherit() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Scope::Builder { +public: + typedef Scope Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline ::uint64_t getScopeId(); + inline void setScopeId( ::uint64_t value); + + inline bool isBind(); + inline bool hasBind(); + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder getBind(); + inline void setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value); + inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder initBind(unsigned int size); + inline void adoptBind(::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> disownBind(); + + inline bool isInherit(); + inline ::capnp::Void getInherit(); + inline void setInherit( ::capnp::Void value = ::capnp::VOID); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Scope::Pipeline { +public: + typedef Scope Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Brand::Binding::Reader { +public: + typedef Binding Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isUnbound() const; + inline ::capnp::Void getUnbound() const; + + inline bool isType() const; + inline bool hasType() const; + inline ::capnp::schema::Type::Reader getType() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Brand::Binding::Builder { +public: + typedef Binding Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isUnbound(); + inline ::capnp::Void getUnbound(); + inline void setUnbound( ::capnp::Void value = ::capnp::VOID); + + inline bool isType(); + inline bool hasType(); + inline ::capnp::schema::Type::Builder getType(); + inline void setType( ::capnp::schema::Type::Reader value); + inline ::capnp::schema::Type::Builder initType(); + inline void adoptType(::capnp::Orphan< ::capnp::schema::Type>&& value); + inline ::capnp::Orphan< ::capnp::schema::Type> disownType(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Brand::Binding::Pipeline { +public: + typedef Binding Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Value::Reader { +public: + typedef Value Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline Which which() const; + inline bool isVoid() const; + inline ::capnp::Void getVoid() const; + + inline bool isBool() const; + inline bool getBool() const; + + inline bool isInt8() const; + inline ::int8_t getInt8() const; + + inline bool isInt16() const; + inline ::int16_t getInt16() const; + + inline bool isInt32() const; + inline ::int32_t getInt32() const; + + inline bool isInt64() const; + inline ::int64_t getInt64() const; + + inline bool isUint8() const; + inline ::uint8_t getUint8() const; + + inline bool isUint16() const; + inline ::uint16_t getUint16() const; + + inline bool isUint32() const; + inline ::uint32_t getUint32() const; + + inline bool isUint64() const; + inline ::uint64_t getUint64() const; + + inline bool isFloat32() const; + inline float getFloat32() const; + + inline bool isFloat64() const; + inline double getFloat64() const; + + inline bool isText() const; + inline bool hasText() const; + inline ::capnp::Text::Reader getText() const; + + inline bool isData() const; + inline bool hasData() const; + inline ::capnp::Data::Reader getData() const; + + inline bool isList() const; + inline bool hasList() const; + inline ::capnp::AnyPointer::Reader getList() const; + + inline bool isEnum() const; + inline ::uint16_t getEnum() const; + + inline bool isStruct() const; + inline bool hasStruct() const; + inline ::capnp::AnyPointer::Reader getStruct() const; + + inline bool isInterface() const; + inline ::capnp::Void getInterface() const; + + inline bool isAnyPointer() const; + inline bool hasAnyPointer() const; + inline ::capnp::AnyPointer::Reader getAnyPointer() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Value::Builder { +public: + typedef Value Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline Which which(); + inline bool isVoid(); + inline ::capnp::Void getVoid(); + inline void setVoid( ::capnp::Void value = ::capnp::VOID); + + inline bool isBool(); + inline bool getBool(); + inline void setBool(bool value); + + inline bool isInt8(); + inline ::int8_t getInt8(); + inline void setInt8( ::int8_t value); + + inline bool isInt16(); + inline ::int16_t getInt16(); + inline void setInt16( ::int16_t value); + + inline bool isInt32(); + inline ::int32_t getInt32(); + inline void setInt32( ::int32_t value); + + inline bool isInt64(); + inline ::int64_t getInt64(); + inline void setInt64( ::int64_t value); + + inline bool isUint8(); + inline ::uint8_t getUint8(); + inline void setUint8( ::uint8_t value); + + inline bool isUint16(); + inline ::uint16_t getUint16(); + inline void setUint16( ::uint16_t value); + + inline bool isUint32(); + inline ::uint32_t getUint32(); + inline void setUint32( ::uint32_t value); + + inline bool isUint64(); + inline ::uint64_t getUint64(); + inline void setUint64( ::uint64_t value); + + inline bool isFloat32(); + inline float getFloat32(); + inline void setFloat32(float value); + + inline bool isFloat64(); + inline double getFloat64(); + inline void setFloat64(double value); + + inline bool isText(); + inline bool hasText(); + inline ::capnp::Text::Builder getText(); + inline void setText( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initText(unsigned int size); + inline void adoptText(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownText(); + + inline bool isData(); + inline bool hasData(); + inline ::capnp::Data::Builder getData(); + inline void setData( ::capnp::Data::Reader value); + inline ::capnp::Data::Builder initData(unsigned int size); + inline void adoptData(::capnp::Orphan< ::capnp::Data>&& value); + inline ::capnp::Orphan< ::capnp::Data> disownData(); + + inline bool isList(); + inline bool hasList(); + inline ::capnp::AnyPointer::Builder getList(); + inline ::capnp::AnyPointer::Builder initList(); + + inline bool isEnum(); + inline ::uint16_t getEnum(); + inline void setEnum( ::uint16_t value); + + inline bool isStruct(); + inline bool hasStruct(); + inline ::capnp::AnyPointer::Builder getStruct(); + inline ::capnp::AnyPointer::Builder initStruct(); + + inline bool isInterface(); + inline ::capnp::Void getInterface(); + inline void setInterface( ::capnp::Void value = ::capnp::VOID); + + inline bool isAnyPointer(); + inline bool hasAnyPointer(); + inline ::capnp::AnyPointer::Builder getAnyPointer(); + inline ::capnp::AnyPointer::Builder initAnyPointer(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Value::Pipeline { +public: + typedef Value Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class Annotation::Reader { +public: + typedef Annotation Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasValue() const; + inline ::capnp::schema::Value::Reader getValue() const; + + inline bool hasBrand() const; + inline ::capnp::schema::Brand::Reader getBrand() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class Annotation::Builder { +public: + typedef Annotation Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasValue(); + inline ::capnp::schema::Value::Builder getValue(); + inline void setValue( ::capnp::schema::Value::Reader value); + inline ::capnp::schema::Value::Builder initValue(); + inline void adoptValue(::capnp::Orphan< ::capnp::schema::Value>&& value); + inline ::capnp::Orphan< ::capnp::schema::Value> disownValue(); + + inline bool hasBrand(); + inline ::capnp::schema::Brand::Builder getBrand(); + inline void setBrand( ::capnp::schema::Brand::Reader value); + inline ::capnp::schema::Brand::Builder initBrand(); + inline void adoptBrand(::capnp::Orphan< ::capnp::schema::Brand>&& value); + inline ::capnp::Orphan< ::capnp::schema::Brand> disownBrand(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class Annotation::Pipeline { +public: + typedef Annotation Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::Value::Pipeline getValue(); + inline ::capnp::schema::Brand::Pipeline getBrand(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CapnpVersion::Reader { +public: + typedef CapnpVersion Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint16_t getMajor() const; + + inline ::uint8_t getMinor() const; + + inline ::uint8_t getMicro() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CapnpVersion::Builder { +public: + typedef CapnpVersion Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint16_t getMajor(); + inline void setMajor( ::uint16_t value); + + inline ::uint8_t getMinor(); + inline void setMinor( ::uint8_t value); + + inline ::uint8_t getMicro(); + inline void setMicro( ::uint8_t value); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CapnpVersion::Pipeline { +public: + typedef CapnpVersion Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::Reader { +public: + typedef CodeGeneratorRequest Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline bool hasNodes() const; + inline ::capnp::List< ::capnp::schema::Node>::Reader getNodes() const; + + inline bool hasRequestedFiles() const; + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader getRequestedFiles() const; + + inline bool hasCapnpVersion() const; + inline ::capnp::schema::CapnpVersion::Reader getCapnpVersion() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::Builder { +public: + typedef CodeGeneratorRequest Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline bool hasNodes(); + inline ::capnp::List< ::capnp::schema::Node>::Builder getNodes(); + inline void setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value); + inline ::capnp::List< ::capnp::schema::Node>::Builder initNodes(unsigned int size); + inline void adoptNodes(::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> disownNodes(); + + inline bool hasRequestedFiles(); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder getRequestedFiles(); + inline void setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder initRequestedFiles(unsigned int size); + inline void adoptRequestedFiles(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> disownRequestedFiles(); + + inline bool hasCapnpVersion(); + inline ::capnp::schema::CapnpVersion::Builder getCapnpVersion(); + inline void setCapnpVersion( ::capnp::schema::CapnpVersion::Reader value); + inline ::capnp::schema::CapnpVersion::Builder initCapnpVersion(); + inline void adoptCapnpVersion(::capnp::Orphan< ::capnp::schema::CapnpVersion>&& value); + inline ::capnp::Orphan< ::capnp::schema::CapnpVersion> disownCapnpVersion(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::Pipeline { +public: + typedef CodeGeneratorRequest Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + + inline ::capnp::schema::CapnpVersion::Pipeline getCapnpVersion(); +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::RequestedFile::Reader { +public: + typedef RequestedFile Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasFilename() const; + inline ::capnp::Text::Reader getFilename() const; + + inline bool hasImports() const; + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader getImports() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::RequestedFile::Builder { +public: + typedef RequestedFile Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasFilename(); + inline ::capnp::Text::Builder getFilename(); + inline void setFilename( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initFilename(unsigned int size); + inline void adoptFilename(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownFilename(); + + inline bool hasImports(); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder getImports(); + inline void setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value); + inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder initImports(unsigned int size); + inline void adoptImports(::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value); + inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> disownImports(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::RequestedFile::Pipeline { +public: + typedef RequestedFile Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +class CodeGeneratorRequest::RequestedFile::Import::Reader { +public: + typedef Import Reads; + + Reader() = default; + inline explicit Reader(::capnp::_::StructReader base): _reader(base) {} + + inline ::capnp::MessageSize totalSize() const { + return _reader.totalSize().asPublic(); + } + +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { + return ::capnp::_::structString(_reader, *_capnpPrivate::brand()); + } +#endif // !CAPNP_LITE + + inline ::uint64_t getId() const; + + inline bool hasName() const; + inline ::capnp::Text::Reader getName() const; + +private: + ::capnp::_::StructReader _reader; + template + friend struct ::capnp::ToDynamic_; + template + friend struct ::capnp::_::PointerHelpers; + template + friend struct ::capnp::List; + friend class ::capnp::MessageBuilder; + friend class ::capnp::Orphanage; +}; + +class CodeGeneratorRequest::RequestedFile::Import::Builder { +public: + typedef Import Builds; + + Builder() = delete; // Deleted to discourage incorrect usage. + // You can explicitly initialize to nullptr instead. + inline Builder(decltype(nullptr)) {} + inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {} + inline operator Reader() const { return Reader(_builder.asReader()); } + inline Reader asReader() const { return *this; } + + inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); } +#if !CAPNP_LITE + inline ::kj::StringTree toString() const { return asReader().toString(); } +#endif // !CAPNP_LITE + + inline ::uint64_t getId(); + inline void setId( ::uint64_t value); + + inline bool hasName(); + inline ::capnp::Text::Builder getName(); + inline void setName( ::capnp::Text::Reader value); + inline ::capnp::Text::Builder initName(unsigned int size); + inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value); + inline ::capnp::Orphan< ::capnp::Text> disownName(); + +private: + ::capnp::_::StructBuilder _builder; + template + friend struct ::capnp::ToDynamic_; + friend class ::capnp::Orphanage; + template + friend struct ::capnp::_::PointerHelpers; +}; + +#if !CAPNP_LITE +class CodeGeneratorRequest::RequestedFile::Import::Pipeline { +public: + typedef Import Pipelines; + + inline Pipeline(decltype(nullptr)): _typeless(nullptr) {} + inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless) + : _typeless(kj::mv(typeless)) {} + +private: + ::capnp::AnyPointer::Pipeline _typeless; + friend class ::capnp::PipelineHook; + template + friend struct ::capnp::ToDynamic_; +}; +#endif // !CAPNP_LITE + +// ======================================================================================= + +inline ::capnp::schema::Node::Which Node::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Node::Which Node::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::hasDisplayName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasDisplayName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::Reader::getDisplayName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::Builder::getDisplayName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setDisplayName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::Builder::initDisplayName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptDisplayName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::Builder::disownDisplayName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint32_t Node::Reader::getDisplayNamePrefixLength() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Node::Builder::getDisplayNamePrefixLength() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setDisplayNamePrefixLength( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Node::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::hasNestedNodes() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasNestedNodes() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader Node::Reader::getNestedNodes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::getNestedNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setNestedNodes( ::capnp::List< ::capnp::schema::Node::NestedNode>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::NestedNode>::Builder Node::Builder::initNestedNodes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptNestedNodes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::NestedNode>> Node::Builder::disownNestedNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::NestedNode>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Node::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Node::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Node::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::isFile() const { + return which() == Node::FILE; +} +inline bool Node::Builder::isFile() { + return which() == Node::FILE; +} +inline ::capnp::Void Node::Reader::getFile() const { + KJ_IREQUIRE((which() == Node::FILE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Node::Builder::getFile() { + KJ_IREQUIRE((which() == Node::FILE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setFile( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::FILE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Reader::isStruct() const { + return which() == Node::STRUCT; +} +inline bool Node::Builder::isStruct() { + return which() == Node::STRUCT; +} +inline typename Node::Struct::Reader Node::Reader::getStruct() const { + KJ_IREQUIRE((which() == Node::STRUCT), + "Must check which() before get()ing a union member."); + return typename Node::Struct::Reader(_reader); +} +inline typename Node::Struct::Builder Node::Builder::getStruct() { + KJ_IREQUIRE((which() == Node::STRUCT), + "Must check which() before get()ing a union member."); + return typename Node::Struct::Builder(_builder); +} +inline typename Node::Struct::Builder Node::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::STRUCT); + _builder.setDataField< ::uint16_t>(::capnp::bounded<7>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<12>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<13>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<224>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<15>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint32_t>(::capnp::bounded<8>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Struct::Builder(_builder); +} +inline bool Node::Reader::isEnum() const { + return which() == Node::ENUM; +} +inline bool Node::Builder::isEnum() { + return which() == Node::ENUM; +} +inline typename Node::Enum::Reader Node::Reader::getEnum() const { + KJ_IREQUIRE((which() == Node::ENUM), + "Must check which() before get()ing a union member."); + return typename Node::Enum::Reader(_reader); +} +inline typename Node::Enum::Builder Node::Builder::getEnum() { + KJ_IREQUIRE((which() == Node::ENUM), + "Must check which() before get()ing a union member."); + return typename Node::Enum::Builder(_builder); +} +inline typename Node::Enum::Builder Node::Builder::initEnum() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::ENUM); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Enum::Builder(_builder); +} +inline bool Node::Reader::isInterface() const { + return which() == Node::INTERFACE; +} +inline bool Node::Builder::isInterface() { + return which() == Node::INTERFACE; +} +inline typename Node::Interface::Reader Node::Reader::getInterface() const { + KJ_IREQUIRE((which() == Node::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Node::Interface::Reader(_reader); +} +inline typename Node::Interface::Builder Node::Builder::getInterface() { + KJ_IREQUIRE((which() == Node::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Node::Interface::Builder(_builder); +} +inline typename Node::Interface::Builder Node::Builder::initInterface() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::INTERFACE); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<4>() * ::capnp::POINTERS).clear(); + return typename Node::Interface::Builder(_builder); +} +inline bool Node::Reader::isConst() const { + return which() == Node::CONST; +} +inline bool Node::Builder::isConst() { + return which() == Node::CONST; +} +inline typename Node::Const::Reader Node::Reader::getConst() const { + KJ_IREQUIRE((which() == Node::CONST), + "Must check which() before get()ing a union member."); + return typename Node::Const::Reader(_reader); +} +inline typename Node::Const::Builder Node::Builder::getConst() { + KJ_IREQUIRE((which() == Node::CONST), + "Must check which() before get()ing a union member."); + return typename Node::Const::Builder(_builder); +} +inline typename Node::Const::Builder Node::Builder::initConst() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::CONST); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<4>() * ::capnp::POINTERS).clear(); + return typename Node::Const::Builder(_builder); +} +inline bool Node::Reader::isAnnotation() const { + return which() == Node::ANNOTATION; +} +inline bool Node::Builder::isAnnotation() { + return which() == Node::ANNOTATION; +} +inline typename Node::Annotation::Reader Node::Reader::getAnnotation() const { + KJ_IREQUIRE((which() == Node::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Node::Annotation::Reader(_reader); +} +inline typename Node::Annotation::Builder Node::Builder::getAnnotation() { + KJ_IREQUIRE((which() == Node::ANNOTATION), + "Must check which() before get()ing a union member."); + return typename Node::Annotation::Builder(_builder); +} +inline typename Node::Annotation::Builder Node::Builder::initAnnotation() { + _builder.setDataField( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, Node::ANNOTATION); + _builder.setDataField(::capnp::bounded<112>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<113>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<114>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<115>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<116>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<117>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<118>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<119>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<120>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<121>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<122>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<123>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Node::Annotation::Builder(_builder); +} +inline bool Node::Reader::hasParameters() const { + return !_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Builder::hasParameters() { + return !_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Node::Reader::getParameters() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_reader.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::getParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} +inline void Node::Builder::setParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Node::Builder::initParameters(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), size); +} +inline void Node::Builder::adoptParameters( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Node::Builder::disownParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown(_builder.getPointerField( + ::capnp::bounded<5>() * ::capnp::POINTERS)); +} + +inline bool Node::Reader::getIsGeneric() const { + return _reader.getDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS); +} + +inline bool Node::Builder::getIsGeneric() { + return _builder.getDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS); +} +inline void Node::Builder::setIsGeneric(bool value) { + _builder.setDataField( + ::capnp::bounded<288>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Parameter::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Parameter::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::Parameter::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::Parameter::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::Parameter::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::Parameter::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::Parameter::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::Parameter::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Node::NestedNode::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::NestedNode::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Node::NestedNode::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Node::NestedNode::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Node::NestedNode::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Node::NestedNode::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Node::NestedNode::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Node::NestedNode::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Node::NestedNode::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Node::NestedNode::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Node::NestedNode::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getDataWordCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getDataWordCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDataWordCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<7>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getPointerCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getPointerCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setPointerCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<12>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::ElementSize Node::Struct::Reader::getPreferredListEncoding() const { + return _reader.getDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS); +} + +inline ::capnp::schema::ElementSize Node::Struct::Builder::getPreferredListEncoding() { + return _builder.getDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setPreferredListEncoding( ::capnp::schema::ElementSize value) { + _builder.setDataField< ::capnp::schema::ElementSize>( + ::capnp::bounded<13>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Struct::Reader::getIsGroup() const { + return _reader.getDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS); +} + +inline bool Node::Struct::Builder::getIsGroup() { + return _builder.getDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setIsGroup(bool value) { + _builder.setDataField( + ::capnp::bounded<224>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Node::Struct::Reader::getDiscriminantCount() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Node::Struct::Builder::getDiscriminantCount() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDiscriminantCount( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<15>() * ::capnp::ELEMENTS, value); +} + +inline ::uint32_t Node::Struct::Reader::getDiscriminantOffset() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Node::Struct::Builder::getDiscriminantOffset() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS); +} +inline void Node::Struct::Builder::setDiscriminantOffset( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<8>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Struct::Reader::hasFields() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Struct::Builder::hasFields() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Field>::Reader Node::Struct::Reader::getFields() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::getFields() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Struct::Builder::setFields( ::capnp::List< ::capnp::schema::Field>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Field>::Builder Node::Struct::Builder::initFields(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Struct::Builder::adoptFields( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Field>> Node::Struct::Builder::disownFields() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Field>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Enum::Reader::hasEnumerants() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Enum::Builder::hasEnumerants() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Reader Node::Enum::Reader::getEnumerants() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::getEnumerants() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Enum::Builder::setEnumerants( ::capnp::List< ::capnp::schema::Enumerant>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Enumerant>::Builder Node::Enum::Builder::initEnumerants(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Enum::Builder::adoptEnumerants( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Enumerant>> Node::Enum::Builder::disownEnumerants() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Enumerant>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Interface::Reader::hasMethods() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Interface::Builder::hasMethods() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Method>::Reader Node::Interface::Reader::getMethods() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::getMethods() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Interface::Builder::setMethods( ::capnp::List< ::capnp::schema::Method>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Method>::Builder Node::Interface::Builder::initMethods(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), size); +} +inline void Node::Interface::Builder::adoptMethods( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Method>> Node::Interface::Builder::disownMethods() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Method>>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Interface::Reader::hasSuperclasses() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Interface::Builder::hasSuperclasses() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Reader Node::Interface::Reader::getSuperclasses() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::getSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Node::Interface::Builder::setSuperclasses( ::capnp::List< ::capnp::schema::Superclass>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Superclass>::Builder Node::Interface::Builder::initSuperclasses(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), size); +} +inline void Node::Interface::Builder::adoptSuperclasses( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Superclass>> Node::Interface::Builder::disownSuperclasses() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Superclass>>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline bool Node::Const::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Const::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Node::Const::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Node::Const::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Node::Const::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Node::Const::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Node::Const::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Const::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Node::Const::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Const::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Const::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Node::Const::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Node::Const::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Node::Const::Pipeline::getValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(4)); +} +#endif // !CAPNP_LITE +inline void Node::Const::Builder::setValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Node::Const::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Node::Const::Builder::adoptValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Node::Const::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline bool Node::Annotation::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Node::Annotation::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Node::Annotation::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Node::Annotation::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Node::Annotation::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Node::Annotation::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Node::Annotation::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Node::Annotation::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Node::Annotation::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Node::Annotation::Reader::getTargetsFile() const { + return _reader.getDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsFile() { + return _builder.getDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsFile(bool value) { + _builder.setDataField( + ::capnp::bounded<112>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsConst() const { + return _reader.getDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsConst() { + return _builder.getDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsConst(bool value) { + _builder.setDataField( + ::capnp::bounded<113>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsEnum() const { + return _reader.getDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsEnum() { + return _builder.getDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsEnum(bool value) { + _builder.setDataField( + ::capnp::bounded<114>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsEnumerant() const { + return _reader.getDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsEnumerant() { + return _builder.getDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsEnumerant(bool value) { + _builder.setDataField( + ::capnp::bounded<115>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsStruct() const { + return _reader.getDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsStruct() { + return _builder.getDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsStruct(bool value) { + _builder.setDataField( + ::capnp::bounded<116>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsField() const { + return _reader.getDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsField() { + return _builder.getDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsField(bool value) { + _builder.setDataField( + ::capnp::bounded<117>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsUnion() const { + return _reader.getDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsUnion() { + return _builder.getDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsUnion(bool value) { + _builder.setDataField( + ::capnp::bounded<118>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsGroup() const { + return _reader.getDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsGroup() { + return _builder.getDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsGroup(bool value) { + _builder.setDataField( + ::capnp::bounded<119>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsInterface() const { + return _reader.getDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsInterface() { + return _builder.getDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsInterface(bool value) { + _builder.setDataField( + ::capnp::bounded<120>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsMethod() const { + return _reader.getDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsMethod() { + return _builder.getDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsMethod(bool value) { + _builder.setDataField( + ::capnp::bounded<121>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsParam() const { + return _reader.getDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsParam() { + return _builder.getDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsParam(bool value) { + _builder.setDataField( + ::capnp::bounded<122>() * ::capnp::ELEMENTS, value); +} + +inline bool Node::Annotation::Reader::getTargetsAnnotation() const { + return _reader.getDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS); +} + +inline bool Node::Annotation::Builder::getTargetsAnnotation() { + return _builder.getDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS); +} +inline void Node::Annotation::Builder::setTargetsAnnotation(bool value) { + _builder.setDataField( + ::capnp::bounded<123>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Field::Which Field::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Field::Which Field::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline bool Field::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Field::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Field::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Field::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Field::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Field::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Field::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Field::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Field::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Field::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Field::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Field::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Field::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Field::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Field::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Field::Reader::getDiscriminantValue() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, 65535u); +} + +inline ::uint16_t Field::Builder::getDiscriminantValue() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, 65535u); +} +inline void Field::Builder::setDiscriminantValue( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value, 65535u); +} + +inline bool Field::Reader::isSlot() const { + return which() == Field::SLOT; +} +inline bool Field::Builder::isSlot() { + return which() == Field::SLOT; +} +inline typename Field::Slot::Reader Field::Reader::getSlot() const { + KJ_IREQUIRE((which() == Field::SLOT), + "Must check which() before get()ing a union member."); + return typename Field::Slot::Reader(_reader); +} +inline typename Field::Slot::Builder Field::Builder::getSlot() { + KJ_IREQUIRE((which() == Field::SLOT), + "Must check which() before get()ing a union member."); + return typename Field::Slot::Builder(_builder); +} +inline typename Field::Slot::Builder Field::Builder::initSlot() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Field::SLOT); + _builder.setDataField< ::uint32_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.setDataField(::capnp::bounded<128>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<2>() * ::capnp::POINTERS).clear(); + _builder.getPointerField(::capnp::bounded<3>() * ::capnp::POINTERS).clear(); + return typename Field::Slot::Builder(_builder); +} +inline bool Field::Reader::isGroup() const { + return which() == Field::GROUP; +} +inline bool Field::Builder::isGroup() { + return which() == Field::GROUP; +} +inline typename Field::Group::Reader Field::Reader::getGroup() const { + KJ_IREQUIRE((which() == Field::GROUP), + "Must check which() before get()ing a union member."); + return typename Field::Group::Reader(_reader); +} +inline typename Field::Group::Builder Field::Builder::getGroup() { + KJ_IREQUIRE((which() == Field::GROUP), + "Must check which() before get()ing a union member."); + return typename Field::Group::Builder(_builder); +} +inline typename Field::Group::Builder Field::Builder::initGroup() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Field::GROUP); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Field::Group::Builder(_builder); +} +inline typename Field::Ordinal::Reader Field::Reader::getOrdinal() const { + return typename Field::Ordinal::Reader(_reader); +} +inline typename Field::Ordinal::Builder Field::Builder::getOrdinal() { + return typename Field::Ordinal::Builder(_builder); +} +#if !CAPNP_LITE +inline typename Field::Ordinal::Pipeline Field::Pipeline::getOrdinal() { + return typename Field::Ordinal::Pipeline(_typeless.noop()); +} +#endif // !CAPNP_LITE +inline typename Field::Ordinal::Builder Field::Builder::initOrdinal() { + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<6>() * ::capnp::ELEMENTS, 0); + return typename Field::Ordinal::Builder(_builder); +} +inline ::uint32_t Field::Slot::Reader::getOffset() const { + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Field::Slot::Builder::getOffset() { + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Field::Slot::Builder::setOffset( ::uint32_t value) { + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Slot::Reader::hasType() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Slot::Builder::hasType() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Field::Slot::Reader::getType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Field::Slot::Builder::getType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Field::Slot::Pipeline::getType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void Field::Slot::Builder::setType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Field::Slot::Builder::initType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Field::Slot::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Field::Slot::Builder::disownType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Field::Slot::Reader::hasDefaultValue() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Field::Slot::Builder::hasDefaultValue() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Field::Slot::Reader::getDefaultValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Field::Slot::Builder::getDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Field::Slot::Pipeline::getDefaultValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Field::Slot::Builder::setDefaultValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Field::Slot::Builder::initDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Field::Slot::Builder::adoptDefaultValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Field::Slot::Builder::disownDefaultValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Field::Slot::Reader::getHadExplicitDefault() const { + return _reader.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} + +inline bool Field::Slot::Builder::getHadExplicitDefault() { + return _builder.getDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS); +} +inline void Field::Slot::Builder::setHadExplicitDefault(bool value) { + _builder.setDataField( + ::capnp::bounded<128>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Field::Group::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Field::Group::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Field::Group::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Field::Ordinal::Which Field::Ordinal::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline bool Field::Ordinal::Reader::isImplicit() const { + return which() == Field::Ordinal::IMPLICIT; +} +inline bool Field::Ordinal::Builder::isImplicit() { + return which() == Field::Ordinal::IMPLICIT; +} +inline ::capnp::Void Field::Ordinal::Reader::getImplicit() const { + KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Field::Ordinal::Builder::getImplicit() { + KJ_IREQUIRE((which() == Field::Ordinal::IMPLICIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Field::Ordinal::Builder::setImplicit( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Field::Ordinal::IMPLICIT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Field::Ordinal::Reader::isExplicit() const { + return which() == Field::Ordinal::EXPLICIT; +} +inline bool Field::Ordinal::Builder::isExplicit() { + return which() == Field::Ordinal::EXPLICIT; +} +inline ::uint16_t Field::Ordinal::Reader::getExplicit() const { + KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Field::Ordinal::Builder::getExplicit() { + KJ_IREQUIRE((which() == Field::Ordinal::EXPLICIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS); +} +inline void Field::Ordinal::Builder::setExplicit( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Field::Ordinal::EXPLICIT); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<6>() * ::capnp::ELEMENTS, value); +} + +inline bool Enumerant::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Enumerant::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Enumerant::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Enumerant::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Enumerant::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Enumerant::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Enumerant::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Enumerant::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Enumerant::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Enumerant::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Enumerant::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Enumerant::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Enumerant::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Enumerant::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Enumerant::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Enumerant::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Enumerant::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Enumerant::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Superclass::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Superclass::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Superclass::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Superclass::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Superclass::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Superclass::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Superclass::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Superclass::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Superclass::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Superclass::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Superclass::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Superclass::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Method::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Method::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Method::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Method::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint16_t Method::Reader::getCodeOrder() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Method::Builder::getCodeOrder() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setCodeOrder( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Method::Reader::getParamStructType() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Method::Builder::getParamStructType() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setParamStructType( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Method::Reader::getResultStructType() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Method::Builder::getResultStructType() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Method::Builder::setResultStructType( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Method::Reader::hasAnnotations() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasAnnotations() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Reader Method::Reader::getAnnotations() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::getAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setAnnotations( ::capnp::List< ::capnp::schema::Annotation>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Annotation>::Builder Method::Builder::initAnnotations(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptAnnotations( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Annotation>> Method::Builder::disownAnnotations() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Annotation>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasParamBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasParamBrand() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Method::Reader::getParamBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Method::Builder::getParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getParamBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void Method::Builder::setParamBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Method::Builder::initParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void Method::Builder::adoptParamBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownParamBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasResultBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasResultBrand() { + return !_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Method::Reader::getResultBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Method::Builder::getResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Method::Pipeline::getResultBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(3)); +} +#endif // !CAPNP_LITE +inline void Method::Builder::setResultBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Method::Builder::initResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} +inline void Method::Builder::adoptResultBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Method::Builder::disownResultBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<3>() * ::capnp::POINTERS)); +} + +inline bool Method::Reader::hasImplicitParameters() const { + return !_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline bool Method::Builder::hasImplicitParameters() { + return !_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Reader Method::Reader::getImplicitParameters() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_reader.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::getImplicitParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::get(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} +inline void Method::Builder::setImplicitParameters( ::capnp::List< ::capnp::schema::Node::Parameter>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::set(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node::Parameter>::Builder Method::Builder::initImplicitParameters(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::init(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), size); +} +inline void Method::Builder::adoptImplicitParameters( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::adopt(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node::Parameter>> Method::Builder::disownImplicitParameters() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node::Parameter>>::disown(_builder.getPointerField( + ::capnp::bounded<4>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Type::Which Type::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::Which Type::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Type::Reader::isVoid() const { + return which() == Type::VOID; +} +inline bool Type::Builder::isVoid() { + return which() == Type::VOID; +} +inline ::capnp::Void Type::Reader::getVoid() const { + KJ_IREQUIRE((which() == Type::VOID), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getVoid() { + KJ_IREQUIRE((which() == Type::VOID), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setVoid( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::VOID); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isBool() const { + return which() == Type::BOOL; +} +inline bool Type::Builder::isBool() { + return which() == Type::BOOL; +} +inline ::capnp::Void Type::Reader::getBool() const { + KJ_IREQUIRE((which() == Type::BOOL), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getBool() { + KJ_IREQUIRE((which() == Type::BOOL), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setBool( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::BOOL); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt8() const { + return which() == Type::INT8; +} +inline bool Type::Builder::isInt8() { + return which() == Type::INT8; +} +inline ::capnp::Void Type::Reader::getInt8() const { + KJ_IREQUIRE((which() == Type::INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt8() { + KJ_IREQUIRE((which() == Type::INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt16() const { + return which() == Type::INT16; +} +inline bool Type::Builder::isInt16() { + return which() == Type::INT16; +} +inline ::capnp::Void Type::Reader::getInt16() const { + KJ_IREQUIRE((which() == Type::INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt16() { + KJ_IREQUIRE((which() == Type::INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt32() const { + return which() == Type::INT32; +} +inline bool Type::Builder::isInt32() { + return which() == Type::INT32; +} +inline ::capnp::Void Type::Reader::getInt32() const { + KJ_IREQUIRE((which() == Type::INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt32() { + KJ_IREQUIRE((which() == Type::INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isInt64() const { + return which() == Type::INT64; +} +inline bool Type::Builder::isInt64() { + return which() == Type::INT64; +} +inline ::capnp::Void Type::Reader::getInt64() const { + KJ_IREQUIRE((which() == Type::INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getInt64() { + KJ_IREQUIRE((which() == Type::INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setInt64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint8() const { + return which() == Type::UINT8; +} +inline bool Type::Builder::isUint8() { + return which() == Type::UINT8; +} +inline ::capnp::Void Type::Reader::getUint8() const { + KJ_IREQUIRE((which() == Type::UINT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint8() { + KJ_IREQUIRE((which() == Type::UINT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint8( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT8); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint16() const { + return which() == Type::UINT16; +} +inline bool Type::Builder::isUint16() { + return which() == Type::UINT16; +} +inline ::capnp::Void Type::Reader::getUint16() const { + KJ_IREQUIRE((which() == Type::UINT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint16() { + KJ_IREQUIRE((which() == Type::UINT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint16( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT16); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint32() const { + return which() == Type::UINT32; +} +inline bool Type::Builder::isUint32() { + return which() == Type::UINT32; +} +inline ::capnp::Void Type::Reader::getUint32() const { + KJ_IREQUIRE((which() == Type::UINT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint32() { + KJ_IREQUIRE((which() == Type::UINT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isUint64() const { + return which() == Type::UINT64; +} +inline bool Type::Builder::isUint64() { + return which() == Type::UINT64; +} +inline ::capnp::Void Type::Reader::getUint64() const { + KJ_IREQUIRE((which() == Type::UINT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getUint64() { + KJ_IREQUIRE((which() == Type::UINT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setUint64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::UINT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isFloat32() const { + return which() == Type::FLOAT32; +} +inline bool Type::Builder::isFloat32() { + return which() == Type::FLOAT32; +} +inline ::capnp::Void Type::Reader::getFloat32() const { + KJ_IREQUIRE((which() == Type::FLOAT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getFloat32() { + KJ_IREQUIRE((which() == Type::FLOAT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setFloat32( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::FLOAT32); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isFloat64() const { + return which() == Type::FLOAT64; +} +inline bool Type::Builder::isFloat64() { + return which() == Type::FLOAT64; +} +inline ::capnp::Void Type::Reader::getFloat64() const { + KJ_IREQUIRE((which() == Type::FLOAT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getFloat64() { + KJ_IREQUIRE((which() == Type::FLOAT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setFloat64( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::FLOAT64); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isText() const { + return which() == Type::TEXT; +} +inline bool Type::Builder::isText() { + return which() == Type::TEXT; +} +inline ::capnp::Void Type::Reader::getText() const { + KJ_IREQUIRE((which() == Type::TEXT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getText() { + KJ_IREQUIRE((which() == Type::TEXT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setText( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::TEXT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isData() const { + return which() == Type::DATA; +} +inline bool Type::Builder::isData() { + return which() == Type::DATA; +} +inline ::capnp::Void Type::Reader::getData() const { + KJ_IREQUIRE((which() == Type::DATA), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::Builder::getData() { + KJ_IREQUIRE((which() == Type::DATA), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::Builder::setData( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::DATA); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Reader::isList() const { + return which() == Type::LIST; +} +inline bool Type::Builder::isList() { + return which() == Type::LIST; +} +inline typename Type::List::Reader Type::Reader::getList() const { + KJ_IREQUIRE((which() == Type::LIST), + "Must check which() before get()ing a union member."); + return typename Type::List::Reader(_reader); +} +inline typename Type::List::Builder Type::Builder::getList() { + KJ_IREQUIRE((which() == Type::LIST), + "Must check which() before get()ing a union member."); + return typename Type::List::Builder(_builder); +} +inline typename Type::List::Builder Type::Builder::initList() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::LIST); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::List::Builder(_builder); +} +inline bool Type::Reader::isEnum() const { + return which() == Type::ENUM; +} +inline bool Type::Builder::isEnum() { + return which() == Type::ENUM; +} +inline typename Type::Enum::Reader Type::Reader::getEnum() const { + KJ_IREQUIRE((which() == Type::ENUM), + "Must check which() before get()ing a union member."); + return typename Type::Enum::Reader(_reader); +} +inline typename Type::Enum::Builder Type::Builder::getEnum() { + KJ_IREQUIRE((which() == Type::ENUM), + "Must check which() before get()ing a union member."); + return typename Type::Enum::Builder(_builder); +} +inline typename Type::Enum::Builder Type::Builder::initEnum() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::ENUM); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Enum::Builder(_builder); +} +inline bool Type::Reader::isStruct() const { + return which() == Type::STRUCT; +} +inline bool Type::Builder::isStruct() { + return which() == Type::STRUCT; +} +inline typename Type::Struct::Reader Type::Reader::getStruct() const { + KJ_IREQUIRE((which() == Type::STRUCT), + "Must check which() before get()ing a union member."); + return typename Type::Struct::Reader(_reader); +} +inline typename Type::Struct::Builder Type::Builder::getStruct() { + KJ_IREQUIRE((which() == Type::STRUCT), + "Must check which() before get()ing a union member."); + return typename Type::Struct::Builder(_builder); +} +inline typename Type::Struct::Builder Type::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::STRUCT); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Struct::Builder(_builder); +} +inline bool Type::Reader::isInterface() const { + return which() == Type::INTERFACE; +} +inline bool Type::Builder::isInterface() { + return which() == Type::INTERFACE; +} +inline typename Type::Interface::Reader Type::Reader::getInterface() const { + KJ_IREQUIRE((which() == Type::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Type::Interface::Reader(_reader); +} +inline typename Type::Interface::Builder Type::Builder::getInterface() { + KJ_IREQUIRE((which() == Type::INTERFACE), + "Must check which() before get()ing a union member."); + return typename Type::Interface::Builder(_builder); +} +inline typename Type::Interface::Builder Type::Builder::initInterface() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::INTERFACE); + _builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0); + _builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear(); + return typename Type::Interface::Builder(_builder); +} +inline bool Type::Reader::isAnyPointer() const { + return which() == Type::ANY_POINTER; +} +inline bool Type::Builder::isAnyPointer() { + return which() == Type::ANY_POINTER; +} +inline typename Type::AnyPointer::Reader Type::Reader::getAnyPointer() const { + KJ_IREQUIRE((which() == Type::ANY_POINTER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Reader(_reader); +} +inline typename Type::AnyPointer::Builder Type::Builder::getAnyPointer() { + KJ_IREQUIRE((which() == Type::ANY_POINTER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Builder(_builder); +} +inline typename Type::AnyPointer::Builder Type::Builder::initAnyPointer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Type::ANY_POINTER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<4>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Builder(_builder); +} +inline bool Type::List::Reader::hasElementType() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::List::Builder::hasElementType() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Type::List::Reader::getElementType() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Type::List::Builder::getElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Type::Pipeline Type::List::Pipeline::getElementType() { + return ::capnp::schema::Type::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::List::Builder::setElementType( ::capnp::schema::Type::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Type::List::Builder::initElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::List::Builder::adoptElementType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Type::List::Builder::disownElementType() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Enum::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Enum::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Enum::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Enum::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Enum::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Enum::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Enum::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Enum::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Enum::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Enum::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Enum::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Enum::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Struct::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Struct::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Struct::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Struct::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Struct::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Struct::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Struct::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Struct::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Struct::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Struct::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Struct::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Struct::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::uint64_t Type::Interface::Reader::getTypeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::Interface::Builder::getTypeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Type::Interface::Builder::setTypeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::Interface::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Type::Interface::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Type::Interface::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Type::Interface::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Type::Interface::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Type::Interface::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Type::Interface::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Type::Interface::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Type::Interface::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::AnyPointer::Which Type::AnyPointer::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline bool Type::AnyPointer::Reader::isUnconstrained() const { + return which() == Type::AnyPointer::UNCONSTRAINED; +} +inline bool Type::AnyPointer::Builder::isUnconstrained() { + return which() == Type::AnyPointer::UNCONSTRAINED; +} +inline typename Type::AnyPointer::Unconstrained::Reader Type::AnyPointer::Reader::getUnconstrained() const { + KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Unconstrained::Reader(_reader); +} +inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::getUnconstrained() { + KJ_IREQUIRE((which() == Type::AnyPointer::UNCONSTRAINED), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Unconstrained::Builder(_builder); +} +inline typename Type::AnyPointer::Unconstrained::Builder Type::AnyPointer::Builder::initUnconstrained() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::UNCONSTRAINED); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Unconstrained::Builder(_builder); +} +inline bool Type::AnyPointer::Reader::isParameter() const { + return which() == Type::AnyPointer::PARAMETER; +} +inline bool Type::AnyPointer::Builder::isParameter() { + return which() == Type::AnyPointer::PARAMETER; +} +inline typename Type::AnyPointer::Parameter::Reader Type::AnyPointer::Reader::getParameter() const { + KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Parameter::Reader(_reader); +} +inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::getParameter() { + KJ_IREQUIRE((which() == Type::AnyPointer::PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::Parameter::Builder(_builder); +} +inline typename Type::AnyPointer::Parameter::Builder Type::AnyPointer::Builder::initParameter() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::PARAMETER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + _builder.setDataField< ::uint64_t>(::capnp::bounded<2>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::Parameter::Builder(_builder); +} +inline bool Type::AnyPointer::Reader::isImplicitMethodParameter() const { + return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; +} +inline bool Type::AnyPointer::Builder::isImplicitMethodParameter() { + return which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER; +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Reader Type::AnyPointer::Reader::getImplicitMethodParameter() const { + KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::ImplicitMethodParameter::Reader(_reader); +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::getImplicitMethodParameter() { + KJ_IREQUIRE((which() == Type::AnyPointer::IMPLICIT_METHOD_PARAMETER), + "Must check which() before get()ing a union member."); + return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); +} +inline typename Type::AnyPointer::ImplicitMethodParameter::Builder Type::AnyPointer::Builder::initImplicitMethodParameter() { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Type::AnyPointer::IMPLICIT_METHOD_PARAMETER); + _builder.setDataField< ::uint16_t>(::capnp::bounded<5>() * ::capnp::ELEMENTS, 0); + return typename Type::AnyPointer::ImplicitMethodParameter::Builder(_builder); +} +inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Type::AnyPointer::Unconstrained::Which Type::AnyPointer::Unconstrained::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isAnyKind() const { + return which() == Type::AnyPointer::Unconstrained::ANY_KIND; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isAnyKind() { + return which() == Type::AnyPointer::Unconstrained::ANY_KIND; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getAnyKind() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getAnyKind() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::ANY_KIND), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setAnyKind( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::ANY_KIND); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isStruct() const { + return which() == Type::AnyPointer::Unconstrained::STRUCT; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isStruct() { + return which() == Type::AnyPointer::Unconstrained::STRUCT; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getStruct() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getStruct() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::STRUCT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setStruct( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::STRUCT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isList() const { + return which() == Type::AnyPointer::Unconstrained::LIST; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isList() { + return which() == Type::AnyPointer::Unconstrained::LIST; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getList() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getList() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::LIST), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setList( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::LIST); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Type::AnyPointer::Unconstrained::Reader::isCapability() const { + return which() == Type::AnyPointer::Unconstrained::CAPABILITY; +} +inline bool Type::AnyPointer::Unconstrained::Builder::isCapability() { + return which() == Type::AnyPointer::Unconstrained::CAPABILITY; +} +inline ::capnp::Void Type::AnyPointer::Unconstrained::Reader::getCapability() const { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Type::AnyPointer::Unconstrained::Builder::getCapability() { + KJ_IREQUIRE((which() == Type::AnyPointer::Unconstrained::CAPABILITY), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Unconstrained::Builder::setCapability( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, Type::AnyPointer::Unconstrained::CAPABILITY); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint64_t Type::AnyPointer::Parameter::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Type::AnyPointer::Parameter::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Parameter::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Type::AnyPointer::Parameter::Reader::getParameterIndex() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Type::AnyPointer::Parameter::Builder::getParameterIndex() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::Parameter::Builder::setParameterIndex( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, value); +} + +inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Reader::getParameterIndex() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Type::AnyPointer::ImplicitMethodParameter::Builder::getParameterIndex() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS); +} +inline void Type::AnyPointer::ImplicitMethodParameter::Builder::setParameterIndex( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<5>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Reader::hasScopes() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Builder::hasScopes() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Reader Brand::Reader::getScopes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::getScopes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Builder::setScopes( ::capnp::List< ::capnp::schema::Brand::Scope>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Brand::Scope>::Builder Brand::Builder::initScopes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Brand::Builder::adoptScopes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Scope>> Brand::Builder::disownScopes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Scope>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Brand::Scope::Which Brand::Scope::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Brand::Scope::Reader::getScopeId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Brand::Scope::Builder::getScopeId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Scope::Builder::setScopeId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Scope::Reader::isBind() const { + return which() == Brand::Scope::BIND; +} +inline bool Brand::Scope::Builder::isBind() { + return which() == Brand::Scope::BIND; +} +inline bool Brand::Scope::Reader::hasBind() const { + if (which() != Brand::Scope::BIND) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Scope::Builder::hasBind() { + if (which() != Brand::Scope::BIND) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Reader Brand::Scope::Reader::getBind() const { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::getBind() { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Scope::Builder::setBind( ::capnp::List< ::capnp::schema::Brand::Binding>::Reader value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Brand::Binding>::Builder Brand::Scope::Builder::initBind(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Brand::Scope::Builder::adoptBind( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>>&& value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::BIND); + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Brand::Binding>> Brand::Scope::Builder::disownBind() { + KJ_IREQUIRE((which() == Brand::Scope::BIND), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Brand::Binding>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Brand::Scope::Reader::isInherit() const { + return which() == Brand::Scope::INHERIT; +} +inline bool Brand::Scope::Builder::isInherit() { + return which() == Brand::Scope::INHERIT; +} +inline ::capnp::Void Brand::Scope::Reader::getInherit() const { + KJ_IREQUIRE((which() == Brand::Scope::INHERIT), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Brand::Scope::Builder::getInherit() { + KJ_IREQUIRE((which() == Brand::Scope::INHERIT), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Scope::Builder::setInherit( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<4>() * ::capnp::ELEMENTS, Brand::Scope::INHERIT); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Brand::Binding::Which Brand::Binding::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Brand::Binding::Reader::isUnbound() const { + return which() == Brand::Binding::UNBOUND; +} +inline bool Brand::Binding::Builder::isUnbound() { + return which() == Brand::Binding::UNBOUND; +} +inline ::capnp::Void Brand::Binding::Reader::getUnbound() const { + KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Brand::Binding::Builder::getUnbound() { + KJ_IREQUIRE((which() == Brand::Binding::UNBOUND), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Brand::Binding::Builder::setUnbound( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::UNBOUND); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Brand::Binding::Reader::isType() const { + return which() == Brand::Binding::TYPE; +} +inline bool Brand::Binding::Builder::isType() { + return which() == Brand::Binding::TYPE; +} +inline bool Brand::Binding::Reader::hasType() const { + if (which() != Brand::Binding::TYPE) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Brand::Binding::Builder::hasType() { + if (which() != Brand::Binding::TYPE) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Type::Reader Brand::Binding::Reader::getType() const { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Type::Builder Brand::Binding::Builder::getType() { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Binding::Builder::setType( ::capnp::schema::Type::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Type::Builder Brand::Binding::Builder::initType() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Brand::Binding::Builder::adoptType( + ::capnp::Orphan< ::capnp::schema::Type>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Brand::Binding::TYPE); + ::capnp::_::PointerHelpers< ::capnp::schema::Type>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Type> Brand::Binding::Builder::disownType() { + KJ_IREQUIRE((which() == Brand::Binding::TYPE), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::schema::Type>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline ::capnp::schema::Value::Which Value::Reader::which() const { + return _reader.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline ::capnp::schema::Value::Which Value::Builder::which() { + return _builder.getDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline bool Value::Reader::isVoid() const { + return which() == Value::VOID; +} +inline bool Value::Builder::isVoid() { + return which() == Value::VOID; +} +inline ::capnp::Void Value::Reader::getVoid() const { + KJ_IREQUIRE((which() == Value::VOID), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Value::Builder::getVoid() { + KJ_IREQUIRE((which() == Value::VOID), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setVoid( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::VOID); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isBool() const { + return which() == Value::BOOL; +} +inline bool Value::Builder::isBool() { + return which() == Value::BOOL; +} +inline bool Value::Reader::getBool() const { + KJ_IREQUIRE((which() == Value::BOOL), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} + +inline bool Value::Builder::getBool() { + KJ_IREQUIRE((which() == Value::BOOL), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setBool(bool value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::BOOL); + _builder.setDataField( + ::capnp::bounded<16>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt8() const { + return which() == Value::INT8; +} +inline bool Value::Builder::isInt8() { + return which() == Value::INT8; +} +inline ::int8_t Value::Reader::getInt8() const { + KJ_IREQUIRE((which() == Value::INT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::int8_t Value::Builder::getInt8() { + KJ_IREQUIRE((which() == Value::INT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt8( ::int8_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT8); + _builder.setDataField< ::int8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt16() const { + return which() == Value::INT16; +} +inline bool Value::Builder::isInt16() { + return which() == Value::INT16; +} +inline ::int16_t Value::Reader::getInt16() const { + KJ_IREQUIRE((which() == Value::INT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int16_t Value::Builder::getInt16() { + KJ_IREQUIRE((which() == Value::INT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt16( ::int16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT16); + _builder.setDataField< ::int16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt32() const { + return which() == Value::INT32; +} +inline bool Value::Builder::isInt32() { + return which() == Value::INT32; +} +inline ::int32_t Value::Reader::getInt32() const { + KJ_IREQUIRE((which() == Value::INT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int32_t Value::Builder::getInt32() { + KJ_IREQUIRE((which() == Value::INT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt32( ::int32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT32); + _builder.setDataField< ::int32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isInt64() const { + return which() == Value::INT64; +} +inline bool Value::Builder::isInt64() { + return which() == Value::INT64; +} +inline ::int64_t Value::Reader::getInt64() const { + KJ_IREQUIRE((which() == Value::INT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::int64_t Value::Builder::getInt64() { + KJ_IREQUIRE((which() == Value::INT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInt64( ::int64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INT64); + _builder.setDataField< ::int64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint8() const { + return which() == Value::UINT8; +} +inline bool Value::Builder::isUint8() { + return which() == Value::UINT8; +} +inline ::uint8_t Value::Reader::getUint8() const { + KJ_IREQUIRE((which() == Value::UINT8), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t Value::Builder::getUint8() { + KJ_IREQUIRE((which() == Value::UINT8), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint8( ::uint8_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT8); + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint16() const { + return which() == Value::UINT16; +} +inline bool Value::Builder::isUint16() { + return which() == Value::UINT16; +} +inline ::uint16_t Value::Reader::getUint16() const { + KJ_IREQUIRE((which() == Value::UINT16), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Value::Builder::getUint16() { + KJ_IREQUIRE((which() == Value::UINT16), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint16( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT16); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint32() const { + return which() == Value::UINT32; +} +inline bool Value::Builder::isUint32() { + return which() == Value::UINT32; +} +inline ::uint32_t Value::Reader::getUint32() const { + KJ_IREQUIRE((which() == Value::UINT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint32_t Value::Builder::getUint32() { + KJ_IREQUIRE((which() == Value::UINT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint32( ::uint32_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT32); + _builder.setDataField< ::uint32_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isUint64() const { + return which() == Value::UINT64; +} +inline bool Value::Builder::isUint64() { + return which() == Value::UINT64; +} +inline ::uint64_t Value::Reader::getUint64() const { + KJ_IREQUIRE((which() == Value::UINT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Value::Builder::getUint64() { + KJ_IREQUIRE((which() == Value::UINT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setUint64( ::uint64_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::UINT64); + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isFloat32() const { + return which() == Value::FLOAT32; +} +inline bool Value::Builder::isFloat32() { + return which() == Value::FLOAT32; +} +inline float Value::Reader::getFloat32() const { + KJ_IREQUIRE((which() == Value::FLOAT32), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline float Value::Builder::getFloat32() { + KJ_IREQUIRE((which() == Value::FLOAT32), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setFloat32(float value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::FLOAT32); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isFloat64() const { + return which() == Value::FLOAT64; +} +inline bool Value::Builder::isFloat64() { + return which() == Value::FLOAT64; +} +inline double Value::Reader::getFloat64() const { + KJ_IREQUIRE((which() == Value::FLOAT64), + "Must check which() before get()ing a union member."); + return _reader.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline double Value::Builder::getFloat64() { + KJ_IREQUIRE((which() == Value::FLOAT64), + "Must check which() before get()ing a union member."); + return _builder.getDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setFloat64(double value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::FLOAT64); + _builder.setDataField( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isText() const { + return which() == Value::TEXT; +} +inline bool Value::Builder::isText() { + return which() == Value::TEXT; +} +inline bool Value::Reader::hasText() const { + if (which() != Value::TEXT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasText() { + if (which() != Value::TEXT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader Value::Reader::getText() const { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder Value::Builder::getText() { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Value::Builder::setText( ::capnp::Text::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder Value::Builder::initText(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Value::Builder::adoptText( + ::capnp::Orphan< ::capnp::Text>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::TEXT); + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> Value::Builder::disownText() { + KJ_IREQUIRE((which() == Value::TEXT), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Value::Reader::isData() const { + return which() == Value::DATA; +} +inline bool Value::Builder::isData() { + return which() == Value::DATA; +} +inline bool Value::Reader::hasData() const { + if (which() != Value::DATA) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasData() { + if (which() != Value::DATA) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Data::Reader Value::Reader::getData() const { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Data::Builder Value::Builder::getData() { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Value::Builder::setData( ::capnp::Data::Reader value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + ::capnp::_::PointerHelpers< ::capnp::Data>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Data::Builder Value::Builder::initData(unsigned int size) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + return ::capnp::_::PointerHelpers< ::capnp::Data>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void Value::Builder::adoptData( + ::capnp::Orphan< ::capnp::Data>&& value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::DATA); + ::capnp::_::PointerHelpers< ::capnp::Data>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Data> Value::Builder::disownData() { + KJ_IREQUIRE((which() == Value::DATA), + "Must check which() before get()ing a union member."); + return ::capnp::_::PointerHelpers< ::capnp::Data>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Value::Reader::isList() const { + return which() == Value::LIST; +} +inline bool Value::Builder::isList() { + return which() == Value::LIST; +} +inline bool Value::Reader::hasList() const { + if (which() != Value::LIST) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasList() { + if (which() != Value::LIST) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getList() const { + KJ_IREQUIRE((which() == Value::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getList() { + KJ_IREQUIRE((which() == Value::LIST), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initList() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::LIST); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Value::Reader::isEnum() const { + return which() == Value::ENUM; +} +inline bool Value::Builder::isEnum() { + return which() == Value::ENUM; +} +inline ::uint16_t Value::Reader::getEnum() const { + KJ_IREQUIRE((which() == Value::ENUM), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t Value::Builder::getEnum() { + KJ_IREQUIRE((which() == Value::ENUM), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setEnum( ::uint16_t value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::ENUM); + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<1>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isStruct() const { + return which() == Value::STRUCT; +} +inline bool Value::Builder::isStruct() { + return which() == Value::STRUCT; +} +inline bool Value::Reader::hasStruct() const { + if (which() != Value::STRUCT) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasStruct() { + if (which() != Value::STRUCT) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getStruct() const { + KJ_IREQUIRE((which() == Value::STRUCT), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getStruct() { + KJ_IREQUIRE((which() == Value::STRUCT), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initStruct() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::STRUCT); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline bool Value::Reader::isInterface() const { + return which() == Value::INTERFACE; +} +inline bool Value::Builder::isInterface() { + return which() == Value::INTERFACE; +} +inline ::capnp::Void Value::Reader::getInterface() const { + KJ_IREQUIRE((which() == Value::INTERFACE), + "Must check which() before get()ing a union member."); + return _reader.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::capnp::Void Value::Builder::getInterface() { + KJ_IREQUIRE((which() == Value::INTERFACE), + "Must check which() before get()ing a union member."); + return _builder.getDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Value::Builder::setInterface( ::capnp::Void value) { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::INTERFACE); + _builder.setDataField< ::capnp::Void>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Value::Reader::isAnyPointer() const { + return which() == Value::ANY_POINTER; +} +inline bool Value::Builder::isAnyPointer() { + return which() == Value::ANY_POINTER; +} +inline bool Value::Reader::hasAnyPointer() const { + if (which() != Value::ANY_POINTER) return false; + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Value::Builder::hasAnyPointer() { + if (which() != Value::ANY_POINTER) return false; + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::AnyPointer::Reader Value::Reader::getAnyPointer() const { + KJ_IREQUIRE((which() == Value::ANY_POINTER), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Reader(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::getAnyPointer() { + KJ_IREQUIRE((which() == Value::ANY_POINTER), + "Must check which() before get()ing a union member."); + return ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::AnyPointer::Builder Value::Builder::initAnyPointer() { + _builder.setDataField( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, Value::ANY_POINTER); + auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); + result.clear(); + return result; +} + +inline ::uint64_t Annotation::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t Annotation::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void Annotation::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool Annotation::Reader::hasValue() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool Annotation::Builder::hasValue() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Value::Reader Annotation::Reader::getValue() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Value::Builder Annotation::Builder::getValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Value::Pipeline Annotation::Pipeline::getValue() { + return ::capnp::schema::Value::Pipeline(_typeless.getPointerField(0)); +} +#endif // !CAPNP_LITE +inline void Annotation::Builder::setValue( ::capnp::schema::Value::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Value::Builder Annotation::Builder::initValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void Annotation::Builder::adoptValue( + ::capnp::Orphan< ::capnp::schema::Value>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Value>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Value> Annotation::Builder::disownValue() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Value>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool Annotation::Reader::hasBrand() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool Annotation::Builder::hasBrand() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::Brand::Reader Annotation::Reader::getBrand() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::Brand::Builder Annotation::Builder::getBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::Brand::Pipeline Annotation::Pipeline::getBrand() { + return ::capnp::schema::Brand::Pipeline(_typeless.getPointerField(1)); +} +#endif // !CAPNP_LITE +inline void Annotation::Builder::setBrand( ::capnp::schema::Brand::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::Brand::Builder Annotation::Builder::initBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void Annotation::Builder::adoptBrand( + ::capnp::Orphan< ::capnp::schema::Brand>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::Brand> Annotation::Builder::disownBrand() { + return ::capnp::_::PointerHelpers< ::capnp::schema::Brand>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint16_t CapnpVersion::Reader::getMajor() const { + return _reader.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint16_t CapnpVersion::Builder::getMajor() { + return _builder.getDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMajor( ::uint16_t value) { + _builder.setDataField< ::uint16_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline ::uint8_t CapnpVersion::Reader::getMinor() const { + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t CapnpVersion::Builder::getMinor() { + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMinor( ::uint8_t value) { + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<2>() * ::capnp::ELEMENTS, value); +} + +inline ::uint8_t CapnpVersion::Reader::getMicro() const { + return _reader.getDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} + +inline ::uint8_t CapnpVersion::Builder::getMicro() { + return _builder.getDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS); +} +inline void CapnpVersion::Builder::setMicro( ::uint8_t value) { + _builder.setDataField< ::uint8_t>( + ::capnp::bounded<3>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::Reader::hasNodes() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasNodes() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::Node>::Reader CodeGeneratorRequest::Reader::getNodes() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::getNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::setNodes( ::capnp::List< ::capnp::schema::Node>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::Node>::Builder CodeGeneratorRequest::Builder::initNodes(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::Builder::adoptNodes( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::Node>> CodeGeneratorRequest::Builder::disownNodes() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::Node>>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::Reader::hasRequestedFiles() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasRequestedFiles() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader CodeGeneratorRequest::Reader::getRequestedFiles() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::getRequestedFiles() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::setRequestedFiles( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>::Builder CodeGeneratorRequest::Builder::initRequestedFiles(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::Builder::adoptRequestedFiles( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>> CodeGeneratorRequest::Builder::disownRequestedFiles() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::Reader::hasCapnpVersion() const { + return !_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::Builder::hasCapnpVersion() { + return !_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::schema::CapnpVersion::Reader CodeGeneratorRequest::Reader::getCapnpVersion() const { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::get(_reader.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline ::capnp::schema::CapnpVersion::Builder CodeGeneratorRequest::Builder::getCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::get(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +#if !CAPNP_LITE +inline ::capnp::schema::CapnpVersion::Pipeline CodeGeneratorRequest::Pipeline::getCapnpVersion() { + return ::capnp::schema::CapnpVersion::Pipeline(_typeless.getPointerField(2)); +} +#endif // !CAPNP_LITE +inline void CodeGeneratorRequest::Builder::setCapnpVersion( ::capnp::schema::CapnpVersion::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::set(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), value); +} +inline ::capnp::schema::CapnpVersion::Builder CodeGeneratorRequest::Builder::initCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::init(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::Builder::adoptCapnpVersion( + ::capnp::Orphan< ::capnp::schema::CapnpVersion>&& value) { + ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::adopt(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::schema::CapnpVersion> CodeGeneratorRequest::Builder::disownCapnpVersion() { + return ::capnp::_::PointerHelpers< ::capnp::schema::CapnpVersion>::disown(_builder.getPointerField( + ::capnp::bounded<2>() * ::capnp::POINTERS)); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::RequestedFile::Reader::hasFilename() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Builder::hasFilename() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Reader::getFilename() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::getFilename() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setFilename( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Builder::initFilename(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::adoptFilename( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Builder::disownFilename() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +inline bool CodeGeneratorRequest::RequestedFile::Reader::hasImports() const { + return !_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Builder::hasImports() { + return !_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader CodeGeneratorRequest::RequestedFile::Reader::getImports() const { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get(_reader.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::getImports() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::get(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::setImports( ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::set(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), value); +} +inline ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>::Builder CodeGeneratorRequest::RequestedFile::Builder::initImports(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::init(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Builder::adoptImports( + ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>&& value) { + ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::adopt(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>> CodeGeneratorRequest::RequestedFile::Builder::disownImports() { + return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::schema::CodeGeneratorRequest::RequestedFile::Import>>::disown(_builder.getPointerField( + ::capnp::bounded<1>() * ::capnp::POINTERS)); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Reader::getId() const { + return _reader.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} + +inline ::uint64_t CodeGeneratorRequest::RequestedFile::Import::Builder::getId() { + return _builder.getDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setId( ::uint64_t value) { + _builder.setDataField< ::uint64_t>( + ::capnp::bounded<0>() * ::capnp::ELEMENTS, value); +} + +inline bool CodeGeneratorRequest::RequestedFile::Import::Reader::hasName() const { + return !_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline bool CodeGeneratorRequest::RequestedFile::Import::Builder::hasName() { + return !_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS).isNull(); +} +inline ::capnp::Text::Reader CodeGeneratorRequest::RequestedFile::Import::Reader::getName() const { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::getName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::setName( ::capnp::Text::Reader value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), value); +} +inline ::capnp::Text::Builder CodeGeneratorRequest::RequestedFile::Import::Builder::initName(unsigned int size) { + return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), size); +} +inline void CodeGeneratorRequest::RequestedFile::Import::Builder::adoptName( + ::capnp::Orphan< ::capnp::Text>&& value) { + ::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value)); +} +inline ::capnp::Orphan< ::capnp::Text> CodeGeneratorRequest::RequestedFile::Import::Builder::disownName() { + return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField( + ::capnp::bounded<0>() * ::capnp::POINTERS)); +} + +} // namespace +} // namespace + +#endif // CAPNP_INCLUDED_a93fc509624c72d9_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/schema.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/schema.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,934 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SCHEMA_H_ +#define CAPNP_SCHEMA_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#if CAPNP_LITE +#error "Reflection APIs, including this header, are not available in lite mode." +#endif + +#include + +namespace capnp { + +class Schema; +class StructSchema; +class EnumSchema; +class InterfaceSchema; +class ConstSchema; +class ListSchema; +class Type; + +template ()> struct SchemaType_ { typedef Schema Type; }; +template struct SchemaType_ { typedef schema::Type::Which Type; }; +template struct SchemaType_ { typedef schema::Type::Which Type; }; +template struct SchemaType_ { typedef EnumSchema Type; }; +template struct SchemaType_ { typedef StructSchema Type; }; +template struct SchemaType_ { typedef InterfaceSchema Type; }; +template struct SchemaType_ { typedef ListSchema Type; }; + +template +using SchemaType = typename SchemaType_::Type; +// SchemaType is the type of T's schema, e.g. StructSchema if T is a struct. + +namespace _ { // private +extern const RawSchema NULL_SCHEMA; +extern const RawSchema NULL_STRUCT_SCHEMA; +extern const RawSchema NULL_ENUM_SCHEMA; +extern const RawSchema NULL_INTERFACE_SCHEMA; +extern const RawSchema NULL_CONST_SCHEMA; +// The schema types default to these null (empty) schemas in case of error, especially when +// exceptions are disabled. +} // namespace _ (private) + +class Schema { + // Convenience wrapper around capnp::schema::Node. + +public: + inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {} + + template + static inline SchemaType from() { return SchemaType::template fromImpl(); } + // Get the Schema for a particular compiled-in type. + + schema::Node::Reader getProto() const; + // Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor + // has performance comparable to accessors of struct-typed fields on Reader classes.) + + kj::ArrayPtr asUncheckedMessage() const; + // Get the encoded schema node content as a single message segment. It is safe to read as an + // unchecked message. + + Schema getDependency(uint64_t id) const KJ_DEPRECATED("Does not handle generics correctly."); + // DEPRECATED: This method cannot correctly account for generic type parameter bindings that + // may apply to the dependency. Instead of using this method, use a method of the Schema API + // that corresponds to the exact kind of dependency. For example, to get a field type, use + // StructSchema::Field::getType(). + // + // Gets the Schema for one of this Schema's dependencies. For example, if this Schema is for a + // struct, you could look up the schema for one of its fields' types. Throws an exception if this + // schema doesn't actually depend on the given id. + // + // Note that not all type IDs found in the schema node are considered "dependencies" -- only the + // ones that are needed to implement the dynamic API are. That includes: + // - Field types. + // - Group types. + // - scopeId for group nodes, but NOT otherwise. + // - Method parameter and return types. + // + // The following are NOT considered dependencies: + // - Nested nodes. + // - scopeId for a non-group node. + // - Annotations. + // + // To obtain schemas for those, you would need a SchemaLoader. + + bool isBranded() const; + // Returns true if this schema represents a non-default parameterization of this type. + + Schema getGeneric() const; + // Get the version of this schema with any brands removed. + + class BrandArgumentList; + BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const; + // Gets the values bound to the brand parameters at the given scope. + + StructSchema asStruct() const; + EnumSchema asEnum() const; + InterfaceSchema asInterface() const; + ConstSchema asConst() const; + // Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use + // getProto() to determine type, e.g. getProto().isStruct(). + + inline bool operator==(const Schema& other) const { return raw == other.raw; } + inline bool operator!=(const Schema& other) const { return raw != other.raw; } + // Determine whether two Schemas are wrapping the exact same underlying data, by identity. If + // you want to check if two Schemas represent the same type (but possibly different versions of + // it), compare their IDs instead. + + template + void requireUsableAs() const; + // Throws an exception if a value with this Schema cannot safely be cast to a native value of + // the given type. This passes if either: + // - *this == from() + // - This schema was loaded with SchemaLoader, the type ID matches typeId(), and + // loadCompiledTypeAndDependencies() was called on the SchemaLoader. + + kj::StringPtr getShortDisplayName() const; + // Get the short version of the node's display name. + +private: + const _::RawBrandedSchema* raw; + + inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) { + KJ_IREQUIRE(raw->lazyInitializer == nullptr, + "Must call ensureInitialized() on RawSchema before constructing Schema."); + } + + template static inline Schema fromImpl() { + return Schema(&_::rawSchema()); + } + + void requireUsableAs(const _::RawSchema* expected) const; + + uint32_t getSchemaOffset(const schema::Value::Reader& value) const; + + Type getBrandBinding(uint64_t scopeId, uint index) const; + // Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the + // parameter is not bound. + // + // TODO(someday): Public interface for iterating over all bindings? + + Schema getDependency(uint64_t id, uint location) const; + // Look up schema for a particular dependency of this schema. `location` is the dependency + // location number as defined in _::RawBrandedSchema. + + Type interpretType(schema::Type::Reader proto, uint location) const; + // Interpret a schema::Type in the given location within the schema, compiling it into a + // Type object. + + friend class StructSchema; + friend class EnumSchema; + friend class InterfaceSchema; + friend class ConstSchema; + friend class ListSchema; + friend class SchemaLoader; + friend class Type; + friend kj::StringTree _::structString( + _::StructReader reader, const _::RawBrandedSchema& schema); + friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema); +}; + +kj::StringPtr KJ_STRINGIFY(const Schema& schema); + +class Schema::BrandArgumentList { + // A list of generic parameter bindings for parameters of some particular type. Note that since + // parameters on an outer type apply to all inner types as well, a deeply-nested type can have + // multiple BrandArgumentLists that apply to it. + // + // A BrandArgumentList only represents the arguments that the client of the type specified. Since + // new parameters can be added over time, this list may not cover all defined parameters for the + // type. Missing parameters should be treated as AnyPointer. This class's implementation of + // operator[] already does this for you; out-of-bounds access will safely return AnyPointer. + +public: + inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {} + + inline uint size() const { return size_; } + Type operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + uint64_t scopeId; + uint size_; + bool isUnbound; + const _::RawBrandedSchema::Binding* bindings; + + inline BrandArgumentList(uint64_t scopeId, bool isUnbound) + : scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {} + inline BrandArgumentList(uint64_t scopeId, uint size, + const _::RawBrandedSchema::Binding* bindings) + : scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {} + + friend class Schema; +}; + +// ------------------------------------------------------------------- + +class StructSchema: public Schema { +public: + inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {} + + class Field; + class FieldList; + class FieldSubset; + + FieldList getFields() const; + // List top-level fields of this struct. This list will contain top-level groups (including + // named unions) but not the members of those groups. The list does, however, contain the + // members of the unnamed union, if there is one. + + FieldSubset getUnionFields() const; + // If the field contains an unnamed union, get a list of fields in the union, ordered by + // ordinal. Since discriminant values are assigned sequentially by ordinal, you may index this + // list by discriminant value. + + FieldSubset getNonUnionFields() const; + // Get the fields of this struct which are not in an unnamed union, ordered by ordinal. + + kj::Maybe findFieldByName(kj::StringPtr name) const; + // Find the field with the given name, or return null if there is no such field. If the struct + // contains an unnamed union, then this will find fields of that union in addition to fields + // of the outer struct, since they exist in the same namespace. It will not, however, find + // members of groups (including named unions) -- you must first look up the group itself, + // then dig into its type. + + Field getFieldByName(kj::StringPtr name) const; + // Like findFieldByName() but throws an exception on failure. + + kj::Maybe getFieldByDiscriminant(uint16_t discriminant) const; + // Finds the field whose `discriminantValue` is equal to the given value, or returns null if + // there is no such field. (If the schema does not represent a union or a struct containing + // an unnamed union, then this always returns null.) + +private: + StructSchema(Schema base): Schema(base) {} + template static inline StructSchema fromImpl() { + return StructSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; +}; + +class StructSchema::Field { +public: + Field() = default; + + inline schema::Field::Reader getProto() const { return proto; } + inline StructSchema getContainingStruct() const { return parent; } + + inline uint getIndex() const { return index; } + // Get the index of this field within the containing struct or union. + + Type getType() const; + // Get the type of this field. Note that this is preferred over getProto().getType() as this + // method will apply generics. + + uint32_t getDefaultValueSchemaOffset() const; + // For struct, list, and object fields, returns the offset, in words, within the first segment of + // the struct's schema, where this field's default value pointer is located. The schema is + // always stored as a single-segment unchecked message, which in turn means that the default + // value pointer itself can be treated as the root of an unchecked message -- if you know where + // to find it, which is what this method helps you with. + // + // For blobs, returns the offset of the beginning of the blob's content within the first segment + // of the struct's schema. + // + // This is primarily useful for code generators. The C++ code generator, for example, embeds + // the entire schema as a raw word array within the generated code. Of course, to implement + // field accessors, it needs access to those fields' default values. Embedding separate copies + // of those default values would be redundant since they are already included in the schema, but + // seeking through the schema at runtime to find the default values would be ugly. Instead, + // the code generator can use getDefaultValueSchemaOffset() to find the offset of the default + // value within the schema, and can simply apply that offset at runtime. + // + // If the above does not make sense, you probably don't need this method. + + inline bool operator==(const Field& other) const; + inline bool operator!=(const Field& other) const { return !(*this == other); } + +private: + StructSchema parent; + uint index; + schema::Field::Reader proto; + + inline Field(StructSchema parent, uint index, schema::Field::Reader proto) + : parent(parent), index(index), proto(proto) {} + + friend class StructSchema; +}; + +kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field); + +class StructSchema::FieldList { +public: + FieldList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Field operator[](uint index) const { return Field(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + StructSchema parent; + List::Reader list; + + inline FieldList(StructSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class StructSchema; +}; + +class StructSchema::FieldSubset { +public: + FieldSubset() = default; // empty list + + inline uint size() const { return size_; } + inline Field operator[](uint index) const { + return Field(parent, indices[index], list[indices[index]]); + } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + StructSchema parent; + List::Reader list; + const uint16_t* indices; + uint size_; + + inline FieldSubset(StructSchema parent, List::Reader list, + const uint16_t* indices, uint size) + : parent(parent), list(list), indices(indices), size_(size) {} + + friend class StructSchema; +}; + +// ------------------------------------------------------------------- + +class EnumSchema: public Schema { +public: + inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {} + + class Enumerant; + class EnumerantList; + + EnumerantList getEnumerants() const; + + kj::Maybe findEnumerantByName(kj::StringPtr name) const; + + Enumerant getEnumerantByName(kj::StringPtr name) const; + // Like findEnumerantByName() but throws an exception on failure. + +private: + EnumSchema(Schema base): Schema(base) {} + template static inline EnumSchema fromImpl() { + return EnumSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; +}; + +class EnumSchema::Enumerant { +public: + Enumerant() = default; + + inline schema::Enumerant::Reader getProto() const { return proto; } + inline EnumSchema getContainingEnum() const { return parent; } + + inline uint16_t getOrdinal() const { return ordinal; } + inline uint getIndex() const { return ordinal; } + + inline bool operator==(const Enumerant& other) const; + inline bool operator!=(const Enumerant& other) const { return !(*this == other); } + +private: + EnumSchema parent; + uint16_t ordinal; + schema::Enumerant::Reader proto; + + inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto) + : parent(parent), ordinal(ordinal), proto(proto) {} + + friend class EnumSchema; +}; + +class EnumSchema::EnumerantList { +public: + EnumerantList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + EnumSchema parent; + List::Reader list; + + inline EnumerantList(EnumSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class EnumSchema; +}; + +// ------------------------------------------------------------------- + +class InterfaceSchema: public Schema { +public: + inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {} + + class Method; + class MethodList; + + MethodList getMethods() const; + + kj::Maybe findMethodByName(kj::StringPtr name) const; + + Method getMethodByName(kj::StringPtr name) const; + // Like findMethodByName() but throws an exception on failure. + + class SuperclassList; + + SuperclassList getSuperclasses() const; + // Get the immediate superclasses of this type, after applying generics. + + bool extends(InterfaceSchema other) const; + // Returns true if `other` is a superclass of this interface (including if `other == *this`). + + kj::Maybe findSuperclass(uint64_t typeId) const; + // Find the superclass of this interface with the given type ID. Returns null if the interface + // extends no such type. + +private: + InterfaceSchema(Schema base): Schema(base) {} + template static inline InterfaceSchema fromImpl() { + return InterfaceSchema(Schema(&_::rawBrandedSchema())); + } + friend class Schema; + friend class Type; + + kj::Maybe findMethodByName(kj::StringPtr name, uint& counter) const; + bool extends(InterfaceSchema other, uint& counter) const; + kj::Maybe findSuperclass(uint64_t typeId, uint& counter) const; + // We protect against malicious schemas with large or cyclic hierarchies by cutting off the + // search when the counter reaches a threshold. +}; + +class InterfaceSchema::Method { +public: + Method() = default; + + inline schema::Method::Reader getProto() const { return proto; } + inline InterfaceSchema getContainingInterface() const { return parent; } + + inline uint16_t getOrdinal() const { return ordinal; } + inline uint getIndex() const { return ordinal; } + + StructSchema getParamType() const; + StructSchema getResultType() const; + // Get the parameter and result types, including substituting generic parameters. + + inline bool operator==(const Method& other) const; + inline bool operator!=(const Method& other) const { return !(*this == other); } + +private: + InterfaceSchema parent; + uint16_t ordinal; + schema::Method::Reader proto; + + inline Method(InterfaceSchema parent, uint16_t ordinal, + schema::Method::Reader proto) + : parent(parent), ordinal(ordinal), proto(proto) {} + + friend class InterfaceSchema; +}; + +class InterfaceSchema::MethodList { +public: + MethodList() = default; // empty list + + inline uint size() const { return list.size(); } + inline Method operator[](uint index) const { return Method(parent, index, list[index]); } + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + InterfaceSchema parent; + List::Reader list; + + inline MethodList(InterfaceSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class InterfaceSchema; +}; + +class InterfaceSchema::SuperclassList { +public: + SuperclassList() = default; // empty list + + inline uint size() const { return list.size(); } + InterfaceSchema operator[](uint index) const; + + typedef _::IndexingIterator Iterator; + inline Iterator begin() const { return Iterator(this, 0); } + inline Iterator end() const { return Iterator(this, size()); } + +private: + InterfaceSchema parent; + List::Reader list; + + inline SuperclassList(InterfaceSchema parent, List::Reader list) + : parent(parent), list(list) {} + + friend class InterfaceSchema; +}; + +// ------------------------------------------------------------------- + +class ConstSchema: public Schema { + // Represents a constant declaration. + // + // `ConstSchema` can be implicitly cast to DynamicValue to read its value. + +public: + inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {} + + template + ReaderFor as() const; + // Read the constant's value. This is a convenience method equivalent to casting the ConstSchema + // to a DynamicValue and then calling its `as()` method. For dependency reasons, this method + // is defined in , which you must #include explicitly. + + uint32_t getValueSchemaOffset() const; + // Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer + // type, this gets the offset from the beginning of the constant's schema node to a pointer + // representing the constant value. + + Type getType() const; + +private: + ConstSchema(Schema base): Schema(base) {} + friend class Schema; +}; + +// ------------------------------------------------------------------- + +class Type { +public: + struct BrandParameter { + uint64_t scopeId; + uint index; + }; + struct ImplicitParameter { + uint index; + }; + + inline Type(); + inline Type(schema::Type::Which primitive); + inline Type(StructSchema schema); + inline Type(EnumSchema schema); + inline Type(InterfaceSchema schema); + inline Type(ListSchema schema); + inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind); + inline Type(BrandParameter param); + inline Type(ImplicitParameter param); + + template + inline static Type from(); + + inline schema::Type::Which which() const; + + StructSchema asStruct() const; + EnumSchema asEnum() const; + InterfaceSchema asInterface() const; + ListSchema asList() const; + // Each of these methods may only be called if which() returns the corresponding type. + + kj::Maybe getBrandParameter() const; + // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular + // AnyPointer and not a parameter. + + kj::Maybe getImplicitParameter() const; + // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular + // AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods. + + inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const; + // Only callable if which() returns ANY_POINTER. + + inline bool isVoid() const; + inline bool isBool() const; + inline bool isInt8() const; + inline bool isInt16() const; + inline bool isInt32() const; + inline bool isInt64() const; + inline bool isUInt8() const; + inline bool isUInt16() const; + inline bool isUInt32() const; + inline bool isUInt64() const; + inline bool isFloat32() const; + inline bool isFloat64() const; + inline bool isText() const; + inline bool isData() const; + inline bool isList() const; + inline bool isEnum() const; + inline bool isStruct() const; + inline bool isInterface() const; + inline bool isAnyPointer() const; + + bool operator==(const Type& other) const; + inline bool operator!=(const Type& other) const { return !(*this == other); } + + size_t hashCode() const; + + inline Type wrapInList(uint depth = 1) const; + // Return the Type formed by wrapping this type in List() `depth` times. + + inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema); + // For internal use. + +private: + schema::Type::Which baseType; // type not including applications of List() + uint8_t listDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ... + + bool isImplicitParam; + // If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId + // must be zero, and paramIndex indicates the parameter index. + + union { + uint16_t paramIndex; + // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the + // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID + // of the scope where the parameter was defined. + + schema::Type::AnyPointer::Unconstrained::Which anyPointerKind; + // If scopeId is zero and isImplicitParam is false. + }; + + union { + const _::RawBrandedSchema* schema; // if type is struct, enum, interface... + uint64_t scopeId; // if type is AnyPointer but it's actually a type parameter... + }; + + Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema) + : baseType(baseType), listDepth(listDepth), schema(schema) { + KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER); + } + + void requireUsableAs(Type expected) const; + + friend class ListSchema; // only for requireUsableAs() +}; + +// ------------------------------------------------------------------- + +class ListSchema { + // ListSchema is a little different because list types are not described by schema nodes. So, + // ListSchema doesn't subclass Schema. + +public: + ListSchema() = default; + + static ListSchema of(schema::Type::Which primitiveType); + static ListSchema of(StructSchema elementType); + static ListSchema of(EnumSchema elementType); + static ListSchema of(InterfaceSchema elementType); + static ListSchema of(ListSchema elementType); + static ListSchema of(Type elementType); + // Construct the schema for a list of the given type. + + static ListSchema of(schema::Type::Reader elementType, Schema context) + KJ_DEPRECATED("Does not handle generics correctly."); + // DEPRECATED: This method cannot correctly account for generic type parameter bindings that + // may apply to the input type. Instead of using this method, use a method of the Schema API + // that corresponds to the exact kind of dependency. For example, to get a field type, use + // StructSchema::Field::getType(). + // + // Construct from an element type schema. Requires a context which can handle getDependency() + // requests for any type ID found in the schema. + + Type getElementType() const; + + inline schema::Type::Which whichElementType() const; + // Get the element type's "which()". ListSchema does not actually store a schema::Type::Reader + // describing the element type, but if it did, this would be equivalent to calling + // .getBody().which() on that type. + + StructSchema getStructElementType() const; + EnumSchema getEnumElementType() const; + InterfaceSchema getInterfaceElementType() const; + ListSchema getListElementType() const; + // Get the schema for complex element types. Each of these throws an exception if the element + // type is not of the requested kind. + + inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; } + inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; } + + template + void requireUsableAs() const; + +private: + Type elementType; + + inline explicit ListSchema(Type elementType): elementType(elementType) {} + + template + struct FromImpl; + template static inline ListSchema fromImpl() { + return FromImpl::get(); + } + + void requireUsableAs(ListSchema expected) const; + + friend class Schema; +}; + +// ======================================================================================= +// inline implementation + +template <> inline schema::Type::Which Schema::from() { return schema::Type::VOID; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::BOOL; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT8; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT16; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::INT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT8; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT16; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::UINT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT32; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::FLOAT64; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::TEXT; } +template <> inline schema::Type::Which Schema::from() { return schema::Type::DATA; } + +inline Schema Schema::getDependency(uint64_t id) const { + return getDependency(id, 0); +} + +inline bool Schema::isBranded() const { + return raw != &raw->generic->defaultBrand; +} + +inline Schema Schema::getGeneric() const { + return Schema(&raw->generic->defaultBrand); +} + +template +inline void Schema::requireUsableAs() const { + requireUsableAs(&_::rawSchema()); +} + +inline bool StructSchema::Field::operator==(const Field& other) const { + return parent == other.parent && index == other.index; +} +inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const { + return parent == other.parent && ordinal == other.ordinal; +} +inline bool InterfaceSchema::Method::operator==(const Method& other) const { + return parent == other.parent && ordinal == other.ordinal; +} + +inline ListSchema ListSchema::of(StructSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(EnumSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(InterfaceSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(ListSchema elementType) { + return ListSchema(Type(elementType)); +} +inline ListSchema ListSchema::of(Type elementType) { + return ListSchema(elementType); +} + +inline Type ListSchema::getElementType() const { + return elementType; +} + +inline schema::Type::Which ListSchema::whichElementType() const { + return elementType.which(); +} + +inline StructSchema ListSchema::getStructElementType() const { + return elementType.asStruct(); +} + +inline EnumSchema ListSchema::getEnumElementType() const { + return elementType.asEnum(); +} + +inline InterfaceSchema ListSchema::getInterfaceElementType() const { + return elementType.asInterface(); +} + +inline ListSchema ListSchema::getListElementType() const { + return elementType.asList(); +} + +template +inline void ListSchema::requireUsableAs() const { + static_assert(kind() == Kind::LIST, + "ListSchema::requireUsableAs() requires T is a list type."); + requireUsableAs(Schema::from()); +} + +inline void ListSchema::requireUsableAs(ListSchema expected) const { + elementType.requireUsableAs(expected.elementType); +} + +template +struct ListSchema::FromImpl> { + static inline ListSchema get() { return of(Schema::from()); } +}; + +inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {} +inline Type::Type(schema::Type::Which primitive) + : baseType(primitive), listDepth(0), isImplicitParam(false) { + KJ_IREQUIRE(primitive != schema::Type::STRUCT && + primitive != schema::Type::ENUM && + primitive != schema::Type::INTERFACE && + primitive != schema::Type::LIST); + if (primitive == schema::Type::ANY_POINTER) { + scopeId = 0; + anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND; + } else { + schema = nullptr; + } +} +inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema) + : baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) { + KJ_IREQUIRE(derived == schema::Type::STRUCT || + derived == schema::Type::ENUM || + derived == schema::Type::INTERFACE); +} + +inline Type::Type(StructSchema schema) + : baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {} +inline Type::Type(EnumSchema schema) + : baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {} +inline Type::Type(InterfaceSchema schema) + : baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {} +inline Type::Type(ListSchema schema) + : Type(schema.getElementType()) { ++listDepth; } +inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), + anyPointerKind(anyPointerKind), scopeId(0) {} +inline Type::Type(BrandParameter param) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), + paramIndex(param.index), scopeId(param.scopeId) {} +inline Type::Type(ImplicitParameter param) + : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true), + paramIndex(param.index), scopeId(0) {} + +inline schema::Type::Which Type::which() const { + return listDepth > 0 ? schema::Type::LIST : baseType; +} + +inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const { + KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER); + return !isImplicitParam && scopeId == 0 ? anyPointerKind + : schema::Type::AnyPointer::Unconstrained::ANY_KIND; +} + +template +inline Type Type::from() { return Type(Schema::from()); } + +inline bool Type::isVoid () const { return baseType == schema::Type::VOID && listDepth == 0; } +inline bool Type::isBool () const { return baseType == schema::Type::BOOL && listDepth == 0; } +inline bool Type::isInt8 () const { return baseType == schema::Type::INT8 && listDepth == 0; } +inline bool Type::isInt16 () const { return baseType == schema::Type::INT16 && listDepth == 0; } +inline bool Type::isInt32 () const { return baseType == schema::Type::INT32 && listDepth == 0; } +inline bool Type::isInt64 () const { return baseType == schema::Type::INT64 && listDepth == 0; } +inline bool Type::isUInt8 () const { return baseType == schema::Type::UINT8 && listDepth == 0; } +inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16 && listDepth == 0; } +inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32 && listDepth == 0; } +inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64 && listDepth == 0; } +inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32 && listDepth == 0; } +inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64 && listDepth == 0; } +inline bool Type::isText () const { return baseType == schema::Type::TEXT && listDepth == 0; } +inline bool Type::isData () const { return baseType == schema::Type::DATA && listDepth == 0; } +inline bool Type::isList () const { return listDepth > 0; } +inline bool Type::isEnum () const { return baseType == schema::Type::ENUM && listDepth == 0; } +inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT && listDepth == 0; } +inline bool Type::isInterface() const { + return baseType == schema::Type::INTERFACE && listDepth == 0; +} +inline bool Type::isAnyPointer() const { + return baseType == schema::Type::ANY_POINTER && listDepth == 0; +} + +inline Type Type::wrapInList(uint depth) const { + Type result = *this; + result.listDepth += depth; + return result; +} + +} // namespace capnp + +#endif // CAPNP_SCHEMA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-async-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-async-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,344 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-async.h" +#include "serialize.h" +#include +#include +#include +#include +#include "test-util.h" +#include + +#if _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +namespace kj { + namespace _ { + int win32Socketpair(SOCKET socks[2]); + } +} +#else +#include +#endif + +namespace capnp { +namespace _ { // private +namespace { + +#if _WIN32 +inline void delay() { Sleep(5); } +#else +inline void delay() { usleep(5000); } +#endif + +class FragmentingOutputStream: public kj::OutputStream { +public: + FragmentingOutputStream(kj::OutputStream& inner): inner(inner) {} + + void write(const void* buffer, size_t size) override { + while (size > 0) { + delay(); + size_t n = rand() % size + 1; + inner.write(buffer, n); + buffer = reinterpret_cast(buffer) + n; + size -= n; + } + } + +private: + kj::OutputStream& inner; +}; + +class TestMessageBuilder: public MallocMessageBuilder { + // A MessageBuilder that tries to allocate an exact number of total segments, by allocating + // minimum-size segments until it reaches the number, then allocating one large segment to + // finish. + +public: + explicit TestMessageBuilder(uint desiredSegmentCount) + : MallocMessageBuilder(0, AllocationStrategy::FIXED_SIZE), + desiredSegmentCount(desiredSegmentCount) {} + ~TestMessageBuilder() { + EXPECT_EQ(0u, desiredSegmentCount); + } + + kj::ArrayPtr allocateSegment(uint minimumSize) override { + if (desiredSegmentCount <= 1) { + if (desiredSegmentCount < 1) { + ADD_FAILURE() << "Allocated more segments than desired."; + } else { + --desiredSegmentCount; + } + return MallocMessageBuilder::allocateSegment(8192); + } else { + --desiredSegmentCount; + return MallocMessageBuilder::allocateSegment(minimumSize); + } + } + +private: + uint desiredSegmentCount; +}; + +class PipeWithSmallBuffer { +public: +#ifdef _WIN32 +#define KJ_SOCKCALL KJ_WINSOCK +#ifndef SHUT_WR +#define SHUT_WR SD_SEND +#endif +#define socketpair(family, type, flags, fds) kj::_::win32Socketpair(fds) +#else +#define KJ_SOCKCALL KJ_SYSCALL +#endif + + PipeWithSmallBuffer() { + // Use a socketpair rather than a pipe so that we can set the buffer size extremely small. + KJ_SOCKCALL(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); + + KJ_SOCKCALL(shutdown(fds[0], SHUT_WR)); + // Note: OSX reports ENOTCONN if we also try to shutdown(fds[1], SHUT_RD). + + // Request that the buffer size be as small as possible, to force the event loop to kick in. + // FUN STUFF: + // - On Linux, the kernel rounds up to the smallest size it permits, so we can ask for a size of + // zero. + // - On OSX, the kernel reports EINVAL on zero, but will dutifully use a 1-byte buffer if we + // set the size to 1. This tends to cause stack overflows due to ridiculously long promise + // chains. + // - Cygwin will apparently actually use a buffer size of 0 and therefore block forever waiting + // for buffer space. + // - GNU HURD throws ENOPROTOOPT for SO_RCVBUF. Apparently, technically, a Unix domain socket + // has only one buffer, and it's controlled via SO_SNDBUF on the other end. OK, we'll ignore + // errors on SO_RCVBUF, then. + // + // Anyway, we now use 127 to avoid these issues (but also to screw around with non-word-boundary + // writes). + uint small = 127; + setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF, (const char*)&small, sizeof(small)); + KJ_SOCKCALL(setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF, (const char*)&small, sizeof(small))); + } + ~PipeWithSmallBuffer() { +#if _WIN32 + closesocket(fds[0]); + closesocket(fds[1]); +#else + close(fds[0]); + close(fds[1]); +#endif + } + + inline int operator[](uint index) { return fds[index]; } + +private: +#ifdef _WIN32 + SOCKET fds[2]; +#else + int fds[2]; +#endif +}; + +#if _WIN32 +// Sockets on win32 are not file descriptors. Ugh. +// +// TODO(cleanup): Maybe put these somewhere reusable? kj/io.h is inappropriate since we don't +// really want to link against winsock. + +class SocketOutputStream: public kj::OutputStream { +public: + explicit SocketOutputStream(SOCKET fd): fd(fd) {} + + void write(const void* buffer, size_t size) override { + const char* ptr = reinterpret_cast(buffer); + while (size > 0) { + kj::miniposix::ssize_t n; + KJ_SOCKCALL(n = send(fd, ptr, size, 0)); + size -= n; + ptr += n; + } + } + +private: + SOCKET fd; +}; + +class SocketInputStream: public kj::InputStream { +public: + explicit SocketInputStream(SOCKET fd): fd(fd) {} + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + char* ptr = reinterpret_cast(buffer); + size_t total = 0; + while (total < minBytes) { + kj::miniposix::ssize_t n; + KJ_SOCKCALL(n = recv(fd, ptr, maxBytes, 0)); + total += n; + maxBytes -= n; + ptr += n; + } + return total; + } + +private: + SOCKET fd; +}; +#else // _WIN32 +typedef kj::FdOutputStream SocketOutputStream; +typedef kj::FdInputStream SocketInputStream; +#endif // _WIN32, else + +TEST(SerializeAsyncTest, ParseAsync) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto input = ioContext.lowLevelProvider->wrapInputFd(fds[0]); + SocketOutputStream rawOutput(fds[1]); + FragmentingOutputStream output(rawOutput); + + TestMessageBuilder message(1); + initTestMessage(message.getRoot()); + + kj::Thread thread([&]() { + writeMessage(output, message); + }); + + auto received = readMessage(*input).wait(ioContext.waitScope); + + checkTestMessage(received->getRoot()); +} + +TEST(SerializeAsyncTest, ParseAsyncOddSegmentCount) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto input = ioContext.lowLevelProvider->wrapInputFd(fds[0]); + SocketOutputStream rawOutput(fds[1]); + FragmentingOutputStream output(rawOutput); + + TestMessageBuilder message(7); + initTestMessage(message.getRoot()); + + kj::Thread thread([&]() { + writeMessage(output, message); + }); + + auto received = readMessage(*input).wait(ioContext.waitScope); + + checkTestMessage(received->getRoot()); +} + +TEST(SerializeAsyncTest, ParseAsyncEvenSegmentCount) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto input = ioContext.lowLevelProvider->wrapInputFd(fds[0]); + SocketOutputStream rawOutput(fds[1]); + FragmentingOutputStream output(rawOutput); + + TestMessageBuilder message(10); + initTestMessage(message.getRoot()); + + kj::Thread thread([&]() { + writeMessage(output, message); + }); + + auto received = readMessage(*input).wait(ioContext.waitScope); + + checkTestMessage(received->getRoot()); +} + +TEST(SerializeAsyncTest, WriteAsync) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto output = ioContext.lowLevelProvider->wrapOutputFd(fds[1]); + + TestMessageBuilder message(1); + auto root = message.getRoot(); + auto list = root.initStructList(16); + for (auto element: list) { + initTestMessage(element); + } + + kj::Thread thread([&]() { + SocketInputStream input(fds[0]); + InputStreamMessageReader reader(input); + auto listReader = reader.getRoot().getStructList(); + EXPECT_EQ(list.size(), listReader.size()); + for (auto element: listReader) { + checkTestMessage(element); + } + }); + + writeMessage(*output, message).wait(ioContext.waitScope); +} + +TEST(SerializeAsyncTest, WriteAsyncOddSegmentCount) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto output = ioContext.lowLevelProvider->wrapOutputFd(fds[1]); + + TestMessageBuilder message(7); + auto root = message.getRoot(); + auto list = root.initStructList(16); + for (auto element: list) { + initTestMessage(element); + } + + kj::Thread thread([&]() { + SocketInputStream input(fds[0]); + InputStreamMessageReader reader(input); + auto listReader = reader.getRoot().getStructList(); + EXPECT_EQ(list.size(), listReader.size()); + for (auto element: listReader) { + checkTestMessage(element); + } + }); + + writeMessage(*output, message).wait(ioContext.waitScope); +} + +TEST(SerializeAsyncTest, WriteAsyncEvenSegmentCount) { + PipeWithSmallBuffer fds; + auto ioContext = kj::setupAsyncIo(); + auto output = ioContext.lowLevelProvider->wrapOutputFd(fds[1]); + + TestMessageBuilder message(10); + auto root = message.getRoot(); + auto list = root.initStructList(16); + for (auto element: list) { + initTestMessage(element); + } + + kj::Thread thread([&]() { + SocketInputStream input(fds[0]); + InputStreamMessageReader reader(input); + auto listReader = reader.getRoot().getStructList(); + EXPECT_EQ(list.size(), listReader.size()); + for (auto element: listReader) { + checkTestMessage(element); + } + }); + + writeMessage(*output, message).wait(ioContext.waitScope); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-async.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-async.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,220 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-async.h" +#include + +namespace capnp { + +namespace { + +class AsyncMessageReader: public MessageReader { +public: + inline AsyncMessageReader(ReaderOptions options): MessageReader(options) { + memset(firstWord, 0, sizeof(firstWord)); + } + ~AsyncMessageReader() noexcept(false) {} + + kj::Promise read(kj::AsyncInputStream& inputStream, kj::ArrayPtr scratchSpace); + + // implements MessageReader ---------------------------------------- + + kj::ArrayPtr getSegment(uint id) override { + if (id >= segmentCount()) { + return nullptr; + } else { + uint32_t size = id == 0 ? segment0Size() : moreSizes[id - 1].get(); + return kj::arrayPtr(segmentStarts[id], size); + } + } + +private: + _::WireValue firstWord[2]; + kj::Array<_::WireValue> moreSizes; + kj::Array segmentStarts; + + kj::Array ownedSpace; + // Only if scratchSpace wasn't big enough. + + inline uint segmentCount() { return firstWord[0].get() + 1; } + inline uint segment0Size() { return firstWord[1].get(); } + + kj::Promise readAfterFirstWord( + kj::AsyncInputStream& inputStream, kj::ArrayPtr scratchSpace); + kj::Promise readSegments( + kj::AsyncInputStream& inputStream, kj::ArrayPtr scratchSpace); +}; + +kj::Promise AsyncMessageReader::read(kj::AsyncInputStream& inputStream, + kj::ArrayPtr scratchSpace) { + return inputStream.tryRead(firstWord, sizeof(firstWord), sizeof(firstWord)) + .then([this,&inputStream,KJ_CPCAP(scratchSpace)](size_t n) mutable -> kj::Promise { + if (n == 0) { + return false; + } else if (n < sizeof(firstWord)) { + // EOF in first word. + KJ_FAIL_REQUIRE("Premature EOF.") { + return false; + } + } + + return readAfterFirstWord(inputStream, scratchSpace).then([]() { return true; }); + }); +} + +kj::Promise AsyncMessageReader::readAfterFirstWord(kj::AsyncInputStream& inputStream, + kj::ArrayPtr scratchSpace) { + if (segmentCount() == 0) { + firstWord[1].set(0); + } + + // Reject messages with too many segments for security reasons. + KJ_REQUIRE(segmentCount() < 512, "Message has too many segments.") { + return kj::READY_NOW; // exception will be propagated + } + + if (segmentCount() > 1) { + // Read sizes for all segments except the first. Include padding if necessary. + moreSizes = kj::heapArray<_::WireValue>(segmentCount() & ~1); + return inputStream.read(moreSizes.begin(), moreSizes.size() * sizeof(moreSizes[0])) + .then([this,&inputStream,KJ_CPCAP(scratchSpace)]() mutable { + return readSegments(inputStream, scratchSpace); + }); + } else { + return readSegments(inputStream, scratchSpace); + } +} + +kj::Promise AsyncMessageReader::readSegments(kj::AsyncInputStream& inputStream, + kj::ArrayPtr scratchSpace) { + size_t totalWords = segment0Size(); + + if (segmentCount() > 1) { + for (uint i = 0; i < segmentCount() - 1; i++) { + totalWords += moreSizes[i].get(); + } + } + + // Don't accept a message which the receiver couldn't possibly traverse without hitting the + // traversal limit. Without this check, a malicious client could transmit a very large segment + // size to make the receiver allocate excessive space and possibly crash. + KJ_REQUIRE(totalWords <= getOptions().traversalLimitInWords, + "Message is too large. To increase the limit on the receiving end, see " + "capnp::ReaderOptions.") { + return kj::READY_NOW; // exception will be propagated + } + + if (scratchSpace.size() < totalWords) { + // TODO(perf): Consider allocating each segment as a separate chunk to reduce memory + // fragmentation. + ownedSpace = kj::heapArray(totalWords); + scratchSpace = ownedSpace; + } + + segmentStarts = kj::heapArray(segmentCount()); + + segmentStarts[0] = scratchSpace.begin(); + + if (segmentCount() > 1) { + size_t offset = segment0Size(); + + for (uint i = 1; i < segmentCount(); i++) { + segmentStarts[i] = scratchSpace.begin() + offset; + offset += moreSizes[i-1].get(); + } + } + + return inputStream.read(scratchSpace.begin(), totalWords * sizeof(word)); +} + + +} // namespace + +kj::Promise> readMessage( + kj::AsyncInputStream& input, ReaderOptions options, kj::ArrayPtr scratchSpace) { + auto reader = kj::heap(options); + auto promise = reader->read(input, scratchSpace); + return promise.then(kj::mvCapture(reader, [](kj::Own&& reader, bool success) { + KJ_REQUIRE(success, "Premature EOF.") { break; } + return kj::mv(reader); + })); +} + +kj::Promise>> tryReadMessage( + kj::AsyncInputStream& input, ReaderOptions options, kj::ArrayPtr scratchSpace) { + auto reader = kj::heap(options); + auto promise = reader->read(input, scratchSpace); + return promise.then(kj::mvCapture(reader, + [](kj::Own&& reader, bool success) -> kj::Maybe> { + if (success) { + return kj::mv(reader); + } else { + return nullptr; + } + })); +} + +// ======================================================================================= + +namespace { + +struct WriteArrays { + // Holds arrays that must remain valid until a write completes. + + kj::Array<_::WireValue> table; + kj::Array> pieces; +}; + +} // namespace + +kj::Promise writeMessage(kj::AsyncOutputStream& output, + kj::ArrayPtr> segments) { + KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message."); + + WriteArrays arrays; + arrays.table = kj::heapArray<_::WireValue>((segments.size() + 2) & ~size_t(1)); + + // We write the segment count - 1 because this makes the first word zero for single-segment + // messages, improving compression. We don't bother doing this with segment sizes because + // one-word segments are rare anyway. + arrays.table[0].set(segments.size() - 1); + for (uint i = 0; i < segments.size(); i++) { + arrays.table[i + 1].set(segments[i].size()); + } + if (segments.size() % 2 == 0) { + // Set padding byte. + arrays.table[segments.size() + 1].set(0); + } + + arrays.pieces = kj::heapArray>(segments.size() + 1); + arrays.pieces[0] = arrays.table.asBytes(); + + for (uint i = 0; i < segments.size(); i++) { + arrays.pieces[i + 1] = segments[i].asBytes(); + } + + auto promise = output.write(arrays.pieces); + + // Make sure the arrays aren't freed until the write completes. + return promise.then(kj::mvCapture(arrays, [](WriteArrays&&) {})); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-async.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-async.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,64 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_ASYNC_H_ +#define CAPNP_SERIALIZE_ASYNC_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "message.h" + +namespace capnp { + +kj::Promise> readMessage( + kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Read a message asynchronously. +// +// `input` must remain valid until the returned promise resolves (or is canceled). +// +// `scratchSpace`, if provided, must remain valid until the returned MessageReader is destroyed. + +kj::Promise>> tryReadMessage( + kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Like `readMessage` but returns null on EOF. + +kj::Promise writeMessage(kj::AsyncOutputStream& output, + kj::ArrayPtr> segments) + KJ_WARN_UNUSED_RESULT; +kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) + KJ_WARN_UNUSED_RESULT; +// Write asynchronously. The parameters must remain valid until the returned promise resolves. + +// ======================================================================================= +// inline implementation details + +inline kj::Promise writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) { + return writeMessage(output, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_ASYNC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-packed-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-packed-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,582 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-packed.h" +#include +#include +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +class TestPipe: public kj::BufferedInputStream, public kj::OutputStream { +public: + TestPipe() + : preferredReadSize(kj::maxValue), readPos(0) {} + explicit TestPipe(size_t preferredReadSize) + : preferredReadSize(preferredReadSize), readPos(0) {} + ~TestPipe() {} + + const std::string& getData() { return data; } + + kj::ArrayPtr getArray() { + return kj::arrayPtr(reinterpret_cast(data.data()), data.size()); + } + + void resetRead(size_t preferredReadSize = kj::maxValue) { + readPos = 0; + this->preferredReadSize = preferredReadSize; + } + + bool allRead() { + return readPos == data.size(); + } + + void clear(size_t preferredReadSize = kj::maxValue) { + resetRead(preferredReadSize); + data.clear(); + } + + void write(const void* buffer, size_t size) override { + data.append(reinterpret_cast(buffer), size); + } + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + KJ_ASSERT(maxBytes <= data.size() - readPos, "Overran end of stream."); + size_t amount = kj::min(maxBytes, kj::max(minBytes, preferredReadSize)); + memcpy(buffer, data.data() + readPos, amount); + readPos += amount; + return amount; + } + + void skip(size_t bytes) override { + KJ_ASSERT(bytes <= data.size() - readPos, "Overran end of stream."); + readPos += bytes; + } + + kj::ArrayPtr tryGetReadBuffer() override { + size_t amount = kj::min(data.size() - readPos, preferredReadSize); + return kj::arrayPtr(reinterpret_cast(data.data() + readPos), amount); + } + +private: + size_t preferredReadSize; + std::string data; + std::string::size_type readPos; +}; + +void expectPacksTo(kj::ArrayPtr unpacked, kj::ArrayPtr packed) { + TestPipe pipe; + + EXPECT_EQ(unpacked.size(), computeUnpackedSizeInWords(packed) * sizeof(word)); + + // ----------------------------------------------------------------- + // write + + { + kj::BufferedOutputStreamWrapper bufferedOut(pipe); + PackedOutputStream packedOut(bufferedOut); + packedOut.write(unpacked.begin(), unpacked.size()); + } + + if (pipe.getData() != std::string(packed.asChars().begin(), packed.asChars().size())) { + KJ_FAIL_ASSERT("Tried to pack `unpacked`, expected `packed`, got `pipe.getData()`", + unpacked, packed, pipe.getData()); + return; + } + + // ----------------------------------------------------------------- + // read + + kj::Array roundTrip = kj::heapArray(unpacked.size()); + + { + PackedInputStream packedIn(pipe); + packedIn.InputStream::read(roundTrip.begin(), roundTrip.size()); + EXPECT_TRUE(pipe.allRead()); + } + + if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { + KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", + packed, unpacked, roundTrip); + return; + } + + for (uint blockSize = 1; blockSize < packed.size(); blockSize <<= 1) { + pipe.resetRead(blockSize); + + { + PackedInputStream packedIn(pipe); + packedIn.InputStream::read(roundTrip.begin(), roundTrip.size()); + EXPECT_TRUE(pipe.allRead()); + } + + if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { + KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", + packed, blockSize, unpacked, roundTrip); + } + } + + // ----------------------------------------------------------------- + // skip + + pipe.resetRead(); + + { + PackedInputStream packedIn(pipe); + packedIn.skip(unpacked.size()); + EXPECT_TRUE(pipe.allRead()); + } + + for (uint blockSize = 1; blockSize < packed.size(); blockSize <<= 1) { + pipe.resetRead(blockSize); + + { + PackedInputStream packedIn(pipe); + packedIn.skip(unpacked.size()); + EXPECT_TRUE(pipe.allRead()); + } + } + + pipe.clear(); + + // ----------------------------------------------------------------- + // write / read multiple + + { + kj::BufferedOutputStreamWrapper bufferedOut(pipe); + PackedOutputStream packedOut(bufferedOut); + for (uint i = 0; i < 5; i++) { + packedOut.write(unpacked.begin(), unpacked.size()); + } + } + + for (uint i = 0; i < 5; i++) { + PackedInputStream packedIn(pipe); + packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size()); + + if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { + KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", + packed, i, unpacked, roundTrip); + } + } + + EXPECT_TRUE(pipe.allRead()); +} + +#ifdef __CDT_PARSER__ +// CDT doesn't seem to understand these initializer lists. +#define expectPacksTo(...) +#endif + +TEST(Packed, SimplePacking) { + expectPacksTo({}, {}); + expectPacksTo({0,0,0,0,0,0,0,0}, {0,0}); + expectPacksTo({0,0,12,0,0,34,0,0}, {0x24,12,34}); + expectPacksTo({1,3,2,4,5,7,6,8}, {0xff,1,3,2,4,5,7,6,8,0}); + expectPacksTo({0,0,0,0,0,0,0,0,1,3,2,4,5,7,6,8}, {0,0,0xff,1,3,2,4,5,7,6,8,0}); + expectPacksTo({0,0,12,0,0,34,0,0,1,3,2,4,5,7,6,8}, {0x24,12,34,0xff,1,3,2,4,5,7,6,8,0}); + expectPacksTo({1,3,2,4,5,7,6,8,8,6,7,4,5,2,3,1}, {0xff,1,3,2,4,5,7,6,8,1,8,6,7,4,5,2,3,1}); + + expectPacksTo( + {1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 0,2,4,0,9,0,5,1}, + {0xff,1,2,3,4,5,6,7,8, 3, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 0xd6,2,4,9,5,1}); + expectPacksTo( + {1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 6,2,4,3,9,0,5,1, 1,2,3,4,5,6,7,8, 0,2,4,0,9,0,5,1}, + {0xff,1,2,3,4,5,6,7,8, 3, 1,2,3,4,5,6,7,8, 6,2,4,3,9,0,5,1, 1,2,3,4,5,6,7,8, 0xd6,2,4,9,5,1}); + + expectPacksTo( + {8,0,100,6,0,1,1,2, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,1,0,2,0,3,1}, + {0xed,8,100,6,1,1,2, 0,2, 0xd4,1,2,3,1}); +} + +// ======================================================================================= + +class TestMessageBuilder: public MallocMessageBuilder { + // A MessageBuilder that tries to allocate an exact number of total segments, by allocating + // minimum-size segments until it reaches the number, then allocating one large segment to + // finish. + +public: + explicit TestMessageBuilder(uint desiredSegmentCount) + : MallocMessageBuilder(0, AllocationStrategy::FIXED_SIZE), + desiredSegmentCount(desiredSegmentCount) {} + ~TestMessageBuilder() { + EXPECT_EQ(0u, desiredSegmentCount); + } + + kj::ArrayPtr allocateSegment(uint minimumSize) override { + if (desiredSegmentCount <= 1) { + if (desiredSegmentCount < 1) { + ADD_FAILURE() << "Allocated more segments than desired."; + } else { + --desiredSegmentCount; + } + return MallocMessageBuilder::allocateSegment(SUGGESTED_FIRST_SEGMENT_WORDS); + } else { + --desiredSegmentCount; + return MallocMessageBuilder::allocateSegment(minimumSize); + } + } + +private: + uint desiredSegmentCount; +}; + +TEST(Packed, RoundTrip) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripScratchSpace) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + word scratch[1024]; + PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr(scratch, 1024)); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripLazy) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripOddSegmentCount) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripOddSegmentCountLazy) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripEvenSegmentCount) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripEvenSegmentCountLazy) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); +} + +TEST(Packed, RoundTripTwoMessages) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + TestMessageBuilder builder2(1); + builder2.initRoot().setTextField("Second message."); + + TestPipe pipe; + writePackedMessage(pipe, builder); + writePackedMessage(pipe, builder2); + + EXPECT_EQ(computeSerializedSizeInWords(builder) + computeSerializedSizeInWords(builder2), + computeUnpackedSizeInWords(pipe.getArray())); + + { + PackedMessageReader reader(pipe); + checkTestMessage(reader.getRoot()); + } + + { + PackedMessageReader reader(pipe); + EXPECT_EQ("Second message.", reader.getRoot().getTextField()); + } +} + +// ======================================================================================= + +TEST(Packed, RoundTripAllZero) { + TestMessageBuilder builder(1); + builder.initRoot(); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); + + // Segment table packs to 2 bytes. + // Root pointer packs to 3 bytes. + // Content packs to 2 bytes (zero span). + EXPECT_LE(pipe.getData().size(), 7u); +} + +TEST(Packed, RoundTripAllZeroScratchSpace) { + TestMessageBuilder builder(1); + builder.initRoot(); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + word scratch[1024]; + PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr(scratch, 1024)); + checkTestMessageAllZero(reader.getRoot()); +} + +TEST(Packed, RoundTripAllZeroLazy) { + TestMessageBuilder builder(1); + builder.initRoot(); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); +} + +TEST(Packed, RoundTripAllZeroOddSegmentCount) { + TestMessageBuilder builder(3); + builder.initRoot().initStructField().initStructField(); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); +} + +TEST(Packed, RoundTripAllZeroOddSegmentCountLazy) { + TestMessageBuilder builder(3); + builder.initRoot().initStructField().initStructField(); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); +} + +TEST(Packed, RoundTripAllZeroEvenSegmentCount) { + TestMessageBuilder builder(2); + builder.initRoot().initStructField().initStructField(); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); +} + +TEST(Packed, RoundTripAllZeroEvenSegmentCountLazy) { + TestMessageBuilder builder(2); + builder.initRoot().initStructField().initStructField(); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + checkTestMessageAllZero(reader.getRoot()); +} + +// ======================================================================================= + +TEST(Packed, RoundTripHugeString) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(1); + builder.initRoot().setTextField(huge); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringScratchSpace) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(1); + builder.initRoot().setTextField(huge); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + word scratch[1024]; + PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr(scratch, 1024)); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringLazy) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(1); + builder.initRoot().setTextField(huge); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringOddSegmentCount) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(3); + builder.initRoot().setTextField(huge); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringOddSegmentCountLazy) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(3); + builder.initRoot().setTextField(huge); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringEvenSegmentCount) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(2); + builder.initRoot().setTextField(huge); + + TestPipe pipe; + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +TEST(Packed, RoundTripHugeStringEvenSegmentCountLazy) { + kj::String huge = kj::heapString(5023); + memset(huge.begin(), 'x', 5023); + + TestMessageBuilder builder(2); + builder.initRoot().setTextField(huge); + + TestPipe pipe(1); + writePackedMessage(pipe, builder); + + EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); + + PackedMessageReader reader(pipe); + EXPECT_TRUE(reader.getRoot().getTextField() == huge); +} + +// TODO(test): Test error cases. + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-packed.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-packed.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,507 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-packed.h" +#include +#include "layout.h" +#include + +namespace capnp { + +namespace _ { // private + +PackedInputStream::PackedInputStream(kj::BufferedInputStream& inner): inner(inner) {} +PackedInputStream::~PackedInputStream() noexcept(false) {} + +size_t PackedInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) { + if (maxBytes == 0) { + return 0; + } + + KJ_DREQUIRE(minBytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned."); + KJ_DREQUIRE(maxBytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned."); + + uint8_t* __restrict__ out = reinterpret_cast(dst); + uint8_t* const outEnd = reinterpret_cast(dst) + maxBytes; + uint8_t* const outMin = reinterpret_cast(dst) + minBytes; + + kj::ArrayPtr buffer = inner.tryGetReadBuffer(); + if (buffer.size() == 0) { + return 0; + } + const uint8_t* __restrict__ in = reinterpret_cast(buffer.begin()); + +#define REFRESH_BUFFER() \ + inner.skip(buffer.size()); \ + buffer = inner.getReadBuffer(); \ + KJ_REQUIRE(buffer.size() > 0, "Premature end of packed input.") { \ + return out - reinterpret_cast(dst); \ + } \ + in = reinterpret_cast(buffer.begin()) + +#define BUFFER_END (reinterpret_cast(buffer.end())) +#define BUFFER_REMAINING ((size_t)(BUFFER_END - in)) + + for (;;) { + uint8_t tag; + + KJ_DASSERT((out - reinterpret_cast(dst)) % sizeof(word) == 0, + "Output pointer should always be aligned here."); + + if (BUFFER_REMAINING < 10) { + if (out >= outMin) { + // We read at least the minimum amount, so go ahead and return. + inner.skip(in - reinterpret_cast(buffer.begin())); + return out - reinterpret_cast(dst); + } + + if (BUFFER_REMAINING == 0) { + REFRESH_BUFFER(); + continue; + } + + // We have at least 1, but not 10, bytes available. We need to read slowly, doing a bounds + // check on each byte. + + tag = *in++; + + for (uint i = 0; i < 8; i++) { + if (tag & (1u << i)) { + if (BUFFER_REMAINING == 0) { + REFRESH_BUFFER(); + } + *out++ = *in++; + } else { + *out++ = 0; + } + } + + if (BUFFER_REMAINING == 0 && (tag == 0 || tag == 0xffu)) { + REFRESH_BUFFER(); + } + } else { + tag = *in++; + +#define HANDLE_BYTE(n) \ + { \ + bool isNonzero = (tag & (1u << n)) != 0; \ + *out++ = *in & (-(int8_t)isNonzero); \ + in += isNonzero; \ + } + + HANDLE_BYTE(0); + HANDLE_BYTE(1); + HANDLE_BYTE(2); + HANDLE_BYTE(3); + HANDLE_BYTE(4); + HANDLE_BYTE(5); + HANDLE_BYTE(6); + HANDLE_BYTE(7); +#undef HANDLE_BYTE + } + + if (tag == 0) { + KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here."); + + uint runLength = *in++ * sizeof(word); + + KJ_REQUIRE(runLength <= outEnd - out, + "Packed input did not end cleanly on a segment boundary.") { + return out - reinterpret_cast(dst); + } + memset(out, 0, runLength); + out += runLength; + + } else if (tag == 0xffu) { + KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here."); + + uint runLength = *in++ * sizeof(word); + + KJ_REQUIRE(runLength <= outEnd - out, + "Packed input did not end cleanly on a segment boundary.") { + return out - reinterpret_cast(dst); + } + + uint inRemaining = BUFFER_REMAINING; + if (inRemaining >= runLength) { + // Fast path. + memcpy(out, in, runLength); + out += runLength; + in += runLength; + } else { + // Copy over the first buffer, then do one big read for the rest. + memcpy(out, in, inRemaining); + out += inRemaining; + runLength -= inRemaining; + + inner.skip(buffer.size()); + inner.read(out, runLength); + out += runLength; + + if (out == outEnd) { + return maxBytes; + } else { + buffer = inner.getReadBuffer(); + in = reinterpret_cast(buffer.begin()); + + // Skip the bounds check below since we just did the same check above. + continue; + } + } + } + + if (out == outEnd) { + inner.skip(in - reinterpret_cast(buffer.begin())); + return maxBytes; + } + } + + KJ_FAIL_ASSERT("Can't get here."); + return 0; // GCC knows KJ_FAIL_ASSERT doesn't return, but Eclipse CDT still warns... + +#undef REFRESH_BUFFER +} + +void PackedInputStream::skip(size_t bytes) { + // We can't just read into buffers because buffers must end on block boundaries. + + if (bytes == 0) { + return; + } + + KJ_DREQUIRE(bytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned."); + + kj::ArrayPtr buffer = inner.getReadBuffer(); + const uint8_t* __restrict__ in = reinterpret_cast(buffer.begin()); + +#define REFRESH_BUFFER() \ + inner.skip(buffer.size()); \ + buffer = inner.getReadBuffer(); \ + KJ_REQUIRE(buffer.size() > 0, "Premature end of packed input.") { return; } \ + in = reinterpret_cast(buffer.begin()) + + for (;;) { + uint8_t tag; + + if (BUFFER_REMAINING < 10) { + if (BUFFER_REMAINING == 0) { + REFRESH_BUFFER(); + continue; + } + + // We have at least 1, but not 10, bytes available. We need to read slowly, doing a bounds + // check on each byte. + + tag = *in++; + + for (uint i = 0; i < 8; i++) { + if (tag & (1u << i)) { + if (BUFFER_REMAINING == 0) { + REFRESH_BUFFER(); + } + in++; + } + } + bytes -= 8; + + if (BUFFER_REMAINING == 0 && (tag == 0 || tag == 0xffu)) { + REFRESH_BUFFER(); + } + } else { + tag = *in++; + +#define HANDLE_BYTE(n) \ + in += (tag & (1u << n)) != 0 + + HANDLE_BYTE(0); + HANDLE_BYTE(1); + HANDLE_BYTE(2); + HANDLE_BYTE(3); + HANDLE_BYTE(4); + HANDLE_BYTE(5); + HANDLE_BYTE(6); + HANDLE_BYTE(7); +#undef HANDLE_BYTE + + bytes -= 8; + } + + if (tag == 0) { + KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here."); + + uint runLength = *in++ * sizeof(word); + + KJ_REQUIRE(runLength <= bytes, "Packed input did not end cleanly on a segment boundary.") { + return; + } + + bytes -= runLength; + + } else if (tag == 0xffu) { + KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here."); + + uint runLength = *in++ * sizeof(word); + + KJ_REQUIRE(runLength <= bytes, "Packed input did not end cleanly on a segment boundary.") { + return; + } + + bytes -= runLength; + + uint inRemaining = BUFFER_REMAINING; + if (inRemaining > runLength) { + // Fast path. + in += runLength; + } else { + // Forward skip to the underlying stream. + runLength -= inRemaining; + inner.skip(buffer.size() + runLength); + + if (bytes == 0) { + return; + } else { + buffer = inner.getReadBuffer(); + in = reinterpret_cast(buffer.begin()); + + // Skip the bounds check below since we just did the same check above. + continue; + } + } + } + + if (bytes == 0) { + inner.skip(in - reinterpret_cast(buffer.begin())); + return; + } + } + + KJ_FAIL_ASSERT("Can't get here."); +} + +// ------------------------------------------------------------------- + +PackedOutputStream::PackedOutputStream(kj::BufferedOutputStream& inner) + : inner(inner) {} +PackedOutputStream::~PackedOutputStream() noexcept(false) {} + +void PackedOutputStream::write(const void* src, size_t size) { + kj::ArrayPtr buffer = inner.getWriteBuffer(); + byte slowBuffer[20]; + + uint8_t* __restrict__ out = reinterpret_cast(buffer.begin()); + + const uint8_t* __restrict__ in = reinterpret_cast(src); + const uint8_t* const inEnd = reinterpret_cast(src) + size; + + while (in < inEnd) { + if (reinterpret_cast(buffer.end()) - out < 10) { + // Oops, we're out of space. We need at least 10 bytes for the fast path, since we don't + // bounds-check on every byte. + + // Write what we have so far. + inner.write(buffer.begin(), out - reinterpret_cast(buffer.begin())); + + // Use a slow buffer into which we'll encode 10 to 20 bytes. This should get us past the + // output stream's buffer boundary. + buffer = kj::arrayPtr(slowBuffer, sizeof(slowBuffer)); + out = reinterpret_cast(buffer.begin()); + } + + uint8_t* tagPos = out++; + +#define HANDLE_BYTE(n) \ + uint8_t bit##n = *in != 0; \ + *out = *in; \ + out += bit##n; /* out only advances if the byte was non-zero */ \ + ++in + + HANDLE_BYTE(0); + HANDLE_BYTE(1); + HANDLE_BYTE(2); + HANDLE_BYTE(3); + HANDLE_BYTE(4); + HANDLE_BYTE(5); + HANDLE_BYTE(6); + HANDLE_BYTE(7); +#undef HANDLE_BYTE + + uint8_t tag = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) + | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7); + *tagPos = tag; + + if (tag == 0) { + // An all-zero word is followed by a count of consecutive zero words (not including the + // first one). + + // We can check a whole word at a time. + const uint64_t* inWord = reinterpret_cast(in); + + // The count must fit it 1 byte, so limit to 255 words. + const uint64_t* limit = reinterpret_cast(inEnd); + if (limit - inWord > 255) { + limit = inWord + 255; + } + + while (inWord < limit && *inWord == 0) { + ++inWord; + } + + // Write the count. + *out++ = inWord - reinterpret_cast(in); + + // Advance input. + in = reinterpret_cast(inWord); + + } else if (tag == 0xffu) { + // An all-nonzero word is followed by a count of consecutive uncompressed words, followed + // by the uncompressed words themselves. + + // Count the number of consecutive words in the input which have no more than a single + // zero-byte. We look for at least two zeros because that's the point where our compression + // scheme becomes a net win. + // TODO(perf): Maybe look for three zeros? Compressing a two-zero word is a loss if the + // following word has no zeros. + const uint8_t* runStart = in; + + const uint8_t* limit = inEnd; + if ((size_t)(limit - in) > 255 * sizeof(word)) { + limit = in + 255 * sizeof(word); + } + + while (in < limit) { + // Check eight input bytes for zeros. + uint c = *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + c += *in++ == 0; + + if (c >= 2) { + // Un-read the word with multiple zeros, since we'll want to compress that one. + in -= 8; + break; + } + } + + // Write the count. + uint count = in - runStart; + *out++ = count / sizeof(word); + + if (count <= reinterpret_cast(buffer.end()) - out) { + // There's enough space to memcpy. + memcpy(out, runStart, count); + out += count; + } else { + // Input overruns the output buffer. We'll give it to the output stream in one chunk + // and let it decide what to do. + inner.write(buffer.begin(), reinterpret_cast(out) - buffer.begin()); + inner.write(runStart, in - runStart); + buffer = inner.getWriteBuffer(); + out = reinterpret_cast(buffer.begin()); + } + } + } + + // Write whatever is left. + inner.write(buffer.begin(), reinterpret_cast(out) - buffer.begin()); +} + +} // namespace _ (private) + +// ======================================================================================= + +PackedMessageReader::PackedMessageReader( + kj::BufferedInputStream& inputStream, ReaderOptions options, kj::ArrayPtr scratchSpace) + : PackedInputStream(inputStream), + InputStreamMessageReader(static_cast(*this), options, scratchSpace) {} + +PackedMessageReader::~PackedMessageReader() noexcept(false) {} + +PackedFdMessageReader::PackedFdMessageReader( + int fd, ReaderOptions options, kj::ArrayPtr scratchSpace) + : FdInputStream(fd), + BufferedInputStreamWrapper(static_cast(*this)), + PackedMessageReader(static_cast(*this), + options, scratchSpace) {} + +PackedFdMessageReader::PackedFdMessageReader( + kj::AutoCloseFd fd, ReaderOptions options, kj::ArrayPtr scratchSpace) + : FdInputStream(kj::mv(fd)), + BufferedInputStreamWrapper(static_cast(*this)), + PackedMessageReader(static_cast(*this), + options, scratchSpace) {} + +PackedFdMessageReader::~PackedFdMessageReader() noexcept(false) {} + +void writePackedMessage(kj::BufferedOutputStream& output, + kj::ArrayPtr> segments) { + _::PackedOutputStream packedOutput(output); + writeMessage(packedOutput, segments); +} + +void writePackedMessage(kj::OutputStream& output, + kj::ArrayPtr> segments) { + KJ_IF_MAYBE(bufferedOutputPtr, kj::dynamicDowncastIfAvailable(output)) { + writePackedMessage(*bufferedOutputPtr, segments); + } else { + byte buffer[8192]; + kj::BufferedOutputStreamWrapper bufferedOutput(output, kj::arrayPtr(buffer, sizeof(buffer))); + writePackedMessage(bufferedOutput, segments); + } +} + +void writePackedMessageToFd(int fd, kj::ArrayPtr> segments) { + kj::FdOutputStream output(fd); + writePackedMessage(output, segments); +} + +size_t computeUnpackedSizeInWords(kj::ArrayPtr packedBytes) { + const byte* ptr = packedBytes.begin(); + const byte* end = packedBytes.end(); + + size_t total = 0; + while (ptr < end) { + uint tag = *ptr; + size_t count = kj::popCount(tag); + total += 1; + KJ_REQUIRE(end - ptr >= count, "invalid packed data"); + ptr += count + 1; + + if (tag == 0) { + KJ_REQUIRE(ptr < end, "invalid packed data"); + total += *ptr++; + } else if (tag == 0xff) { + KJ_REQUIRE(ptr < end, "invalid packed data"); + size_t words = *ptr++; + total += words; + size_t bytes = words * sizeof(word); + KJ_REQUIRE(end - ptr >= bytes, "invalid packed data"); + ptr += bytes; + } + } + + return total; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-packed.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-packed.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,130 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_PACKED_H_ +#define CAPNP_SERIALIZE_PACKED_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "serialize.h" + +namespace capnp { + +namespace _ { // private + +class PackedInputStream: public kj::InputStream { + // An input stream that unpacks packed data with a picky constraint: The caller must read data + // in the exact same size and sequence as the data was written to PackedOutputStream. + +public: + explicit PackedInputStream(kj::BufferedInputStream& inner); + KJ_DISALLOW_COPY(PackedInputStream); + ~PackedInputStream() noexcept(false); + + // implements InputStream ------------------------------------------ + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + kj::BufferedInputStream& inner; +}; + +class PackedOutputStream: public kj::OutputStream { +public: + explicit PackedOutputStream(kj::BufferedOutputStream& inner); + KJ_DISALLOW_COPY(PackedOutputStream); + ~PackedOutputStream() noexcept(false); + + // implements OutputStream ----------------------------------------- + void write(const void* buffer, size_t bytes) override; + +private: + kj::BufferedOutputStream& inner; +}; + +} // namespace _ (private) + +class PackedMessageReader: private _::PackedInputStream, public InputStreamMessageReader { +public: + PackedMessageReader(kj::BufferedInputStream& inputStream, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + KJ_DISALLOW_COPY(PackedMessageReader); + ~PackedMessageReader() noexcept(false); +}; + +class PackedFdMessageReader: private kj::FdInputStream, private kj::BufferedInputStreamWrapper, + public PackedMessageReader { +public: + PackedFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + // Read message from a file descriptor, without taking ownership of the descriptor. + // Note that if you want to reuse the descriptor after the reader is destroyed, you'll need to + // seek it, since otherwise the position is unspecified. + + PackedFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + // Read a message from a file descriptor, taking ownership of the descriptor. + + KJ_DISALLOW_COPY(PackedFdMessageReader); + + ~PackedFdMessageReader() noexcept(false); +}; + +void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder); +void writePackedMessage(kj::BufferedOutputStream& output, + kj::ArrayPtr> segments); +// Write a packed message to a buffered output stream. + +void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder); +void writePackedMessage(kj::OutputStream& output, + kj::ArrayPtr> segments); +// Write a packed message to an unbuffered output stream. If you intend to write multiple messages +// in succession, consider wrapping your output in a buffered stream in order to reduce system +// call overhead. + +void writePackedMessageToFd(int fd, MessageBuilder& builder); +void writePackedMessageToFd(int fd, kj::ArrayPtr> segments); +// Write a single packed message to the file descriptor. + +size_t computeUnpackedSizeInWords(kj::ArrayPtr packedBytes); +// Computes the number of words to which the given packed bytes will unpack. Not intended for use +// in performance-sensitive situations. + +// ======================================================================================= +// inline stuff + +inline void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder.getSegmentsForOutput()); +} + +inline void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder) { + writePackedMessage(output, builder.getSegmentsForOutput()); +} + +inline void writePackedMessageToFd(int fd, MessageBuilder& builder) { + writePackedMessageToFd(fd, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_PACKED_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,482 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize.h" +#include +#include +#include +#include +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +class TestMessageBuilder: public MallocMessageBuilder { + // A MessageBuilder that tries to allocate an exact number of total segments, by allocating + // minimum-size segments until it reaches the number, then allocating one large segment to + // finish. + +public: + explicit TestMessageBuilder(uint desiredSegmentCount) + : MallocMessageBuilder(0, AllocationStrategy::FIXED_SIZE), + desiredSegmentCount(desiredSegmentCount) {} + ~TestMessageBuilder() { + EXPECT_EQ(0u, desiredSegmentCount); + } + + kj::ArrayPtr allocateSegment(uint minimumSize) override { + if (desiredSegmentCount <= 1) { + if (desiredSegmentCount < 1) { + ADD_FAILURE() << "Allocated more segments than desired."; + } else { + --desiredSegmentCount; + } + return MallocMessageBuilder::allocateSegment(SUGGESTED_FIRST_SEGMENT_WORDS); + } else { + --desiredSegmentCount; + return MallocMessageBuilder::allocateSegment(minimumSize); + } + } + +private: + uint desiredSegmentCount; +}; + +kj::Array copyWords(kj::ArrayPtr input) { + auto result = kj::heapArray(input.size()); + memcpy(result.asBytes().begin(), input.asBytes().begin(), input.asBytes().size()); + return result; +} + +TEST(Serialize, FlatArray) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + { + FlatArrayMessageReader reader(serialized.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serialized.end(), reader.getEnd()); + } + + { + MallocMessageBuilder builder2; + auto remaining = initMessageBuilderFromFlatArrayCopy(serialized, builder2); + checkTestMessage(builder2.getRoot()); + EXPECT_EQ(serialized.end(), remaining.begin()); + EXPECT_EQ(serialized.end(), remaining.end()); + } + + kj::Array serializedWithSuffix = kj::heapArray(serialized.size() + 5); + memcpy(serializedWithSuffix.begin(), serialized.begin(), serialized.size() * sizeof(word)); + + { + FlatArrayMessageReader reader(serializedWithSuffix.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serializedWithSuffix.end() - 5, reader.getEnd()); + } + + { + MallocMessageBuilder builder2; + auto remaining = initMessageBuilderFromFlatArrayCopy(serializedWithSuffix, builder2); + checkTestMessage(builder2.getRoot()); + EXPECT_EQ(serializedWithSuffix.end() - 5, remaining.begin()); + EXPECT_EQ(serializedWithSuffix.end(), remaining.end()); + } + + { + // Test expectedSizeInWordsFromPrefix(). We pass in a copy of the slice so that valgrind can + // detect out-of-bounds access. + EXPECT_EQ(1, expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, 0)))); + for (uint i = 1; i <= serialized.size(); i++) { + EXPECT_EQ(serialized.size(), + expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, i)))); + } + } +} + +TEST(Serialize, FlatArrayOddSegmentCount) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + { + FlatArrayMessageReader reader(serialized.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serialized.end(), reader.getEnd()); + } + + kj::Array serializedWithSuffix = kj::heapArray(serialized.size() + 5); + memcpy(serializedWithSuffix.begin(), serialized.begin(), serialized.size() * sizeof(word)); + + { + FlatArrayMessageReader reader(serializedWithSuffix.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serializedWithSuffix.end() - 5, reader.getEnd()); + } + + { + // Test expectedSizeInWordsFromPrefix(). We pass in a copy of the slice so that valgrind can + // detect out-of-bounds access. + + // Segment table is 4 words, so with fewer words we'll have incomplete information. + for (uint i = 0; i < 4; i++) { + size_t expectedSize = expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, i))); + EXPECT_LT(expectedSize, serialized.size()); + EXPECT_GT(expectedSize, i); + } + // After that, we get the exact length. + for (uint i = 4; i <= serialized.size(); i++) { + EXPECT_EQ(serialized.size(), + expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, i)))); + } + } +} + +TEST(Serialize, FlatArrayEvenSegmentCount) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + { + FlatArrayMessageReader reader(serialized.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serialized.end(), reader.getEnd()); + } + + kj::Array serializedWithSuffix = kj::heapArray(serialized.size() + 5); + memcpy(serializedWithSuffix.begin(), serialized.begin(), serialized.size() * sizeof(word)); + + { + FlatArrayMessageReader reader(serializedWithSuffix.asPtr()); + checkTestMessage(reader.getRoot()); + EXPECT_EQ(serializedWithSuffix.end() - 5, reader.getEnd()); + } + + { + // Test expectedSizeInWordsFromPrefix(). We pass in a copy of the slice so that valgrind can + // detect out-of-bounds access. + + // Segment table is 6 words, so with fewer words we'll have incomplete information. + for (uint i = 0; i < 6; i++) { + size_t expectedSize = expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, i))); + EXPECT_LT(expectedSize, serialized.size()); + EXPECT_GT(expectedSize, i); + } + // After that, we get the exact length. + for (uint i = 6; i <= serialized.size(); i++) { + EXPECT_EQ(serialized.size(), + expectedSizeInWordsFromPrefix(copyWords(serialized.slice(0, i)))); + } + } +} + +class TestInputStream: public kj::InputStream { +public: + TestInputStream(kj::ArrayPtr data, bool lazy) + : pos(data.asChars().begin()), + end(data.asChars().end()), + lazy(lazy) {} + ~TestInputStream() {} + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + KJ_ASSERT(maxBytes <= size_t(end - pos), "Overran end of stream."); + size_t amount = lazy ? minBytes : maxBytes; + memcpy(buffer, pos, amount); + pos += amount; + return amount; + } + +private: + const char* pos; + const char* end; + bool lazy; +}; + +TEST(Serialize, InputStream) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), false); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamScratchSpace) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + word scratch[4096]; + TestInputStream stream(serialized.asPtr(), false); + InputStreamMessageReader reader(stream, ReaderOptions(), kj::ArrayPtr(scratch, 4096)); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamLazy) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), true); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamOddSegmentCount) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), false); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamOddSegmentCountLazy) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), true); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamEvenSegmentCount) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), false); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamEvenSegmentCountLazy) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), true); + InputStreamMessageReader reader(stream, ReaderOptions()); + + checkTestMessage(reader.getRoot()); +} + +TEST(Serialize, InputStreamToBuilder) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestInputStream stream(serialized.asPtr(), false); + + MallocMessageBuilder builder2; + readMessageCopy(stream, builder2); + + checkTestMessage(builder2.getRoot()); +} + +class TestOutputStream: public kj::OutputStream { +public: + TestOutputStream() {} + ~TestOutputStream() {} + + void write(const void* buffer, size_t size) override { + data.append(reinterpret_cast(buffer), size); + } + + bool dataEquals(kj::ArrayPtr other) { + return data == + std::string(other.asChars().begin(), other.asChars().size()); + } + +private: + std::string data; +}; + +TEST(Serialize, WriteMessage) { + TestMessageBuilder builder(1); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestOutputStream output; + writeMessage(output, builder); + + EXPECT_TRUE(output.dataEquals(serialized.asPtr())); +} + +TEST(Serialize, WriteMessageOddSegmentCount) { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestOutputStream output; + writeMessage(output, builder); + + EXPECT_TRUE(output.dataEquals(serialized.asPtr())); +} + +TEST(Serialize, WriteMessageEvenSegmentCount) { + TestMessageBuilder builder(10); + initTestMessage(builder.initRoot()); + + kj::Array serialized = messageToFlatArray(builder); + + TestOutputStream output; + writeMessage(output, builder); + + EXPECT_TRUE(output.dataEquals(serialized.asPtr())); +} + +#if _WIN32 +int mkstemp(char *tpl) { + char* end = tpl + strlen(tpl); + while (end > tpl && *(end-1) == 'X') --end; + + for (;;) { + KJ_ASSERT(_mktemp(tpl) == tpl); + + int fd = open(tpl, O_RDWR | O_CREAT | O_EXCL | O_TEMPORARY | O_BINARY, 0700); + if (fd >= 0) { + return fd; + } + + int error = errno; + if (error != EEXIST && error != EINTR) { + KJ_FAIL_SYSCALL("open(mktemp())", error, tpl); + } + + memset(end, 'X', strlen(end)); + } +} +#endif + +TEST(Serialize, FileDescriptors) { +#if _WIN32 || __ANDROID__ + // TODO(cleanup): Find the Windows temp directory? Seems overly difficult. + char filename[] = "capnproto-serialize-test-XXXXXX"; +#else + char filename[] = "/tmp/capnproto-serialize-test-XXXXXX"; +#endif + kj::AutoCloseFd tmpfile(mkstemp(filename)); + ASSERT_GE(tmpfile.get(), 0); + +#if !_WIN32 + // Unlink the file so that it will be deleted on close. + // (For win32, we already handled this is mkstemp().) + EXPECT_EQ(0, unlink(filename)); +#endif + + { + TestMessageBuilder builder(7); + initTestMessage(builder.initRoot()); + writeMessageToFd(tmpfile.get(), builder); + } + + { + TestMessageBuilder builder(1); + builder.initRoot().setTextField("second message in file"); + writeMessageToFd(tmpfile.get(), builder); + } + + lseek(tmpfile, 0, SEEK_SET); + + { + StreamFdMessageReader reader(tmpfile.get()); + checkTestMessage(reader.getRoot()); + } + + { + StreamFdMessageReader reader(tmpfile.get()); + EXPECT_EQ("second message in file", reader.getRoot().getTextField()); + } +} + +TEST(Serialize, RejectTooManySegments) { + kj::Array data = kj::heapArray(8192); + WireValue* table = reinterpret_cast*>(data.begin()); + table[0].set(1024); + for (uint i = 0; i < 1024; i++) { + table[i+1].set(1); + } + TestInputStream input(data.asPtr(), false); + + kj::Maybe e = kj::runCatchingExceptions([&]() { + InputStreamMessageReader reader(input); +#if !KJ_NO_EXCEPTIONS + ADD_FAILURE() << "Should have thrown an exception."; +#endif + }); + + KJ_EXPECT(e != nullptr, "Should have thrown an exception."); +} + +#if !__MINGW32__ // Inexplicably crashes when exception is thrown from constructor. +TEST(Serialize, RejectHugeMessage) { + // A message whose root struct contains two words of data! + AlignedData<4> data = {{0,0,0,0,3,0,0,0, 0,0,0,0,2,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}}; + + TestInputStream input(kj::arrayPtr(data.words, 4), false); + + // We'll set the traversal limit to 2 words so our 3-word message is too big. + ReaderOptions options; + options.traversalLimitInWords = 2; + + kj::Maybe e = kj::runCatchingExceptions([&]() { + InputStreamMessageReader reader(input, options); +#if !KJ_NO_EXCEPTIONS + ADD_FAILURE() << "Should have thrown an exception."; +#endif + }); + + KJ_EXPECT(e != nullptr, "Should have thrown an exception."); +} +#endif // !__MINGW32__ + +// TODO(test): Test error cases. + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-text-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-text-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,131 @@ +// Copyright (c) 2015 Philip Quinn. +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-text.h" +#include +#include +#include +#include +#include "test-util.h" + +#include + +namespace capnp { +namespace _ { // private +namespace { + +KJ_TEST("TestAllTypes") { + MallocMessageBuilder builder; + initTestMessage(builder.initRoot()); + + { + // Plain output + TextCodec codec; + codec.setPrettyPrint(false); + auto text = codec.encode(builder.getRoot()); + + auto stringify = kj::str(builder.getRoot()); + KJ_EXPECT(text == stringify); + + MallocMessageBuilder reader; + auto orphan = codec.decode(text, reader.getOrphanage()); + auto structReader = orphan.getReader(); + checkTestMessage(structReader); + } + { + // Pretty output + TextCodec codec; + codec.setPrettyPrint(true); + auto text = codec.encode(builder.getRoot()); + + auto stringify = prettyPrint(builder.getRoot()).flatten(); + KJ_EXPECT(text == stringify); + + MallocMessageBuilder reader; + auto orphan = codec.decode(text, reader.getOrphanage()); + auto structReader = orphan.getReader(); + checkTestMessage(structReader); + } +} + +KJ_TEST("TestDefaults") { + MallocMessageBuilder builder; + initTestMessage(builder.initRoot()); + + TextCodec codec; + auto text = codec.encode(builder.getRoot()); + + MallocMessageBuilder reader; + auto orphan = codec.decode(text, reader.getOrphanage()); + auto structReader = orphan.getReader(); + checkTestMessage(structReader); +} + +KJ_TEST("TestListDefaults") { + MallocMessageBuilder builder; + initTestMessage(builder.initRoot()); + + TextCodec codec; + auto text = codec.encode(builder.getRoot()); + + MallocMessageBuilder reader; + auto orphan = codec.decode(text, reader.getOrphanage()); + auto structReader = orphan.getReader(); + checkTestMessage(structReader); +} + +KJ_TEST("raw text") { + using TestType = capnproto_test::capnp::test::TestLateUnion; + + kj::String message = + kj::str(R"(( + foo = -123, bar = "bar", baz = 456, + # Test Comment + theUnion = ( qux = "qux" ), + anotherUnion = ( corge = [ 7, 8, 9 ] ), + ))"); + + MallocMessageBuilder builder; + auto testType = builder.initRoot(); + + TextCodec codec; + codec.decode(message, testType); + + auto reader = testType.asReader(); + KJ_EXPECT(reader.getFoo() == -123); + KJ_EXPECT(reader.getBar() == "bar"); + KJ_EXPECT(reader.getBaz() == 456); + + KJ_EXPECT(reader.getTheUnion().isQux()); + KJ_EXPECT(reader.getTheUnion().hasQux()); + KJ_EXPECT(reader.getTheUnion().getQux() == "qux"); + + KJ_EXPECT(reader.getAnotherUnion().isCorge()); + KJ_EXPECT(reader.getAnotherUnion().hasCorge()); + KJ_EXPECT(reader.getAnotherUnion().getCorge().size() == 3); + KJ_EXPECT(reader.getAnotherUnion().getCorge()[0] == 7); + KJ_EXPECT(reader.getAnotherUnion().getCorge()[1] == 8); + KJ_EXPECT(reader.getAnotherUnion().getCorge()[2] == 9); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-text.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-text.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,145 @@ +// Copyright (c) 2015 Philip Quinn. +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize-text.h" + +#include + +#include "pretty-print.h" +#include "compiler/lexer.capnp.h" +#include "compiler/lexer.h" +#include "compiler/node-translator.h" +#include "compiler/parser.h" + +namespace { + +class ThrowingErrorReporter final: public capnp::compiler::ErrorReporter { + // Throws all errors as assertion failures. +public: + void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override { + KJ_FAIL_REQUIRE(kj::str(message, " (", startByte, ":", endByte, ").")); + } + + bool hadErrors() override { return false; } +}; + +class ExternalResolver final: public capnp::compiler::ValueTranslator::Resolver { + // Throws all external resolution requests as assertion failures. +public: + kj::Maybe + resolveConstant(capnp::compiler::Expression::Reader name) override { + KJ_FAIL_REQUIRE("External constants not allowed."); + } + + kj::Maybe> + readEmbed(capnp::compiler::LocatedText::Reader filename) override { + KJ_FAIL_REQUIRE("External embeds not allowed."); + } +}; + +template +void lexAndParseExpression(kj::StringPtr input, Function f) { + // Parses a single expression from the input and calls `f(expression)`. + + ThrowingErrorReporter errorReporter; + + capnp::MallocMessageBuilder tokenArena; + auto lexedTokens = tokenArena.initRoot(); + capnp::compiler::lex(input, lexedTokens, errorReporter); + + capnp::compiler::CapnpParser parser(tokenArena.getOrphanage(), errorReporter); + auto tokens = lexedTokens.asReader().getTokens(); + capnp::compiler::CapnpParser::ParserInput parserInput(tokens.begin(), tokens.end()); + + if (parserInput.getPosition() != tokens.end()) { + KJ_IF_MAYBE(expression, parser.getParsers().expression(parserInput)) { + // The input is expected to contain a *single* message. + KJ_REQUIRE(parserInput.getPosition() == tokens.end(), "Extra tokens in input."); + + f(expression->getReader()); + } else { + auto best = parserInput.getBest(); + if (best == tokens.end()) { + KJ_FAIL_REQUIRE("Premature end of input."); + } else { + errorReporter.addErrorOn(*best, "Parse error"); + } + } + } else { + KJ_FAIL_REQUIRE("Failed to read input."); + } +} + +} // namespace + +namespace capnp { + +TextCodec::TextCodec() : prettyPrint(false) {} +TextCodec::~TextCodec() noexcept(true) {} + +void TextCodec::setPrettyPrint(bool enabled) { prettyPrint = enabled; } + +kj::String TextCodec::encode(DynamicValue::Reader value) const { + if (!prettyPrint) { + return kj::str(value); + } else { + if (value.getType() == DynamicValue::Type::STRUCT) { + return capnp::prettyPrint(value.as()).flatten(); + } else if (value.getType() == DynamicValue::Type::LIST) { + return capnp::prettyPrint(value.as()).flatten(); + } else { + return kj::str(value); + } + } +} + +void TextCodec::decode(kj::StringPtr input, DynamicStruct::Builder output) const { + lexAndParseExpression(input, [&output](compiler::Expression::Reader expression) { + KJ_REQUIRE(expression.isTuple(), "Input does not contain a struct."); + + ThrowingErrorReporter errorReporter; + ExternalResolver nullResolver; + + Orphanage orphanage = Orphanage::getForMessageContaining(output); + compiler::ValueTranslator translator(nullResolver, errorReporter, orphanage); + translator.fillStructValue(output, expression.getTuple()); + }); +} + +Orphan TextCodec::decode(kj::StringPtr input, Type type, Orphanage orphanage) const { + Orphan output; + + lexAndParseExpression(input, [&type, &orphanage, &output](compiler::Expression::Reader expression) { + ThrowingErrorReporter errorReporter; + ExternalResolver nullResolver; + + compiler::ValueTranslator translator(nullResolver, errorReporter, orphanage); + KJ_IF_MAYBE(value, translator.compileValue(expression, type)) { + output = *kj::mv(value); + } else { + // An error should have already been given to the errorReporter. + } + }); + + return output; +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize-text.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize-text.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,96 @@ +// Copyright (c) 2015 Philip Quinn. +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_SERIALIZE_TEXT_H_ +#define CAPNP_SERIALIZE_TEXT_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include "dynamic.h" +#include "orphan.h" +#include "schema.h" + +namespace capnp { + +class TextCodec { + // Reads and writes Cap'n Proto objects in a plain text format (as used in the schema + // language for constants, and read/written by the 'decode' and 'encode' commands of + // the capnp tool). + // + // This format is useful for debugging or human input, but it is not a robust alternative + // to the binary format. Changes to a schema's types or names that are permitted in a + // schema's binary evolution will likely break messages stored in this format. + // + // Note that definitions or references (to constants, other fields, or files) are not + // permitted in this format. To evaluate declarations with the full expressiveness of the + // schema language, see `capnp::SchemaParser`. + // + // Requires linking with the capnpc library. + +public: + TextCodec(); + ~TextCodec() noexcept(true); + + void setPrettyPrint(bool enabled); + // If enabled, pads the output of `encode()` with spaces and newlines to make it more + // human-readable. + + template + kj::String encode(T&& value) const; + kj::String encode(DynamicValue::Reader value) const; + // Encode any Cap'n Proto value. + + template + Orphan decode(kj::StringPtr input, Orphanage orphanage) const; + // Decode a text message into a Cap'n Proto object of type T, allocated in the given + // orphanage. Any errors parsing the input or assigning the fields of T are thrown as + // exceptions. + + void decode(kj::StringPtr input, DynamicStruct::Builder output) const; + // Decode a text message for a struct into the given builder. Any errors parsing the + // input or assigning the fields of the output are thrown as exceptions. + + // TODO(someday): expose some control over the error handling? +private: + Orphan decode(kj::StringPtr input, Type type, Orphanage orphanage) const; + + bool prettyPrint; +}; + +// ======================================================================================= +// inline stuff + +template +inline kj::String TextCodec::encode(T&& value) const { + return encode(DynamicValue::Reader(ReaderFor>(kj::fwd(value)))); +} + +template +inline Orphan TextCodec::decode(kj::StringPtr input, Orphanage orphanage) const { + return decode(input, Type::from(), orphanage).template releaseAs(); +} + +} // namespace capnp + +#endif // CAPNP_SERIALIZE_TEXT_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,314 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "serialize.h" +#include "layout.h" +#include +#include + +namespace capnp { + +FlatArrayMessageReader::FlatArrayMessageReader( + kj::ArrayPtr array, ReaderOptions options) + : MessageReader(options), end(array.end()) { + if (array.size() < 1) { + // Assume empty message. + return; + } + + const _::WireValue* table = + reinterpret_cast*>(array.begin()); + + uint segmentCount = table[0].get() + 1; + size_t offset = segmentCount / 2u + 1u; + + KJ_REQUIRE(array.size() >= offset, "Message ends prematurely in segment table.") { + return; + } + + { + uint segmentSize = table[1].get(); + + KJ_REQUIRE(array.size() >= offset + segmentSize, + "Message ends prematurely in first segment.") { + return; + } + + segment0 = array.slice(offset, offset + segmentSize); + offset += segmentSize; + } + + if (segmentCount > 1) { + moreSegments = kj::heapArray>(segmentCount - 1); + + for (uint i = 1; i < segmentCount; i++) { + uint segmentSize = table[i + 1].get(); + + KJ_REQUIRE(array.size() >= offset + segmentSize, "Message ends prematurely.") { + moreSegments = nullptr; + return; + } + + moreSegments[i - 1] = array.slice(offset, offset + segmentSize); + offset += segmentSize; + } + } + + end = array.begin() + offset; +} + +size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr array) { + if (array.size() < 1) { + // All messages are at least one word. + return 1; + } + + const _::WireValue* table = + reinterpret_cast*>(array.begin()); + + uint segmentCount = table[0].get() + 1; + size_t offset = segmentCount / 2u + 1u; + + // If the array is too small to contain the full segment table, truncate segmentCount to just + // what is available. + segmentCount = kj::min(segmentCount, array.size() * 2 - 1u); + + size_t totalSize = offset; + for (uint i = 0; i < segmentCount; i++) { + totalSize += table[i + 1].get(); + } + return totalSize; +} + +kj::ArrayPtr FlatArrayMessageReader::getSegment(uint id) { + if (id == 0) { + return segment0; + } else if (id <= moreSegments.size()) { + return moreSegments[id - 1]; + } else { + return nullptr; + } +} + +kj::ArrayPtr initMessageBuilderFromFlatArrayCopy( + kj::ArrayPtr array, MessageBuilder& target, ReaderOptions options) { + FlatArrayMessageReader reader(array, options); + target.setRoot(reader.getRoot()); + return kj::arrayPtr(reader.getEnd(), array.end()); +} + +kj::Array messageToFlatArray(kj::ArrayPtr> segments) { + kj::Array result = kj::heapArray(computeSerializedSizeInWords(segments)); + + _::WireValue* table = + reinterpret_cast<_::WireValue*>(result.begin()); + + // We write the segment count - 1 because this makes the first word zero for single-segment + // messages, improving compression. We don't bother doing this with segment sizes because + // one-word segments are rare anyway. + table[0].set(segments.size() - 1); + + for (uint i = 0; i < segments.size(); i++) { + table[i + 1].set(segments[i].size()); + } + + if (segments.size() % 2 == 0) { + // Set padding byte. + table[segments.size() + 1].set(0); + } + + word* dst = result.begin() + segments.size() / 2 + 1; + + for (auto& segment: segments) { + memcpy(dst, segment.begin(), segment.size() * sizeof(word)); + dst += segment.size(); + } + + KJ_DASSERT(dst == result.end(), "Buffer overrun/underrun bug in code above."); + + return kj::mv(result); +} + +size_t computeSerializedSizeInWords(kj::ArrayPtr> segments) { + KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message."); + + size_t totalSize = segments.size() / 2 + 1; + + for (auto& segment: segments) { + totalSize += segment.size(); + } + + return totalSize; +} + +// ======================================================================================= + +InputStreamMessageReader::InputStreamMessageReader( + kj::InputStream& inputStream, ReaderOptions options, kj::ArrayPtr scratchSpace) + : MessageReader(options), inputStream(inputStream), readPos(nullptr) { + _::WireValue firstWord[2]; + + inputStream.read(firstWord, sizeof(firstWord)); + + uint segmentCount = firstWord[0].get() + 1; + uint segment0Size = segmentCount == 0 ? 0 : firstWord[1].get(); + + size_t totalWords = segment0Size; + + // Reject messages with too many segments for security reasons. + KJ_REQUIRE(segmentCount < 512, "Message has too many segments.") { + segmentCount = 1; + segment0Size = 1; + break; + } + + // Read sizes for all segments except the first. Include padding if necessary. + KJ_STACK_ARRAY(_::WireValue, moreSizes, segmentCount & ~1, 16, 64); + if (segmentCount > 1) { + inputStream.read(moreSizes.begin(), moreSizes.size() * sizeof(moreSizes[0])); + for (uint i = 0; i < segmentCount - 1; i++) { + totalWords += moreSizes[i].get(); + } + } + + // Don't accept a message which the receiver couldn't possibly traverse without hitting the + // traversal limit. Without this check, a malicious client could transmit a very large segment + // size to make the receiver allocate excessive space and possibly crash. + KJ_REQUIRE(totalWords <= options.traversalLimitInWords, + "Message is too large. To increase the limit on the receiving end, see " + "capnp::ReaderOptions.") { + segmentCount = 1; + segment0Size = kj::min(segment0Size, options.traversalLimitInWords); + totalWords = segment0Size; + break; + } + + if (scratchSpace.size() < totalWords) { + // TODO(perf): Consider allocating each segment as a separate chunk to reduce memory + // fragmentation. + ownedSpace = kj::heapArray(totalWords); + scratchSpace = ownedSpace; + } + + segment0 = scratchSpace.slice(0, segment0Size); + + if (segmentCount > 1) { + moreSegments = kj::heapArray>(segmentCount - 1); + size_t offset = segment0Size; + + for (uint i = 0; i < segmentCount - 1; i++) { + uint segmentSize = moreSizes[i].get(); + moreSegments[i] = scratchSpace.slice(offset, offset + segmentSize); + offset += segmentSize; + } + } + + if (segmentCount == 1) { + inputStream.read(scratchSpace.begin(), totalWords * sizeof(word)); + } else if (segmentCount > 1) { + readPos = scratchSpace.asBytes().begin(); + readPos += inputStream.read(readPos, segment0Size * sizeof(word), totalWords * sizeof(word)); + } +} + +InputStreamMessageReader::~InputStreamMessageReader() noexcept(false) { + if (readPos != nullptr) { + unwindDetector.catchExceptionsIfUnwinding([&]() { + // Note that lazy reads only happen when we have multiple segments, so moreSegments.back() is + // valid. + const byte* allEnd = reinterpret_cast(moreSegments.back().end()); + inputStream.skip(allEnd - readPos); + }); + } +} + +kj::ArrayPtr InputStreamMessageReader::getSegment(uint id) { + if (id > moreSegments.size()) { + return nullptr; + } + + kj::ArrayPtr segment = id == 0 ? segment0 : moreSegments[id - 1]; + + if (readPos != nullptr) { + // May need to lazily read more data. + const byte* segmentEnd = reinterpret_cast(segment.end()); + if (readPos < segmentEnd) { + // Note that lazy reads only happen when we have multiple segments, so moreSegments.back() is + // valid. + const byte* allEnd = reinterpret_cast(moreSegments.back().end()); + readPos += inputStream.read(readPos, segmentEnd - readPos, allEnd - readPos); + } + } + + return segment; +} + +void readMessageCopy(kj::InputStream& input, MessageBuilder& target, + ReaderOptions options, kj::ArrayPtr scratchSpace) { + InputStreamMessageReader message(input, options, scratchSpace); + target.setRoot(message.getRoot()); +} + +// ------------------------------------------------------------------- + +void writeMessage(kj::OutputStream& output, kj::ArrayPtr> segments) { + KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message."); + + KJ_STACK_ARRAY(_::WireValue, table, (segments.size() + 2) & ~size_t(1), 16, 64); + + // We write the segment count - 1 because this makes the first word zero for single-segment + // messages, improving compression. We don't bother doing this with segment sizes because + // one-word segments are rare anyway. + table[0].set(segments.size() - 1); + for (uint i = 0; i < segments.size(); i++) { + table[i + 1].set(segments[i].size()); + } + if (segments.size() % 2 == 0) { + // Set padding byte. + table[segments.size() + 1].set(0); + } + + KJ_STACK_ARRAY(kj::ArrayPtr, pieces, segments.size() + 1, 4, 32); + pieces[0] = table.asBytes(); + + for (uint i = 0; i < segments.size(); i++) { + pieces[i + 1] = segments[i].asBytes(); + } + + output.write(pieces); +} + +// ======================================================================================= + +StreamFdMessageReader::~StreamFdMessageReader() noexcept(false) {} + +void writeMessageToFd(int fd, kj::ArrayPtr> segments) { + kj::FdOutputStream stream(fd); + writeMessage(stream, segments); +} + +void readMessageCopyFromFd(int fd, MessageBuilder& target, + ReaderOptions options, kj::ArrayPtr scratchSpace) { + kj::FdInputStream stream(fd); + readMessageCopy(stream, target, options, scratchSpace); +} + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/serialize.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/serialize.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,237 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file implements a simple serialization format for Cap'n Proto messages. The format +// is as follows: +// +// * 32-bit little-endian segment count (4 bytes). +// * 32-bit little-endian size of each segment (4*(segment count) bytes). +// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even +// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.) +// * Data from each segment, in order (8*sum(segment sizes) bytes) +// +// This format has some important properties: +// - It is self-delimiting, so multiple messages may be written to a stream without any external +// delimiter. +// - The total size and position of each segment can be determined by reading only the first part +// of the message, allowing lazy and random-access reading of the segment data. +// - A message is always at least 8 bytes. +// - A single-segment message can be read entirely in two system calls with no buffering. +// - A multi-segment message can be read entirely in three system calls with no buffering. +// - The format is appropriate for mmap()ing since all data is aligned. + +#ifndef CAPNP_SERIALIZE_H_ +#define CAPNP_SERIALIZE_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "message.h" +#include + +namespace capnp { + +class FlatArrayMessageReader: public MessageReader { + // Parses a message from a flat array. Note that it makes sense to use this together with mmap() + // for extremely fast parsing. + +public: + FlatArrayMessageReader(kj::ArrayPtr array, ReaderOptions options = ReaderOptions()); + // The array must remain valid until the MessageReader is destroyed. + + kj::ArrayPtr getSegment(uint id) override; + + const word* getEnd() const { return end; } + // Get a pointer just past the end of the message as determined by reading the message header. + // This could actually be before the end of the input array. This pointer is useful e.g. if + // you know that the input array has extra stuff appended after the message and you want to + // get at it. + +private: + // Optimize for single-segment case. + kj::ArrayPtr segment0; + kj::Array> moreSegments; + const word* end; +}; + +kj::ArrayPtr initMessageBuilderFromFlatArrayCopy( + kj::ArrayPtr array, MessageBuilder& target, + ReaderOptions options = ReaderOptions()); +// Convenience function which reads a message using `FlatArrayMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// Returns an ArrayPtr containing any words left over in the array after consuming the whole +// message. This is useful when reading multiple messages that have been concatenated. See also +// FlatArrayMessageReader::getEnd(). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +kj::Array messageToFlatArray(MessageBuilder& builder); +// Constructs a flat array containing the entire content of the given message. +// +// To output the message as bytes, use `.asBytes()` on the returned word array. Keep in mind that +// `asBytes()` returns an ArrayPtr, so you have to save the Array as well to prevent it from being +// deleted. For example: +// +// kj::Array words = messageToFlatArray(myMessage); +// kj::ArrayPtr bytes = words.asBytes(); +// write(fd, bytes.begin(), bytes.size()); + +kj::Array messageToFlatArray(kj::ArrayPtr> segments); +// Version of messageToFlatArray that takes a raw segment array. + +size_t computeSerializedSizeInWords(MessageBuilder& builder); +// Returns the size, in words, that will be needed to serialize the message, including the header. + +size_t computeSerializedSizeInWords(kj::ArrayPtr> segments); +// Version of computeSerializedSizeInWords that takes a raw segment array. + +size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr messagePrefix); +// Given a prefix of a serialized message, try to determine the expected total size of the message, +// in words. The returned size is based on the information known so far; it may be an underestimate +// if the prefix doesn't contain the full segment table. +// +// If the returned value is greater than `messagePrefix.size()`, then the message is not yet +// complete and the app cannot parse it yet. If the returned value is less than or equal to +// `messagePrefix.size()`, then the returned value is the exact total size of the message; any +// remaining bytes are part of the next message. +// +// This function is useful when reading messages from a stream in an asynchronous way, but when +// using the full KJ async infrastructure would be too difficult. Each time bytes are received, +// use this function to determine if an entire message is ready to be parsed. + +// ======================================================================================= + +class InputStreamMessageReader: public MessageReader { + // A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader + // for a subclass specific to file descriptors. + +public: + InputStreamMessageReader(kj::InputStream& inputStream, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); + ~InputStreamMessageReader() noexcept(false); + + // implements MessageReader ---------------------------------------- + kj::ArrayPtr getSegment(uint id) override; + +private: + kj::InputStream& inputStream; + byte* readPos; + + // Optimize for single-segment case. + kj::ArrayPtr segment0; + kj::Array> moreSegments; + + kj::Array ownedSpace; + // Only if scratchSpace wasn't big enough. + + kj::UnwindDetector unwindDetector; +}; + +void readMessageCopy(kj::InputStream& input, MessageBuilder& target, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Convenience function which reads a message using `InputStreamMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +void writeMessage(kj::OutputStream& output, MessageBuilder& builder); +// Write the message to the given output stream. + +void writeMessage(kj::OutputStream& output, kj::ArrayPtr> segments); +// Write the segment array to the given output stream. + +// ======================================================================================= +// Specializations for reading from / writing to file descriptors. + +class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader { + // A MessageReader that reads from a steam-based file descriptor. + +public: + StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : FdInputStream(fd), InputStreamMessageReader(*this, options, scratchSpace) {} + // Read message from a file descriptor, without taking ownership of the descriptor. + + StreamFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr) + : FdInputStream(kj::mv(fd)), InputStreamMessageReader(*this, options, scratchSpace) {} + // Read a message from a file descriptor, taking ownership of the descriptor. + + ~StreamFdMessageReader() noexcept(false); +}; + +void readMessageCopyFromFd(int fd, MessageBuilder& target, + ReaderOptions options = ReaderOptions(), + kj::ArrayPtr scratchSpace = nullptr); +// Convenience function which reads a message using `StreamFdMessageReader` then copies the +// content into the target `MessageBuilder`, verifying that the message structure is valid +// (although not necessarily that it matches the desired schema). +// +// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one +// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not +// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.) + +void writeMessageToFd(int fd, MessageBuilder& builder); +// Write the message to the given file descriptor. +// +// This function throws an exception on any I/O error. If your code is not exception-safe, be sure +// you catch this exception at the call site. If throwing an exception is not acceptable, you +// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). + +void writeMessageToFd(int fd, kj::ArrayPtr> segments); +// Write the segment array to the given file descriptor. +// +// This function throws an exception on any I/O error. If your code is not exception-safe, be sure +// you catch this exception at the call site. If throwing an exception is not acceptable, you +// can implement your own OutputStream with arbitrary error handling and then use writeMessage(). + +// ======================================================================================= +// inline stuff + +inline kj::Array messageToFlatArray(MessageBuilder& builder) { + return messageToFlatArray(builder.getSegmentsForOutput()); +} + +inline size_t computeSerializedSizeInWords(MessageBuilder& builder) { + return computeSerializedSizeInWords(builder.getSegmentsForOutput()); +} + +inline void writeMessage(kj::OutputStream& output, MessageBuilder& builder) { + writeMessage(output, builder.getSegmentsForOutput()); +} + +inline void writeMessageToFd(int fd, MessageBuilder& builder) { + writeMessageToFd(fd, builder.getSegmentsForOutput()); +} + +} // namespace capnp + +#endif // SERIALIZE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/stringify-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/stringify-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,706 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "message.h" +#include "dynamic.h" +#include "pretty-print.h" +#include +#include +#include "test-util.h" + +namespace capnp { +namespace _ { // private +namespace { + +TEST(Stringify, KjStringification) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + // This test got ugly after printing was changed to always print primitives even when they have + // default values... + + EXPECT_EQ("(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "enumField = foo, " + "interfaceField = void)", + kj::str(root)); + + initTestMessage(root); + + EXPECT_EQ("(" + "voidField = void, " + "boolField = true, " + "int8Field = -123, " + "int16Field = -12345, " + "int32Field = -12345678, " + "int64Field = -123456789012345, " + "uInt8Field = 234, " + "uInt16Field = 45678, " + "uInt32Field = 3456789012, " + "uInt64Field = 12345678901234567890, " + "float32Field = 1234.5, " + "float64Field = -1.23e47, " + "textField = \"foo\", " + "dataField = \"bar\", " + "structField = (" + "voidField = void, " + "boolField = true, " + "int8Field = -12, " + "int16Field = 3456, " + "int32Field = -78901234, " + "int64Field = 56789012345678, " + "uInt8Field = 90, " + "uInt16Field = 1234, " + "uInt32Field = 56789012, " + "uInt64Field = 345678901234567890, " + "float32Field = -1.25e-10, " + "float64Field = 345, " + "textField = \"baz\", " + "dataField = \"qux\", " + "structField = (" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"nested\", " + "structField = (" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"really nested\", " + "enumField = foo, " + "interfaceField = void), " + "enumField = foo, " + "interfaceField = void), " + "enumField = baz, " + "interfaceField = void, " + "voidList = [void, void, void], " + "boolList = [false, true, false, true, true], " + "int8List = [12, -34, -128, 127], " + "int16List = [1234, -5678, -32768, 32767], " + "int32List = [12345678, -90123456, -2147483648, 2147483647], " + "int64List = [123456789012345, -678901234567890, " + "-9223372036854775808, 9223372036854775807], " + "uInt8List = [12, 34, 0, 255], " + "uInt16List = [1234, 5678, 0, 65535], " + "uInt32List = [12345678, 90123456, 0, 4294967295], " + "uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615], " + "float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], " + "float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], " + "textList = [\"quux\", \"corge\", \"grault\"], " + "dataList = [\"garply\", \"waldo\", \"fred\"], " + "structList = [" + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"x structlist 1\", " + "enumField = foo, " + "interfaceField = void), " + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"x structlist 2\", " + "enumField = foo, " + "interfaceField = void), " + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"x structlist 3\", " + "enumField = foo, " + "interfaceField = void)], " + "enumList = [qux, bar, grault]), " + "enumField = corge, " + "interfaceField = void, " + "voidList = [void, void, void, void, void, void], " + "boolList = [true, false, false, true], " + "int8List = [111, -111], " + "int16List = [11111, -11111], " + "int32List = [111111111, -111111111], " + "int64List = [1111111111111111111, -1111111111111111111], " + "uInt8List = [111, 222], " + "uInt16List = [33333, 44444], " + "uInt32List = [3333333333], " + "uInt64List = [11111111111111111111], " + "float32List = [5555.5, inf, -inf, nan], " + "float64List = [7777.75, inf, -inf, nan], " + "textList = [\"plugh\", \"xyzzy\", \"thud\"], " + "dataList = [\"oops\", \"exhausted\", \"rfc3092\"], " + "structList = [" + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"structlist 1\", " + "enumField = foo, " + "interfaceField = void), " + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"structlist 2\", " + "enumField = foo, " + "interfaceField = void), " + "(" + "voidField = void, " + "boolField = false, " + "int8Field = 0, " + "int16Field = 0, " + "int32Field = 0, " + "int64Field = 0, " + "uInt8Field = 0, " + "uInt16Field = 0, " + "uInt32Field = 0, " + "uInt64Field = 0, " + "float32Field = 0, " + "float64Field = 0, " + "textField = \"structlist 3\", " + "enumField = foo, " + "interfaceField = void)], " + "enumList = [foo, garply])", + kj::str(root)); +} + +TEST(Stringify, PrettyPrint) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + EXPECT_EQ( + "( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " enumField = foo,\n" + " interfaceField = void )", prettyPrint(root).flatten()); + + initTestMessage(root); + + EXPECT_EQ( + "( voidField = void,\n" + " boolField = true,\n" + " int8Field = -123,\n" + " int16Field = -12345,\n" + " int32Field = -12345678,\n" + " int64Field = -123456789012345,\n" + " uInt8Field = 234,\n" + " uInt16Field = 45678,\n" + " uInt32Field = 3456789012,\n" + " uInt64Field = 12345678901234567890,\n" + " float32Field = 1234.5,\n" + " float64Field = -1.23e47,\n" + " textField = \"foo\",\n" + " dataField = \"bar\",\n" + " structField = (\n" + " voidField = void,\n" + " boolField = true,\n" + " int8Field = -12,\n" + " int16Field = 3456,\n" + " int32Field = -78901234,\n" + " int64Field = 56789012345678,\n" + " uInt8Field = 90,\n" + " uInt16Field = 1234,\n" + " uInt32Field = 56789012,\n" + " uInt64Field = 345678901234567890,\n" + " float32Field = -1.25e-10,\n" + " float64Field = 345,\n" + " textField = \"baz\",\n" + " dataField = \"qux\",\n" + " structField = (\n" + " voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"nested\",\n" + " structField = (\n" + " voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"really nested\",\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " enumField = baz,\n" + " interfaceField = void,\n" + " voidList = [void, void, void],\n" + " boolList = [false, true, false, true, true],\n" + " int8List = [12, -34, -128, 127],\n" + " int16List = [1234, -5678, -32768, 32767],\n" + " int32List = [12345678, -90123456, -2147483648, 2147483647],\n" + " int64List = [123456789012345, -678901234567890, " + "-9223372036854775808, 9223372036854775807],\n" + " uInt8List = [12, 34, 0, 255],\n" + " uInt16List = [1234, 5678, 0, 65535],\n" + " uInt32List = [12345678, 90123456, 0, 4294967295],\n" + " uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615],\n" + " float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37],\n" + " float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306],\n" + " textList = [\"quux\", \"corge\", \"grault\"],\n" + " dataList = [\"garply\", \"waldo\", \"fred\"],\n" + " structList = [\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"x structlist 1\",\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"x structlist 2\",\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"x structlist 3\",\n" + " enumField = foo,\n" + " interfaceField = void ) ],\n" + " enumList = [qux, bar, grault] ),\n" + " enumField = corge,\n" + " interfaceField = void,\n" + " voidList = [void, void, void, void, void, void],\n" + " boolList = [true, false, false, true],\n" + " int8List = [111, -111],\n" + " int16List = [11111, -11111],\n" + " int32List = [111111111, -111111111],\n" + " int64List = [1111111111111111111, -1111111111111111111],\n" + " uInt8List = [111, 222],\n" + " uInt16List = [33333, 44444],\n" + " uInt32List = [3333333333],\n" + " uInt64List = [11111111111111111111],\n" + " float32List = [5555.5, inf, -inf, nan],\n" + " float64List = [7777.75, inf, -inf, nan],\n" + " textList = [\"plugh\", \"xyzzy\", \"thud\"],\n" + " dataList = [\"oops\", \"exhausted\", \"rfc3092\"],\n" + " structList = [\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"structlist 1\",\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"structlist 2\",\n" + " enumField = foo,\n" + " interfaceField = void ),\n" + " ( voidField = void,\n" + " boolField = false,\n" + " int8Field = 0,\n" + " int16Field = 0,\n" + " int32Field = 0,\n" + " int64Field = 0,\n" + " uInt8Field = 0,\n" + " uInt16Field = 0,\n" + " uInt32Field = 0,\n" + " uInt64Field = 0,\n" + " float32Field = 0,\n" + " float64Field = 0,\n" + " textField = \"structlist 3\",\n" + " enumField = foo,\n" + " interfaceField = void ) ],\n" + " enumList = [foo, garply] )", + prettyPrint(root).flatten()); +} + +TEST(Stringify, PrettyPrintAdvanced) { + MallocMessageBuilder builder; + + { + auto root = builder.initRoot(); + + auto list = root.initStructList(3); + list[0].setInt32Field(123); + list[0].setTextField("foo"); + list[1].setInt32Field(456); + list[1].setTextField("bar"); + list[2].setInt32Field(789); + list[2].setTextField("baz"); + + EXPECT_EQ( + "( structList = [\n" + " (int32Field = 123, textField = \"foo\"),\n" + " (int32Field = 456, textField = \"bar\"),\n" + " (int32Field = 789, textField = \"baz\") ] )", + prettyPrint(root).flatten()); + + root.setSomeText("foo"); + + EXPECT_EQ( + "( someText = \"foo\",\n" + " structList = [\n" + " (int32Field = 123, textField = \"foo\"),\n" + " (int32Field = 456, textField = \"bar\"),\n" + " (int32Field = 789, textField = \"baz\") ] )", + prettyPrint(root).flatten()); + } + + { + auto root = builder.initRoot(); + auto ll = root.initInt32ListList(3); + ll.set(0, {123, 456, 789, 1234567890}); + ll.set(1, {234, 567, 891, 1234567890}); + ll.set(2, {345, 678, 912, 1234567890}); + + EXPECT_EQ( + "[ [123, 456, 789, 1234567890],\n" + " [234, 567, 891, 1234567890],\n" + " [345, 678, 912, 1234567890] ]", + prettyPrint(ll).flatten()); + + EXPECT_EQ( + "( int32ListList = [\n" + " [123, 456, 789, 1234567890],\n" + " [234, 567, 891, 1234567890],\n" + " [345, 678, 912, 1234567890] ] )", + prettyPrint(root).flatten()); + + root.initList8(0); + + EXPECT_EQ( + "( list8 = [],\n" + " int32ListList = [\n" + " [123, 456, 789, 1234567890],\n" + " [234, 567, 891, 1234567890],\n" + " [345, 678, 912, 1234567890] ] )", + prettyPrint(root).flatten()); + + auto l8 = root.initList8(1); + l8[0].setF(12); + + EXPECT_EQ( + "( list8 = [(f = 12)],\n" + " int32ListList = [\n" + " [123, 456, 789, 1234567890],\n" + " [234, 567, 891, 1234567890],\n" + " [345, 678, 912, 1234567890] ] )", + prettyPrint(root).flatten()); + + l8 = root.initList8(2); + l8[0].setF(12); + l8[1].setF(34); + + EXPECT_EQ( + "( list8 = [(f = 12), (f = 34)],\n" + " int32ListList = [\n" + " [123, 456, 789, 1234567890],\n" + " [234, 567, 891, 1234567890],\n" + " [345, 678, 912, 1234567890] ] )", + prettyPrint(root).flatten()); + } + + { + auto root = builder.initRoot(); + + auto s = root.getUn().initStruct(); + EXPECT_EQ( + "(un = (struct = ()))", + prettyPrint(root).flatten()); + + s.setSomeText("foo"); + EXPECT_EQ( + "( un = (\n" + " struct = (someText = \"foo\") ) )", + prettyPrint(root).flatten()); + + s.setMoreText("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar"); + EXPECT_EQ( + "( un = (\n" + " struct = (\n" + " someText = \"foo\",\n" + " moreText = \"baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\" ) ) )", + prettyPrint(root).flatten()); + } +} + +TEST(Stringify, Unions) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getUnion0().setU0f0s16(123); + root.getUnion1().setU1f0sp("foo"); + root.getUnion2().setU2f0s1(true); + root.getUnion3().setU3f0s64(123456789012345678ll); + + EXPECT_EQ("(" + "union0 = (u0f0s16 = 123), " + "union1 = (u1f0sp = \"foo\"), " + "union2 = (u2f0s1 = true), " + "union3 = (u3f0s64 = 123456789012345678), " + "bit0 = false, bit2 = false, bit3 = false, bit4 = false, bit5 = false, " + "bit6 = false, bit7 = false, byte0 = 0)", + kj::str(root)); + + EXPECT_EQ("(u0f0s16 = 123)", kj::str(root.getUnion0())); + EXPECT_EQ("(u1f0sp = \"foo\")", kj::str(root.getUnion1())); + EXPECT_EQ("(u2f0s1 = true)", kj::str(root.getUnion2())); + EXPECT_EQ("(u3f0s64 = 123456789012345678)", kj::str(root.getUnion3())); +} + +TEST(Stringify, UnionDefaults) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.getUnion0().setU0f0s16(0); // Non-default field has default value. + root.getUnion1().setU1f0sp("foo"); // Non-default field has non-default value. + root.getUnion2().setU2f0s1(false); // Default field has default value. + root.getUnion3().setU3f0s1(true); // Default field has non-default value. + + EXPECT_EQ("(" + "union0 = (u0f0s16 = 0), " + "union1 = (u1f0sp = \"foo\"), " + "union2 = (u2f0s1 = false), " + "union3 = (u3f0s1 = true), " + "bit0 = false, bit2 = false, bit3 = false, bit4 = false, bit5 = false, " + "bit6 = false, bit7 = false, byte0 = 0)", + kj::str(root)); + + EXPECT_EQ("(u0f0s16 = 0)", kj::str(root.getUnion0())); + EXPECT_EQ("(u1f0sp = \"foo\")", kj::str(root.getUnion1())); + EXPECT_EQ("(u2f0s1 = false)", kj::str(root.getUnion2())); + EXPECT_EQ("(u3f0s1 = true)", kj::str(root.getUnion3())); +} + +TEST(Stringify, UnnamedUnions) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + root.setBar(123); + + EXPECT_EQ("(middle = 0, bar = 123)", kj::str(root)); + EXPECT_EQ("(middle = 0, bar = 123)", prettyPrint(root).flatten()); + + root.setAfter("foooooooooooooooooooooooooooooooo"); + + EXPECT_EQ("(middle = 0, bar = 123, after = \"foooooooooooooooooooooooooooooooo\")", + kj::str(root)); + EXPECT_EQ( + "( middle = 0,\n" + " bar = 123,\n" + " after = \"foooooooooooooooooooooooooooooooo\" )", + prettyPrint(root).flatten()); + + root.setBefore("before"); + + EXPECT_EQ("(before = \"before\", middle = 0, bar = 123, " + "after = \"foooooooooooooooooooooooooooooooo\")", kj::str(root)); + EXPECT_EQ( + "( before = \"before\",\n" + " middle = 0,\n" + " bar = 123,\n" + " after = \"foooooooooooooooooooooooooooooooo\" )", + prettyPrint(root).flatten()); + + root.setFoo(0); + + EXPECT_EQ( + "(before = \"before\", foo = 0, middle = 0, after = \"foooooooooooooooooooooooooooooooo\")", + kj::str(root)); + EXPECT_EQ( + "( before = \"before\",\n" + " foo = 0,\n" + " middle = 0,\n" + " after = \"foooooooooooooooooooooooooooooooo\" )", + prettyPrint(root).flatten()); +} + +TEST(Stringify, StructUnions) { + MallocMessageBuilder builder; + auto root = builder.initRoot(); + + auto s = root.getUn().initStruct(); + s.setSomeText("foo"); + s.setMoreText("bar"); + + EXPECT_EQ("(un = (struct = (someText = \"foo\", moreText = \"bar\")))", kj::str(root)); +} + +TEST(Stringify, MoreValues) { + EXPECT_EQ("123", kj::str(DynamicValue::Reader(123))); + EXPECT_EQ("1.23e47", kj::str(DynamicValue::Reader(123e45))); + EXPECT_EQ("\"foo\"", kj::str(DynamicValue::Reader("foo"))); + EXPECT_EQ("\"\\a\\b\\n\\t\\\"\"", kj::str(DynamicValue::Reader("\a\b\n\t\""))); + + EXPECT_EQ("foo", kj::str(DynamicValue::Reader(TestEnum::FOO))); + EXPECT_EQ("(123)", kj::str(DynamicValue::Reader(static_cast(123)))); +} + +TEST(Stringify, Generics) { + MallocMessageBuilder builder; + auto root = builder.initRoot>::Inner>(); + root.setFoo("abcd"); + auto l = root.initBar(2); + l.set(0, 123); + l.set(1, 456); + + EXPECT_EQ("(foo = \"abcd\", bar = [123, 456])", kj::str(root)); +} + +} // namespace +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/stringify.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/stringify.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,300 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "dynamic.h" +#include +#include + +namespace capnp { + +namespace { + +static const char HEXDIGITS[] = "0123456789abcdef"; + +enum PrintMode { + BARE, + // The value is planned to be printed on its own line, unless it is very short and contains + // no inner newlines. + + PREFIXED, + // The value is planned to be printed with a prefix, like "memberName = " (a struct field). + + PARENTHESIZED + // The value is printed in parenthesized (a union value). +}; + +enum class PrintKind { + LIST, + RECORD +}; + +class Indent { +public: + explicit Indent(bool enable): amount(enable ? 1 : 0) {} + + Indent next() { + return Indent(amount == 0 ? 0 : amount + 1); + } + + kj::StringTree delimit(kj::Array items, PrintMode mode, PrintKind kind) { + if (amount == 0 || canPrintAllInline(items, kind)) { + return kj::StringTree(kj::mv(items), ", "); + } else { + KJ_STACK_ARRAY(char, delimArrayPtr, amount * 2 + 3, 32, 256); + auto delim = delimArrayPtr.begin(); + delim[0] = ','; + delim[1] = '\n'; + memset(delim + 2, ' ', amount * 2); + delim[amount * 2 + 2] = '\0'; + + // If the outer value isn't being printed on its own line, we need to add a newline/indent + // before the first item, otherwise we only add a space on the assumption that it is preceded + // by an open bracket or parenthesis. + return kj::strTree(mode == BARE ? " " : delim + 1, + kj::StringTree(kj::mv(items), kj::StringPtr(delim, amount * 2 + 2)), ' '); + } + } + +private: + uint amount; + + explicit Indent(uint amount): amount(amount) {} + + static constexpr size_t maxInlineValueSize = 24; + static constexpr size_t maxInlineRecordSize = 64; + + static bool canPrintInline(const kj::StringTree& text) { + if (text.size() > maxInlineValueSize) { + return false; + } + + char flat[maxInlineValueSize + 1]; + text.flattenTo(flat); + flat[text.size()] = '\0'; + if (strchr(flat, '\n') != nullptr) { + return false; + } + + return true; + } + + static bool canPrintAllInline(const kj::Array& items, PrintKind kind) { + size_t totalSize = 0; + for (auto& item: items) { + if (!canPrintInline(item)) return false; + if (kind == PrintKind::RECORD) { + totalSize += item.size(); + if (totalSize > maxInlineRecordSize) return false; + } + } + return true; + } +}; + +static schema::Type::Which whichFieldType(const StructSchema::Field& field) { + auto proto = field.getProto(); + switch (proto.which()) { + case schema::Field::SLOT: + return proto.getSlot().getType().which(); + case schema::Field::GROUP: + return schema::Type::STRUCT; + } + KJ_UNREACHABLE; +} + +static kj::StringTree print(const DynamicValue::Reader& value, + schema::Type::Which which, Indent indent, + PrintMode mode) { + switch (value.getType()) { + case DynamicValue::UNKNOWN: + return kj::strTree("?"); + case DynamicValue::VOID: + return kj::strTree("void"); + case DynamicValue::BOOL: + return kj::strTree(value.as() ? "true" : "false"); + case DynamicValue::INT: + return kj::strTree(value.as()); + case DynamicValue::UINT: + return kj::strTree(value.as()); + case DynamicValue::FLOAT: + if (which == schema::Type::FLOAT32) { + return kj::strTree(value.as()); + } else { + return kj::strTree(value.as()); + } + case DynamicValue::TEXT: + case DynamicValue::DATA: { + // TODO(someday): Maybe data should be printed as binary literal. + kj::ArrayPtr chars; + if (value.getType() == DynamicValue::DATA) { + chars = value.as().asChars(); + } else { + chars = value.as(); + } + + kj::Vector escaped(chars.size()); + + for (char c: chars) { + switch (c) { + case '\a': escaped.addAll(kj::StringPtr("\\a")); break; + case '\b': escaped.addAll(kj::StringPtr("\\b")); break; + case '\f': escaped.addAll(kj::StringPtr("\\f")); break; + case '\n': escaped.addAll(kj::StringPtr("\\n")); break; + case '\r': escaped.addAll(kj::StringPtr("\\r")); break; + case '\t': escaped.addAll(kj::StringPtr("\\t")); break; + case '\v': escaped.addAll(kj::StringPtr("\\v")); break; + case '\'': escaped.addAll(kj::StringPtr("\\\'")); break; + case '\"': escaped.addAll(kj::StringPtr("\\\"")); break; + case '\\': escaped.addAll(kj::StringPtr("\\\\")); break; + default: + if (c < 0x20) { + escaped.add('\\'); + escaped.add('x'); + uint8_t c2 = c; + escaped.add(HEXDIGITS[c2 / 16]); + escaped.add(HEXDIGITS[c2 % 16]); + } else { + escaped.add(c); + } + break; + } + } + return kj::strTree('"', escaped, '"'); + } + case DynamicValue::LIST: { + auto listValue = value.as(); + auto which = listValue.getSchema().whichElementType(); + kj::Array elements = KJ_MAP(element, listValue) { + return print(element, which, indent.next(), BARE); + }; + return kj::strTree('[', indent.delimit(kj::mv(elements), mode, PrintKind::LIST), ']'); + } + case DynamicValue::ENUM: { + auto enumValue = value.as(); + KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) { + return kj::strTree(enumerant->getProto().getName()); + } else { + // Unknown enum value; output raw number. + return kj::strTree('(', enumValue.getRaw(), ')'); + } + break; + } + case DynamicValue::STRUCT: { + auto structValue = value.as(); + auto unionFields = structValue.getSchema().getUnionFields(); + auto nonUnionFields = structValue.getSchema().getNonUnionFields(); + + kj::Vector printedFields(nonUnionFields.size() + (unionFields.size() != 0)); + + // We try to write the union field, if any, in proper order with the rest. + auto which = structValue.which(); + + kj::StringTree unionValue; + KJ_IF_MAYBE(field, which) { + // Even if the union field has its default value, if it is not the default field of the + // union then we have to print it anyway. + auto fieldProto = field->getProto(); + if (fieldProto.getDiscriminantValue() != 0 || structValue.has(*field)) { + unionValue = kj::strTree( + fieldProto.getName(), " = ", + print(structValue.get(*field), whichFieldType(*field), indent.next(), PREFIXED)); + } else { + which = nullptr; + } + } + + for (auto field: nonUnionFields) { + KJ_IF_MAYBE(unionField, which) { + if (unionField->getIndex() < field.getIndex()) { + printedFields.add(kj::mv(unionValue)); + which = nullptr; + } + } + if (structValue.has(field)) { + printedFields.add(kj::strTree( + field.getProto().getName(), " = ", + print(structValue.get(field), whichFieldType(field), indent.next(), PREFIXED))); + } + } + if (which != nullptr) { + // Union value is last. + printedFields.add(kj::mv(unionValue)); + } + + if (mode == PARENTHESIZED) { + return indent.delimit(printedFields.releaseAsArray(), mode, PrintKind::RECORD); + } else { + return kj::strTree( + '(', indent.delimit(printedFields.releaseAsArray(), mode, PrintKind::RECORD), ')'); + } + } + case DynamicValue::CAPABILITY: + return kj::strTree(""); + case DynamicValue::ANY_POINTER: + return kj::strTree(""); + } + + KJ_UNREACHABLE; +} + +kj::StringTree stringify(DynamicValue::Reader value) { + return print(value, schema::Type::STRUCT, Indent(false), BARE); +} + +} // namespace + +kj::StringTree prettyPrint(DynamicStruct::Reader value) { + return print(value, schema::Type::STRUCT, Indent(true), BARE); +} + +kj::StringTree prettyPrint(DynamicList::Reader value) { + return print(value, schema::Type::LIST, Indent(true), BARE); +} + +kj::StringTree prettyPrint(DynamicStruct::Builder value) { return prettyPrint(value.asReader()); } +kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(value.asReader()); } + +kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value) { return stringify(value); } +kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value) { return stringify(value.asReader()); } +kj::StringTree KJ_STRINGIFY(DynamicEnum value) { return stringify(value); } +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value) { return stringify(value); } +kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); } +kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value) { return stringify(value); } +kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value) { return stringify(value.asReader()); } + +namespace _ { // private + +kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema) { + return stringify(DynamicStruct::Reader(Schema(&schema).asStruct(), reader)); +} + +kj::String enumString(uint16_t value, const RawBrandedSchema& schema) { + auto enumerants = Schema(&schema).asEnum().getEnumerants(); + if (value < enumerants.size()) { + return kj::heapString(enumerants[value].getProto().getName()); + } else { + return kj::str(value); + } +} + +} // namespace _ (private) + +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/test-import.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/test-import.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,28 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xf36d7b330303c66e; + +using Test = import "test.capnp"; + +struct TestImport { + field @0 :Test.TestAllTypes; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/test-import2.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/test-import2.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,32 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xc64a3bf0338a124a; + +using Import1 = import "/capnp/schema.capnp"; +using Import2 = import "test-import.capnp"; +using Import3 = import "test.capnp"; + +struct TestImport2 { + foo @0 :Import3.TestAllTypes; + bar @1 :Import1.Node; + baz @2 :Import2.TestImport; +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/test-util.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/test-util.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1150 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "test-util.h" +#include +#include + +namespace capnp { +namespace _ { // private +namespace { + +template +void genericInitTestMessage(Builder builder) { + builder.setVoidField(VOID); + builder.setVoidField(); // Means the same as above. + builder.setBoolField(true); + builder.setInt8Field(-123); + builder.setInt16Field(-12345); + builder.setInt32Field(-12345678); + builder.setInt64Field(-123456789012345ll); + builder.setUInt8Field(234u); + builder.setUInt16Field(45678u); + builder.setUInt32Field(3456789012u); + builder.setUInt64Field(12345678901234567890ull); + builder.setFloat32Field(1234.5); + builder.setFloat64Field(-123e45); + builder.setTextField("foo"); + builder.setDataField(data("bar")); + { + auto subBuilder = builder.initStructField(); + subBuilder.setVoidField(VOID); + subBuilder.setBoolField(true); + subBuilder.setInt8Field(-12); + subBuilder.setInt16Field(3456); + subBuilder.setInt32Field(-78901234); + subBuilder.setInt64Field(56789012345678ll); + subBuilder.setUInt8Field(90u); + subBuilder.setUInt16Field(1234u); + subBuilder.setUInt32Field(56789012u); + subBuilder.setUInt64Field(345678901234567890ull); + subBuilder.setFloat32Field(-1.25e-10f); + subBuilder.setFloat64Field(345); + subBuilder.setTextField("baz"); + subBuilder.setDataField(data("qux")); + { + auto subSubBuilder = subBuilder.initStructField(); + subSubBuilder.setTextField("nested"); + subSubBuilder.initStructField().setTextField("really nested"); + } + subBuilder.setEnumField(TestEnum::BAZ); + + subBuilder.setVoidList({VOID, VOID, VOID}); + subBuilder.setBoolList({false, true, false, true, true}); + subBuilder.setInt8List({12, -34, -0x80, 0x7f}); + subBuilder.setInt16List({1234, -5678, -0x8000, 0x7fff}); + // gcc warns on -0x800... and the only work-around I could find was to do -0x7ff...-1. + subBuilder.setInt32List({12345678, -90123456, -0x7fffffff - 1, 0x7fffffff}); + subBuilder.setInt64List({123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll}); + subBuilder.setUInt8List({12u, 34u, 0u, 0xffu}); + subBuilder.setUInt16List({1234u, 5678u, 0u, 0xffffu}); + subBuilder.setUInt32List({12345678u, 90123456u, 0u, 0xffffffffu}); + subBuilder.setUInt64List({123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); + subBuilder.setFloat32List({0, 1234567, 1e37f, -1e37f, 1e-37f, -1e-37f}); + subBuilder.setFloat64List({0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306}); + subBuilder.setTextList({"quux", "corge", "grault"}); + subBuilder.setDataList({data("garply"), data("waldo"), data("fred")}); + { + auto listBuilder = subBuilder.initStructList(3); + listBuilder[0].setTextField("x structlist 1"); + listBuilder[1].setTextField("x structlist 2"); + listBuilder[2].setTextField("x structlist 3"); + } + subBuilder.setEnumList({TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT}); + } + builder.setEnumField(TestEnum::CORGE); + + builder.initVoidList(6); + builder.setBoolList({true, false, false, true}); + builder.setInt8List({111, -111}); + builder.setInt16List({11111, -11111}); + builder.setInt32List({111111111, -111111111}); + builder.setInt64List({1111111111111111111ll, -1111111111111111111ll}); + builder.setUInt8List({111u, 222u}); + builder.setUInt16List({33333u, 44444u}); + builder.setUInt32List({3333333333u}); + builder.setUInt64List({11111111111111111111ull}); + builder.setFloat32List({5555.5, kj::inf(), -kj::inf(), kj::nan()}); + builder.setFloat64List({7777.75, kj::inf(), -kj::inf(), kj::nan()}); + builder.setTextList({"plugh", "xyzzy", "thud"}); + builder.setDataList({data("oops"), data("exhausted"), data("rfc3092")}); + { + auto listBuilder = builder.initStructList(3); + listBuilder[0].setTextField("structlist 1"); + listBuilder[1].setTextField("structlist 2"); + listBuilder[2].setTextField("structlist 3"); + } + builder.setEnumList({TestEnum::FOO, TestEnum::GARPLY}); +} + +#if !CAPNP_LITE + +void dynamicInitTestMessage(DynamicStruct::Builder builder) { + builder.set("voidField", VOID); + builder.set("boolField", true); + builder.set("int8Field", -123); + builder.set("int16Field", -12345); + builder.set("int32Field", -12345678); + builder.set("int64Field", -123456789012345ll); + builder.set("uInt8Field", 234u); + builder.set("uInt16Field", 45678u); + builder.set("uInt32Field", 3456789012u); + builder.set("uInt64Field", 12345678901234567890ull); + builder.set("float32Field", 1234.5); + builder.set("float64Field", -123e45); + builder.set("textField", "foo"); + builder.set("dataField", data("bar")); + { + auto subBuilder = builder.init("structField").as(); + subBuilder.set("voidField", VOID); + subBuilder.set("boolField", true); + subBuilder.set("int8Field", -12); + subBuilder.set("int16Field", 3456); + subBuilder.set("int32Field", -78901234); + subBuilder.set("int64Field", 56789012345678ll); + subBuilder.set("uInt8Field", 90u); + subBuilder.set("uInt16Field", 1234u); + subBuilder.set("uInt32Field", 56789012u); + subBuilder.set("uInt64Field", 345678901234567890ull); + subBuilder.set("float32Field", -1.25e-10); + subBuilder.set("float64Field", 345); + subBuilder.set("textField", "baz"); + subBuilder.set("dataField", data("qux")); + { + auto subSubBuilder = subBuilder.init("structField").as(); + subSubBuilder.set("textField", "nested"); + subSubBuilder.init("structField").as().set("textField", "really nested"); + } + subBuilder.set("enumField", "baz"); + + subBuilder.set("voidList", {VOID, VOID, VOID}); + subBuilder.set("boolList", {false, true, false, true, true}); + subBuilder.set("int8List", {12, -34, -0x80, 0x7f}); + subBuilder.set("int16List", {1234, -5678, -0x8000, 0x7fff}); + // gcc warns on -0x800... and the only work-around I could find was to do -0x7ff...-1. + subBuilder.set("int32List", {12345678, -90123456, -0x7fffffff - 1, 0x7fffffff}); + subBuilder.set("int64List", {123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll}); + subBuilder.set("uInt8List", {12u, 34u, 0u, 0xffu}); + subBuilder.set("uInt16List", {1234u, 5678u, 0u, 0xffffu}); + subBuilder.set("uInt32List", {12345678u, 90123456u, 0u, 0xffffffffu}); + subBuilder.set("uInt64List", {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); + subBuilder.set("float32List", {0, 1234567, 1e37, -1e37, 1e-37, -1e-37}); + subBuilder.set("float64List", {0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306}); + subBuilder.set("textList", {"quux", "corge", "grault"}); + subBuilder.set("dataList", {data("garply"), data("waldo"), data("fred")}); + { + auto listBuilder = subBuilder.init("structList", 3).as(); + listBuilder[0].as().set("textField", "x structlist 1"); + listBuilder[1].as().set("textField", "x structlist 2"); + listBuilder[2].as().set("textField", "x structlist 3"); + } + subBuilder.set("enumList", {"qux", "bar", "grault"}); + } + builder.set("enumField", "corge"); + + builder.init("voidList", 6); + builder.set("boolList", {true, false, false, true}); + builder.set("int8List", {111, -111}); + builder.set("int16List", {11111, -11111}); + builder.set("int32List", {111111111, -111111111}); + builder.set("int64List", {1111111111111111111ll, -1111111111111111111ll}); + builder.set("uInt8List", {111u, 222u}); + builder.set("uInt16List", {33333u, 44444u}); + builder.set("uInt32List", {3333333333u}); + builder.set("uInt64List", {11111111111111111111ull}); + builder.set("float32List", {5555.5, kj::inf(), -kj::inf(), kj::nan()}); + builder.set("float64List", {7777.75, kj::inf(), -kj::inf(), kj::nan()}); + builder.set("textList", {"plugh", "xyzzy", "thud"}); + builder.set("dataList", {data("oops"), data("exhausted"), data("rfc3092")}); + { + auto listBuilder = builder.init("structList", 3).as(); + listBuilder[0].as().set("textField", "structlist 1"); + listBuilder[1].as().set("textField", "structlist 2"); + listBuilder[2].as().set("textField", "structlist 3"); + } + builder.set("enumList", {"foo", "garply"}); +} + +#endif // !CAPNP_LITE + +inline bool isNaN(float f) { return f != f; } +inline bool isNaN(double f) { return f != f; } + +template +void genericCheckTestMessage(Reader reader) { + EXPECT_EQ(VOID, reader.getVoidField()); + EXPECT_EQ(true, reader.getBoolField()); + EXPECT_EQ(-123, reader.getInt8Field()); + EXPECT_EQ(-12345, reader.getInt16Field()); + EXPECT_EQ(-12345678, reader.getInt32Field()); + EXPECT_EQ(-123456789012345ll, reader.getInt64Field()); + EXPECT_EQ(234u, reader.getUInt8Field()); + EXPECT_EQ(45678u, reader.getUInt16Field()); + EXPECT_EQ(3456789012u, reader.getUInt32Field()); + EXPECT_EQ(12345678901234567890ull, reader.getUInt64Field()); + EXPECT_FLOAT_EQ(1234.5f, reader.getFloat32Field()); + EXPECT_DOUBLE_EQ(-123e45, reader.getFloat64Field()); + EXPECT_EQ("foo", reader.getTextField()); + EXPECT_EQ(data("bar"), reader.getDataField()); + { + auto subReader = reader.getStructField(); + EXPECT_EQ(VOID, subReader.getVoidField()); + EXPECT_EQ(true, subReader.getBoolField()); + EXPECT_EQ(-12, subReader.getInt8Field()); + EXPECT_EQ(3456, subReader.getInt16Field()); + EXPECT_EQ(-78901234, subReader.getInt32Field()); + EXPECT_EQ(56789012345678ll, subReader.getInt64Field()); + EXPECT_EQ(90u, subReader.getUInt8Field()); + EXPECT_EQ(1234u, subReader.getUInt16Field()); + EXPECT_EQ(56789012u, subReader.getUInt32Field()); + EXPECT_EQ(345678901234567890ull, subReader.getUInt64Field()); + EXPECT_FLOAT_EQ(-1.25e-10f, subReader.getFloat32Field()); + EXPECT_DOUBLE_EQ(345, subReader.getFloat64Field()); + EXPECT_EQ("baz", subReader.getTextField()); + EXPECT_EQ(data("qux"), subReader.getDataField()); + { + auto subSubReader = subReader.getStructField(); + EXPECT_EQ("nested", subSubReader.getTextField()); + EXPECT_EQ("really nested", subSubReader.getStructField().getTextField()); + } + EXPECT_EQ(TestEnum::BAZ, subReader.getEnumField()); + + checkList(subReader.getVoidList(), {VOID, VOID, VOID}); + checkList(subReader.getBoolList(), {false, true, false, true, true}); + checkList(subReader.getInt8List(), {12, -34, -0x80, 0x7f}); + checkList(subReader.getInt16List(), {1234, -5678, -0x8000, 0x7fff}); + // gcc warns on -0x800... and the only work-around I could find was to do -0x7ff...-1. + checkList(subReader.getInt32List(), {12345678, -90123456, -0x7fffffff - 1, 0x7fffffff}); + checkList(subReader.getInt64List(), {123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll}); + checkList(subReader.getUInt8List(), {12u, 34u, 0u, 0xffu}); + checkList(subReader.getUInt16List(), {1234u, 5678u, 0u, 0xffffu}); + checkList(subReader.getUInt32List(), {12345678u, 90123456u, 0u, 0xffffffffu}); + checkList(subReader.getUInt64List(), {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); + checkList(subReader.getFloat32List(), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f}); + checkList(subReader.getFloat64List(), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306}); + checkList(subReader.getTextList(), {"quux", "corge", "grault"}); + checkList(subReader.getDataList(), {data("garply"), data("waldo"), data("fred")}); + { + auto listReader = subReader.getStructList(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("x structlist 1", listReader[0].getTextField()); + EXPECT_EQ("x structlist 2", listReader[1].getTextField()); + EXPECT_EQ("x structlist 3", listReader[2].getTextField()); + } + checkList(subReader.getEnumList(), {TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT}); + } + EXPECT_EQ(TestEnum::CORGE, reader.getEnumField()); + + EXPECT_EQ(6u, reader.getVoidList().size()); + checkList(reader.getBoolList(), {true, false, false, true}); + checkList(reader.getInt8List(), {111, -111}); + checkList(reader.getInt16List(), {11111, -11111}); + checkList(reader.getInt32List(), {111111111, -111111111}); + checkList(reader.getInt64List(), {1111111111111111111ll, -1111111111111111111ll}); + checkList(reader.getUInt8List(), {111u, 222u}); + checkList(reader.getUInt16List(), {33333u, 44444u}); + checkList(reader.getUInt32List(), {3333333333u}); + checkList(reader.getUInt64List(), {11111111111111111111ull}); + { + auto listReader = reader.getFloat32List(); + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(5555.5f, listReader[0]); + EXPECT_EQ(kj::inf(), listReader[1]); + EXPECT_EQ(-kj::inf(), listReader[2]); + EXPECT_TRUE(isNaN(listReader[3])); + } + { + auto listReader = reader.getFloat64List(); + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(7777.75, listReader[0]); + EXPECT_EQ(kj::inf(), listReader[1]); + EXPECT_EQ(-kj::inf(), listReader[2]); + EXPECT_TRUE(isNaN(listReader[3])); + } + checkList(reader.getTextList(), {"plugh", "xyzzy", "thud"}); + checkList(reader.getDataList(), {data("oops"), data("exhausted"), data("rfc3092")}); + { + auto listReader = reader.getStructList(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("structlist 1", listReader[0].getTextField()); + EXPECT_EQ("structlist 2", listReader[1].getTextField()); + EXPECT_EQ("structlist 3", listReader[2].getTextField()); + } + checkList(reader.getEnumList(), {TestEnum::FOO, TestEnum::GARPLY}); +} + +#if !CAPNP_LITE + +// Hack because as<>() is a template-parameter-dependent lookup everywhere below... +#define as template as + +Text::Reader name(DynamicEnum e) { + KJ_IF_MAYBE(schema, e.getEnumerant()) { + return schema->getProto().getName(); + } else { + return "(unknown enumerant)"; + } +} + +template +void checkEnumList(T reader, std::initializer_list expected) { + auto list = reader.as(); + ASSERT_EQ(expected.size(), list.size()); + for (uint i = 0; i < expected.size(); i++) { + EXPECT_EQ(expected.begin()[i], name(list[i].as())); + } +} + +template +void dynamicCheckTestMessage(Reader reader) { + EXPECT_EQ(VOID, reader.get("voidField").as()); + EXPECT_EQ(true, reader.get("boolField").as()); + EXPECT_EQ(-123, reader.get("int8Field").as()); + EXPECT_EQ(-12345, reader.get("int16Field").as()); + EXPECT_EQ(-12345678, reader.get("int32Field").as()); + EXPECT_EQ(-123456789012345ll, reader.get("int64Field").as()); + EXPECT_EQ(234u, reader.get("uInt8Field").as()); + EXPECT_EQ(45678u, reader.get("uInt16Field").as()); + EXPECT_EQ(3456789012u, reader.get("uInt32Field").as()); + EXPECT_EQ(12345678901234567890ull, reader.get("uInt64Field").as()); + EXPECT_FLOAT_EQ(1234.5f, reader.get("float32Field").as()); + EXPECT_DOUBLE_EQ(-123e45, reader.get("float64Field").as()); + EXPECT_EQ("foo", reader.get("textField").as()); + EXPECT_EQ(data("bar"), reader.get("dataField").as()); + { + auto subReader = reader.get("structField").as(); + EXPECT_EQ(VOID, subReader.get("voidField").as()); + EXPECT_EQ(true, subReader.get("boolField").as()); + EXPECT_EQ(-12, subReader.get("int8Field").as()); + EXPECT_EQ(3456, subReader.get("int16Field").as()); + EXPECT_EQ(-78901234, subReader.get("int32Field").as()); + EXPECT_EQ(56789012345678ll, subReader.get("int64Field").as()); + EXPECT_EQ(90u, subReader.get("uInt8Field").as()); + EXPECT_EQ(1234u, subReader.get("uInt16Field").as()); + EXPECT_EQ(56789012u, subReader.get("uInt32Field").as()); + EXPECT_EQ(345678901234567890ull, subReader.get("uInt64Field").as()); + EXPECT_FLOAT_EQ(-1.25e-10f, subReader.get("float32Field").as()); + EXPECT_DOUBLE_EQ(345, subReader.get("float64Field").as()); + EXPECT_EQ("baz", subReader.get("textField").as()); + EXPECT_EQ(data("qux"), subReader.get("dataField").as()); + { + auto subSubReader = subReader.get("structField").as(); + EXPECT_EQ("nested", subSubReader.get("textField").as()); + EXPECT_EQ("really nested", subSubReader.get("structField").as() + .get("textField").as()); + } + EXPECT_EQ("baz", name(subReader.get("enumField").as())); + + checkList(subReader.get("voidList"), {VOID, VOID, VOID}); + checkList(subReader.get("boolList"), {false, true, false, true, true}); + checkList(subReader.get("int8List"), {12, -34, -0x80, 0x7f}); + checkList(subReader.get("int16List"), {1234, -5678, -0x8000, 0x7fff}); + // gcc warns on -0x800... and the only work-around I could find was to do -0x7ff...-1. + checkList(subReader.get("int32List"), {12345678, -90123456, -0x7fffffff-1, 0x7fffffff}); + checkList(subReader.get("int64List"), {123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll}); + checkList(subReader.get("uInt8List"), {12u, 34u, 0u, 0xffu}); + checkList(subReader.get("uInt16List"), {1234u, 5678u, 0u, 0xffffu}); + checkList(subReader.get("uInt32List"), {12345678u, 90123456u, 0u, 0xffffffffu}); + checkList(subReader.get("uInt64List"), {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); + checkList(subReader.get("float32List"), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f}); + checkList(subReader.get("float64List"), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306}); + checkList(subReader.get("textList"), {"quux", "corge", "grault"}); + checkList(subReader.get("dataList"), {data("garply"), data("waldo"), data("fred")}); + { + auto listReader = subReader.get("structList").as(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("x structlist 1", listReader[0].as().get("textField").as()); + EXPECT_EQ("x structlist 2", listReader[1].as().get("textField").as()); + EXPECT_EQ("x structlist 3", listReader[2].as().get("textField").as()); + } + checkEnumList(subReader.get("enumList"), {"qux", "bar", "grault"}); + } + EXPECT_EQ("corge", name(reader.get("enumField").as())); + + EXPECT_EQ(6u, reader.get("voidList").as().size()); + checkList(reader.get("boolList"), {true, false, false, true}); + checkList(reader.get("int8List"), {111, -111}); + checkList(reader.get("int16List"), {11111, -11111}); + checkList(reader.get("int32List"), {111111111, -111111111}); + checkList(reader.get("int64List"), {1111111111111111111ll, -1111111111111111111ll}); + checkList(reader.get("uInt8List"), {111u, 222u}); + checkList(reader.get("uInt16List"), {33333u, 44444u}); + checkList(reader.get("uInt32List"), {3333333333u}); + checkList(reader.get("uInt64List"), {11111111111111111111ull}); + { + auto listReader = reader.get("float32List").as(); + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(5555.5f, listReader[0].as()); + EXPECT_EQ(kj::inf(), listReader[1].as()); + EXPECT_EQ(-kj::inf(), listReader[2].as()); + EXPECT_TRUE(isNaN(listReader[3].as())); + } + { + auto listReader = reader.get("float64List").as(); + ASSERT_EQ(4u, listReader.size()); + EXPECT_EQ(7777.75, listReader[0].as()); + EXPECT_EQ(kj::inf(), listReader[1].as()); + EXPECT_EQ(-kj::inf(), listReader[2].as()); + EXPECT_TRUE(isNaN(listReader[3].as())); + } + checkList(reader.get("textList"), {"plugh", "xyzzy", "thud"}); + checkList(reader.get("dataList"), {data("oops"), data("exhausted"), data("rfc3092")}); + { + auto listReader = reader.get("structList").as(); + ASSERT_EQ(3u, listReader.size()); + EXPECT_EQ("structlist 1", listReader[0].as().get("textField").as()); + EXPECT_EQ("structlist 2", listReader[1].as().get("textField").as()); + EXPECT_EQ("structlist 3", listReader[2].as().get("textField").as()); + } + checkEnumList(reader.get("enumList"), {"foo", "garply"}); +} + +#undef as + +#endif // !CAPNP_LITE + +template +void genericCheckTestMessageAllZero(Reader reader) { + EXPECT_EQ(VOID, reader.getVoidField()); + EXPECT_EQ(false, reader.getBoolField()); + EXPECT_EQ(0, reader.getInt8Field()); + EXPECT_EQ(0, reader.getInt16Field()); + EXPECT_EQ(0, reader.getInt32Field()); + EXPECT_EQ(0, reader.getInt64Field()); + EXPECT_EQ(0u, reader.getUInt8Field()); + EXPECT_EQ(0u, reader.getUInt16Field()); + EXPECT_EQ(0u, reader.getUInt32Field()); + EXPECT_EQ(0u, reader.getUInt64Field()); + EXPECT_FLOAT_EQ(0, reader.getFloat32Field()); + EXPECT_DOUBLE_EQ(0, reader.getFloat64Field()); + EXPECT_EQ("", reader.getTextField()); + EXPECT_EQ(data(""), reader.getDataField()); + { + auto subReader = reader.getStructField(); + EXPECT_EQ(VOID, subReader.getVoidField()); + EXPECT_EQ(false, subReader.getBoolField()); + EXPECT_EQ(0, subReader.getInt8Field()); + EXPECT_EQ(0, subReader.getInt16Field()); + EXPECT_EQ(0, subReader.getInt32Field()); + EXPECT_EQ(0, subReader.getInt64Field()); + EXPECT_EQ(0u, subReader.getUInt8Field()); + EXPECT_EQ(0u, subReader.getUInt16Field()); + EXPECT_EQ(0u, subReader.getUInt32Field()); + EXPECT_EQ(0u, subReader.getUInt64Field()); + EXPECT_FLOAT_EQ(0, subReader.getFloat32Field()); + EXPECT_DOUBLE_EQ(0, subReader.getFloat64Field()); + EXPECT_EQ("", subReader.getTextField()); + EXPECT_EQ(data(""), subReader.getDataField()); + { + auto subSubReader = subReader.getStructField(); + EXPECT_EQ("", subSubReader.getTextField()); + EXPECT_EQ("", subSubReader.getStructField().getTextField()); + } + + EXPECT_EQ(0u, subReader.getVoidList().size()); + EXPECT_EQ(0u, subReader.getBoolList().size()); + EXPECT_EQ(0u, subReader.getInt8List().size()); + EXPECT_EQ(0u, subReader.getInt16List().size()); + EXPECT_EQ(0u, subReader.getInt32List().size()); + EXPECT_EQ(0u, subReader.getInt64List().size()); + EXPECT_EQ(0u, subReader.getUInt8List().size()); + EXPECT_EQ(0u, subReader.getUInt16List().size()); + EXPECT_EQ(0u, subReader.getUInt32List().size()); + EXPECT_EQ(0u, subReader.getUInt64List().size()); + EXPECT_EQ(0u, subReader.getFloat32List().size()); + EXPECT_EQ(0u, subReader.getFloat64List().size()); + EXPECT_EQ(0u, subReader.getTextList().size()); + EXPECT_EQ(0u, subReader.getDataList().size()); + EXPECT_EQ(0u, subReader.getStructList().size()); + } + + EXPECT_EQ(0u, reader.getVoidList().size()); + EXPECT_EQ(0u, reader.getBoolList().size()); + EXPECT_EQ(0u, reader.getInt8List().size()); + EXPECT_EQ(0u, reader.getInt16List().size()); + EXPECT_EQ(0u, reader.getInt32List().size()); + EXPECT_EQ(0u, reader.getInt64List().size()); + EXPECT_EQ(0u, reader.getUInt8List().size()); + EXPECT_EQ(0u, reader.getUInt16List().size()); + EXPECT_EQ(0u, reader.getUInt32List().size()); + EXPECT_EQ(0u, reader.getUInt64List().size()); + EXPECT_EQ(0u, reader.getFloat32List().size()); + EXPECT_EQ(0u, reader.getFloat64List().size()); + EXPECT_EQ(0u, reader.getTextList().size()); + EXPECT_EQ(0u, reader.getDataList().size()); + EXPECT_EQ(0u, reader.getStructList().size()); +} + +#if !CAPNP_LITE + +// Hack because as<>() is a template-parameter-dependent lookup everywhere below... +#define as template as + +template +void dynamicCheckTestMessageAllZero(Reader reader) { + EXPECT_EQ(VOID, reader.get("voidField").as()); + EXPECT_EQ(false, reader.get("boolField").as()); + EXPECT_EQ(0, reader.get("int8Field").as()); + EXPECT_EQ(0, reader.get("int16Field").as()); + EXPECT_EQ(0, reader.get("int32Field").as()); + EXPECT_EQ(0, reader.get("int64Field").as()); + EXPECT_EQ(0u, reader.get("uInt8Field").as()); + EXPECT_EQ(0u, reader.get("uInt16Field").as()); + EXPECT_EQ(0u, reader.get("uInt32Field").as()); + EXPECT_EQ(0u, reader.get("uInt64Field").as()); + EXPECT_FLOAT_EQ(0, reader.get("float32Field").as()); + EXPECT_DOUBLE_EQ(0, reader.get("float64Field").as()); + EXPECT_EQ("", reader.get("textField").as()); + EXPECT_EQ(data(""), reader.get("dataField").as()); + { + auto subReader = reader.get("structField").as(); + EXPECT_EQ(VOID, subReader.get("voidField").as()); + EXPECT_EQ(false, subReader.get("boolField").as()); + EXPECT_EQ(0, subReader.get("int8Field").as()); + EXPECT_EQ(0, subReader.get("int16Field").as()); + EXPECT_EQ(0, subReader.get("int32Field").as()); + EXPECT_EQ(0, subReader.get("int64Field").as()); + EXPECT_EQ(0u, subReader.get("uInt8Field").as()); + EXPECT_EQ(0u, subReader.get("uInt16Field").as()); + EXPECT_EQ(0u, subReader.get("uInt32Field").as()); + EXPECT_EQ(0u, subReader.get("uInt64Field").as()); + EXPECT_FLOAT_EQ(0, subReader.get("float32Field").as()); + EXPECT_DOUBLE_EQ(0, subReader.get("float64Field").as()); + EXPECT_EQ("", subReader.get("textField").as()); + EXPECT_EQ(data(""), subReader.get("dataField").as()); + { + auto subSubReader = subReader.get("structField").as(); + EXPECT_EQ("", subSubReader.get("textField").as()); + EXPECT_EQ("", subSubReader.get("structField").as() + .get("textField").as()); + } + + EXPECT_EQ(0u, subReader.get("voidList").as().size()); + EXPECT_EQ(0u, subReader.get("boolList").as().size()); + EXPECT_EQ(0u, subReader.get("int8List").as().size()); + EXPECT_EQ(0u, subReader.get("int16List").as().size()); + EXPECT_EQ(0u, subReader.get("int32List").as().size()); + EXPECT_EQ(0u, subReader.get("int64List").as().size()); + EXPECT_EQ(0u, subReader.get("uInt8List").as().size()); + EXPECT_EQ(0u, subReader.get("uInt16List").as().size()); + EXPECT_EQ(0u, subReader.get("uInt32List").as().size()); + EXPECT_EQ(0u, subReader.get("uInt64List").as().size()); + EXPECT_EQ(0u, subReader.get("float32List").as().size()); + EXPECT_EQ(0u, subReader.get("float64List").as().size()); + EXPECT_EQ(0u, subReader.get("textList").as().size()); + EXPECT_EQ(0u, subReader.get("dataList").as().size()); + EXPECT_EQ(0u, subReader.get("structList").as().size()); + } + + EXPECT_EQ(0u, reader.get("voidList").as().size()); + EXPECT_EQ(0u, reader.get("boolList").as().size()); + EXPECT_EQ(0u, reader.get("int8List").as().size()); + EXPECT_EQ(0u, reader.get("int16List").as().size()); + EXPECT_EQ(0u, reader.get("int32List").as().size()); + EXPECT_EQ(0u, reader.get("int64List").as().size()); + EXPECT_EQ(0u, reader.get("uInt8List").as().size()); + EXPECT_EQ(0u, reader.get("uInt16List").as().size()); + EXPECT_EQ(0u, reader.get("uInt32List").as().size()); + EXPECT_EQ(0u, reader.get("uInt64List").as().size()); + EXPECT_EQ(0u, reader.get("float32List").as().size()); + EXPECT_EQ(0u, reader.get("float64List").as().size()); + EXPECT_EQ(0u, reader.get("textList").as().size()); + EXPECT_EQ(0u, reader.get("dataList").as().size()); + EXPECT_EQ(0u, reader.get("structList").as().size()); +} + +#undef as + +#endif // !CAPNP_LITE + +template +void genericInitListDefaults(Builder builder) { + auto lists = builder.initLists(); + + lists.initList0(2); + lists.initList1(4); + lists.initList8(2); + lists.initList16(2); + lists.initList32(2); + lists.initList64(2); + lists.initListP(2); + + lists.getList0()[0].setF(VOID); + lists.getList0()[1].setF(VOID); + lists.getList1()[0].setF(true); + lists.getList1()[1].setF(false); + lists.getList1()[2].setF(true); + lists.getList1()[3].setF(true); + lists.getList8()[0].setF(123u); + lists.getList8()[1].setF(45u); + lists.getList16()[0].setF(12345u); + lists.getList16()[1].setF(6789u); + lists.getList32()[0].setF(123456789u); + lists.getList32()[1].setF(234567890u); + lists.getList64()[0].setF(1234567890123456u); + lists.getList64()[1].setF(2345678901234567u); + lists.getListP()[0].setF("foo"); + lists.getListP()[1].setF("bar"); + + { + auto l = lists.initInt32ListList(3); + l.set(0, {1, 2, 3}); + l.set(1, {4, 5}); + l.set(2, {12341234}); + } + + { + auto l = lists.initTextListList(3); + l.set(0, {"foo", "bar"}); + l.set(1, {"baz"}); + l.set(2, {"qux", "corge"}); + } + + { + auto l = lists.initStructListList(2); + auto e = l.init(0, 2); + e[0].setInt32Field(123); + e[1].setInt32Field(456); + e = l.init(1, 1); + e[0].setInt32Field(789); + } +} + +#if !CAPNP_LITE + +void dynamicInitListDefaults(DynamicStruct::Builder builder) { + auto lists = builder.init("lists").as(); + + lists.init("list0", 2); + lists.init("list1", 4); + lists.init("list8", 2); + lists.init("list16", 2); + lists.init("list32", 2); + lists.init("list64", 2); + lists.init("listP", 2); + + lists.get("list0").as()[0].as().set("f", VOID); + lists.get("list0").as()[1].as().set("f", VOID); + lists.get("list1").as()[0].as().set("f", true); + lists.get("list1").as()[1].as().set("f", false); + lists.get("list1").as()[2].as().set("f", true); + lists.get("list1").as()[3].as().set("f", true); + lists.get("list8").as()[0].as().set("f", 123u); + lists.get("list8").as()[1].as().set("f", 45u); + lists.get("list16").as()[0].as().set("f", 12345u); + lists.get("list16").as()[1].as().set("f", 6789u); + lists.get("list32").as()[0].as().set("f", 123456789u); + lists.get("list32").as()[1].as().set("f", 234567890u); + lists.get("list64").as()[0].as().set("f", 1234567890123456u); + lists.get("list64").as()[1].as().set("f", 2345678901234567u); + lists.get("listP").as()[0].as().set("f", "foo"); + lists.get("listP").as()[1].as().set("f", "bar"); + + { + auto l = lists.init("int32ListList", 3).as(); + l.init(0, 3).as().copyFrom({1, 2, 3}); + l.init(1, 2).as().copyFrom({4, 5}); + l.init(2, 1).as().copyFrom({12341234}); + } + + { + auto l = lists.init("textListList", 3).as(); + l.init(0, 2).as().copyFrom({"foo", "bar"}); + l.init(1, 1).as().copyFrom({"baz"}); + l.init(2, 2).as().copyFrom({"qux", "corge"}); + } + + { + auto l = lists.init("structListList", 2).as(); + auto e = l.init(0, 2).as(); + e[0].as().setInt32Field(123); + e[1].as().setInt32Field(456); + e = l.init(1, 1).as(); + e[0].as().setInt32Field(789); + } +} + +#endif // !CAPNP_LITE + +template +void genericCheckListDefaults(Reader reader) { + auto lists = reader.getLists(); + + ASSERT_EQ(2u, lists.getList0().size()); + ASSERT_EQ(4u, lists.getList1().size()); + ASSERT_EQ(2u, lists.getList8().size()); + ASSERT_EQ(2u, lists.getList16().size()); + ASSERT_EQ(2u, lists.getList32().size()); + ASSERT_EQ(2u, lists.getList64().size()); + ASSERT_EQ(2u, lists.getListP().size()); + + EXPECT_EQ(VOID, lists.getList0()[0].getF()); + EXPECT_EQ(VOID, lists.getList0()[1].getF()); + EXPECT_TRUE(lists.getList1()[0].getF()); + EXPECT_FALSE(lists.getList1()[1].getF()); + EXPECT_TRUE(lists.getList1()[2].getF()); + EXPECT_TRUE(lists.getList1()[3].getF()); + EXPECT_EQ(123u, lists.getList8()[0].getF()); + EXPECT_EQ(45u, lists.getList8()[1].getF()); + EXPECT_EQ(12345u, lists.getList16()[0].getF()); + EXPECT_EQ(6789u, lists.getList16()[1].getF()); + EXPECT_EQ(123456789u, lists.getList32()[0].getF()); + EXPECT_EQ(234567890u, lists.getList32()[1].getF()); + EXPECT_EQ(1234567890123456u, lists.getList64()[0].getF()); + EXPECT_EQ(2345678901234567u, lists.getList64()[1].getF()); + EXPECT_EQ("foo", lists.getListP()[0].getF()); + EXPECT_EQ("bar", lists.getListP()[1].getF()); + + { + auto l = lists.getInt32ListList(); + ASSERT_EQ(3u, l.size()); + checkList(l[0], {1, 2, 3}); + checkList(l[1], {4, 5}); + checkList(l[2], {12341234}); + } + + { + auto l = lists.getTextListList(); + ASSERT_EQ(3u, l.size()); + checkList(l[0], {"foo", "bar"}); + checkList(l[1], {"baz"}); + checkList(l[2], {"qux", "corge"}); + } + + { + auto l = lists.getStructListList(); + ASSERT_EQ(2u, l.size()); + auto e = l[0]; + ASSERT_EQ(2u, e.size()); + EXPECT_EQ(123, e[0].getInt32Field()); + EXPECT_EQ(456, e[1].getInt32Field()); + e = l[1]; + ASSERT_EQ(1u, e.size()); + EXPECT_EQ(789, e[0].getInt32Field()); + } +} + +#if !CAPNP_LITE + +// Hack because as<>() is a template-parameter-dependent lookup everywhere below... +#define as template as + +template +void dynamicCheckListDefaults(Reader reader) { + auto lists = reader.get("lists").as(); + + ASSERT_EQ(2u, lists.get("list0").as().size()); + ASSERT_EQ(4u, lists.get("list1").as().size()); + ASSERT_EQ(2u, lists.get("list8").as().size()); + ASSERT_EQ(2u, lists.get("list16").as().size()); + ASSERT_EQ(2u, lists.get("list32").as().size()); + ASSERT_EQ(2u, lists.get("list64").as().size()); + ASSERT_EQ(2u, lists.get("listP").as().size()); + + EXPECT_EQ(VOID, lists.get("list0").as()[0].as().get("f").as()); + EXPECT_EQ(VOID, lists.get("list0").as()[1].as().get("f").as()); + EXPECT_TRUE(lists.get("list1").as()[0].as().get("f").as()); + EXPECT_FALSE(lists.get("list1").as()[1].as().get("f").as()); + EXPECT_TRUE(lists.get("list1").as()[2].as().get("f").as()); + EXPECT_TRUE(lists.get("list1").as()[3].as().get("f").as()); + EXPECT_EQ(123u, lists.get("list8").as()[0].as().get("f").as()); + EXPECT_EQ(45u, lists.get("list8").as()[1].as().get("f").as()); + EXPECT_EQ(12345u, lists.get("list16").as()[0].as().get("f").as()); + EXPECT_EQ(6789u, lists.get("list16").as()[1].as().get("f").as()); + EXPECT_EQ(123456789u, lists.get("list32").as()[0].as().get("f").as()); + EXPECT_EQ(234567890u, lists.get("list32").as()[1].as().get("f").as()); + EXPECT_EQ(1234567890123456u, lists.get("list64").as()[0].as().get("f").as()); + EXPECT_EQ(2345678901234567u, lists.get("list64").as()[1].as().get("f").as()); + EXPECT_EQ("foo", lists.get("listP").as()[0].as().get("f").as()); + EXPECT_EQ("bar", lists.get("listP").as()[1].as().get("f").as()); + + { + auto l = lists.get("int32ListList").as(); + ASSERT_EQ(3u, l.size()); + checkList(l[0], {1, 2, 3}); + checkList(l[1], {4, 5}); + checkList(l[2], {12341234}); + } + + { + auto l = lists.get("textListList").as(); + ASSERT_EQ(3u, l.size()); + checkList(l[0], {"foo", "bar"}); + checkList(l[1], {"baz"}); + checkList(l[2], {"qux", "corge"}); + } + + { + auto l = lists.get("structListList").as(); + ASSERT_EQ(2u, l.size()); + auto e = l[0].as(); + ASSERT_EQ(2u, e.size()); + EXPECT_EQ(123, e[0].as().getInt32Field()); + EXPECT_EQ(456, e[1].as().getInt32Field()); + e = l[1].as(); + ASSERT_EQ(1u, e.size()); + EXPECT_EQ(789, e[0].as().getInt32Field()); + } +} + +#undef as + +#endif // !CAPNP_LITE + +} // namespace + +void initTestMessage(TestAllTypes::Builder builder) { genericInitTestMessage(builder); } +void initTestMessage(TestDefaults::Builder builder) { genericInitTestMessage(builder); } +void initTestMessage(TestListDefaults::Builder builder) { genericInitListDefaults(builder); } + +void checkTestMessage(TestAllTypes::Builder builder) { genericCheckTestMessage(builder); } +void checkTestMessage(TestDefaults::Builder builder) { genericCheckTestMessage(builder); } +void checkTestMessage(TestListDefaults::Builder builder) { genericCheckListDefaults(builder); } + +void checkTestMessage(TestAllTypes::Reader reader) { genericCheckTestMessage(reader); } +void checkTestMessage(TestDefaults::Reader reader) { genericCheckTestMessage(reader); } +void checkTestMessage(TestListDefaults::Reader reader) { genericCheckListDefaults(reader); } + +void checkTestMessageAllZero(TestAllTypes::Builder builder) { + genericCheckTestMessageAllZero(builder); +} +void checkTestMessageAllZero(TestAllTypes::Reader reader) { + genericCheckTestMessageAllZero(reader); +} + +#if !CAPNP_LITE + +void initDynamicTestMessage(DynamicStruct::Builder builder) { + dynamicInitTestMessage(builder); +} +void initDynamicTestLists(DynamicStruct::Builder builder) { + dynamicInitListDefaults(builder); +} +void checkDynamicTestMessage(DynamicStruct::Builder builder) { + dynamicCheckTestMessage(builder); +} +void checkDynamicTestLists(DynamicStruct::Builder builder) { + dynamicCheckListDefaults(builder); +} +void checkDynamicTestMessage(DynamicStruct::Reader reader) { + dynamicCheckTestMessage(reader); +} +void checkDynamicTestLists(DynamicStruct::Reader reader) { + dynamicCheckListDefaults(reader); +} +void checkDynamicTestMessageAllZero(DynamicStruct::Builder builder) { + dynamicCheckTestMessageAllZero(builder); +} +void checkDynamicTestMessageAllZero(DynamicStruct::Reader reader) { + dynamicCheckTestMessageAllZero(reader); +} + +#endif // !CAPNP_LITE + +// ======================================================================================= +// Interface implementations. + +#if !CAPNP_LITE + +TestInterfaceImpl::TestInterfaceImpl(int& callCount): callCount(callCount) {} + +kj::Promise TestInterfaceImpl::foo(FooContext context) { + ++callCount; + auto params = context.getParams(); + auto result = context.getResults(); + EXPECT_EQ(123, params.getI()); + EXPECT_TRUE(params.getJ()); + result.setX("foo"); + return kj::READY_NOW; +} + +kj::Promise TestInterfaceImpl::baz(BazContext context) { + ++callCount; + auto params = context.getParams(); + checkTestMessage(params.getS()); + context.releaseParams(); + EXPECT_ANY_THROW(context.getParams()); + + return kj::READY_NOW; +} + +TestExtendsImpl::TestExtendsImpl(int& callCount): callCount(callCount) {} + +kj::Promise TestExtendsImpl::foo(FooContext context) { + ++callCount; + auto params = context.getParams(); + auto result = context.getResults(); + EXPECT_EQ(321, params.getI()); + EXPECT_FALSE(params.getJ()); + result.setX("bar"); + return kj::READY_NOW; +} + +kj::Promise TestExtendsImpl::grault(GraultContext context) { + ++callCount; + context.releaseParams(); + + initTestMessage(context.getResults()); + + return kj::READY_NOW; +} + +TestPipelineImpl::TestPipelineImpl(int& callCount): callCount(callCount) {} + +kj::Promise TestPipelineImpl::getCap(GetCapContext context) { + ++callCount; + + auto params = context.getParams(); + EXPECT_EQ(234, params.getN()); + + auto cap = params.getInCap(); + context.releaseParams(); + + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + + return request.send().then( + [this,KJ_CPCAP(context)](Response&& response) mutable { + EXPECT_EQ("foo", response.getX()); + + auto result = context.getResults(); + result.setS("bar"); + result.initOutBox().setCap(kj::heap(callCount)); + }); +} + +kj::Promise TestPipelineImpl::getAnyCap(GetAnyCapContext context) { + ++callCount; + + auto params = context.getParams(); + EXPECT_EQ(234, params.getN()); + + auto cap = params.getInCap(); + context.releaseParams(); + + auto request = cap.castAs().fooRequest(); + request.setI(123); + request.setJ(true); + + return request.send().then( + [this,KJ_CPCAP(context)](Response&& response) mutable { + EXPECT_EQ("foo", response.getX()); + + auto result = context.getResults(); + result.setS("bar"); + result.initOutBox().setCap(kj::heap(callCount)); + }); +} + +kj::Promise TestCallOrderImpl::getCallSequence(GetCallSequenceContext context) { + auto result = context.getResults(); + result.setN(count++); + return kj::READY_NOW; +} + +TestTailCallerImpl::TestTailCallerImpl(int& callCount): callCount(callCount) {} + +kj::Promise TestTailCallerImpl::foo(FooContext context) { + ++callCount; + + auto params = context.getParams(); + auto tailRequest = params.getCallee().fooRequest(); + tailRequest.setI(params.getI()); + tailRequest.setT("from TestTailCaller"); + return context.tailCall(kj::mv(tailRequest)); +} + +TestTailCalleeImpl::TestTailCalleeImpl(int& callCount): callCount(callCount) {} + +kj::Promise TestTailCalleeImpl::foo(FooContext context) { + ++callCount; + + auto params = context.getParams(); + auto results = context.getResults(); + + results.setI(params.getI()); + results.setT(params.getT()); + results.setC(kj::heap()); + + return kj::READY_NOW; +} + +TestMoreStuffImpl::TestMoreStuffImpl(int& callCount, int& handleCount) + : callCount(callCount), handleCount(handleCount) {} + +kj::Promise TestMoreStuffImpl::getCallSequence(GetCallSequenceContext context) { + auto result = context.getResults(); + result.setN(callCount++); + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::callFoo(CallFooContext context) { + ++callCount; + + auto params = context.getParams(); + auto cap = params.getCap(); + + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + + return request.send().then( + [KJ_CPCAP(context)](Response&& response) mutable { + EXPECT_EQ("foo", response.getX()); + context.getResults().setS("bar"); + }); +} + +kj::Promise TestMoreStuffImpl::callFooWhenResolved(CallFooWhenResolvedContext context) { + ++callCount; + + auto params = context.getParams(); + auto cap = params.getCap(); + + return cap.whenResolved().then([KJ_CPCAP(cap),KJ_CPCAP(context)]() mutable { + auto request = cap.fooRequest(); + request.setI(123); + request.setJ(true); + + return request.send().then( + [KJ_CPCAP(context)](Response&& response) mutable { + EXPECT_EQ("foo", response.getX()); + context.getResults().setS("bar"); + }); + }); +} + +kj::Promise TestMoreStuffImpl::neverReturn(NeverReturnContext context) { + ++callCount; + + // Attach `cap` to the promise to make sure it is released. + auto promise = kj::Promise(kj::NEVER_DONE).attach(context.getParams().getCap()); + + // Also attach `cap` to the result struct to make sure that is released. + context.getResults().setCapCopy(context.getParams().getCap()); + + context.allowCancellation(); + return kj::mv(promise); +} + +kj::Promise TestMoreStuffImpl::hold(HoldContext context) { + ++callCount; + + auto params = context.getParams(); + clientToHold = params.getCap(); + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::callHeld(CallHeldContext context) { + ++callCount; + + auto request = clientToHold.fooRequest(); + request.setI(123); + request.setJ(true); + + return request.send().then( + [KJ_CPCAP(context)](Response&& response) mutable { + EXPECT_EQ("foo", response.getX()); + context.getResults().setS("bar"); + }); +} + +kj::Promise TestMoreStuffImpl::getHeld(GetHeldContext context) { + ++callCount; + auto result = context.getResults(); + result.setCap(clientToHold); + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::echo(EchoContext context) { + ++callCount; + auto params = context.getParams(); + auto result = context.getResults(); + result.setCap(params.getCap()); + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::expectCancel(ExpectCancelContext context) { + auto cap = context.getParams().getCap(); + context.allowCancellation(); + return loop(0, cap, context); +} + +kj::Promise TestMoreStuffImpl::loop(uint depth, test::TestInterface::Client cap, + ExpectCancelContext context) { + if (depth > 100) { + ADD_FAILURE() << "Looped too long, giving up."; + return kj::READY_NOW; + } else { + return kj::evalLater([this,depth,KJ_CPCAP(cap),KJ_CPCAP(context)]() mutable { + return loop(depth + 1, cap, context); + }); + } +} + +class HandleImpl final: public test::TestHandle::Server { +public: + HandleImpl(int& count): count(count) { ++count; } + ~HandleImpl() { --count; } + +private: + int& count; +}; + +kj::Promise TestMoreStuffImpl::getHandle(GetHandleContext context) { + context.getResults().setHandle(kj::heap(handleCount)); + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::getNull(GetNullContext context) { + return kj::READY_NOW; +} + +kj::Promise TestMoreStuffImpl::getEnormousString(GetEnormousStringContext context) { + context.getResults().initStr(100000000); // 100MB + return kj::READY_NOW; +} + +#endif // !CAPNP_LITE + +} // namespace _ (private) +} // namespace capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/test-util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/test-util.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,312 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_TEST_UTIL_H_ +#define CAPNP_TEST_UTIL_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include +#include +#include "blob.h" +#include + +#if !CAPNP_LITE +#include "dynamic.h" +#endif // !CAPNP_LITE + +// TODO(cleanup): Auto-generate stringification functions for union discriminants. +namespace capnproto_test { +namespace capnp { +namespace test { +inline kj::String KJ_STRINGIFY(TestUnion::Union0::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestUnion::Union1::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestUnion::Union2::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestUnion::Union3::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestUnnamedUnion::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestGroups::Groups::Which which) { + return kj::str(static_cast(which)); +} +inline kj::String KJ_STRINGIFY(TestInterleavedGroups::Group1::Which which) { + return kj::str(static_cast(which)); +} +} // namespace test +} // namespace capnp +} // namespace capnproto_test + +namespace capnp { +namespace _ { // private + +inline Data::Reader data(const char* str) { + return Data::Reader(reinterpret_cast(str), strlen(str)); +} + +namespace test = capnproto_test::capnp::test; + +// We don't use "using namespace" to pull these in because then things would still compile +// correctly if they were generated in the global namespace. +using ::capnproto_test::capnp::test::TestAllTypes; +using ::capnproto_test::capnp::test::TestDefaults; +using ::capnproto_test::capnp::test::TestEnum; +using ::capnproto_test::capnp::test::TestUnion; +using ::capnproto_test::capnp::test::TestUnionDefaults; +using ::capnproto_test::capnp::test::TestNestedTypes; +using ::capnproto_test::capnp::test::TestUsing; +using ::capnproto_test::capnp::test::TestListDefaults; + +void initTestMessage(TestAllTypes::Builder builder); +void initTestMessage(TestDefaults::Builder builder); +void initTestMessage(TestListDefaults::Builder builder); + +void checkTestMessage(TestAllTypes::Builder builder); +void checkTestMessage(TestDefaults::Builder builder); +void checkTestMessage(TestListDefaults::Builder builder); + +void checkTestMessage(TestAllTypes::Reader reader); +void checkTestMessage(TestDefaults::Reader reader); +void checkTestMessage(TestListDefaults::Reader reader); + +void checkTestMessageAllZero(TestAllTypes::Builder builder); +void checkTestMessageAllZero(TestAllTypes::Reader reader); + +#if !CAPNP_LITE +void initDynamicTestMessage(DynamicStruct::Builder builder); +void initDynamicTestLists(DynamicStruct::Builder builder); +void checkDynamicTestMessage(DynamicStruct::Builder builder); +void checkDynamicTestLists(DynamicStruct::Builder builder); +void checkDynamicTestMessage(DynamicStruct::Reader reader); +void checkDynamicTestLists(DynamicStruct::Reader reader); +void checkDynamicTestMessageAllZero(DynamicStruct::Builder builder); +void checkDynamicTestMessageAllZero(DynamicStruct::Reader reader); +#endif // !CAPNP_LITE + +template +inline void checkElement(T a, T b) { + EXPECT_EQ(a, b); +} + +template <> +inline void checkElement(float a, float b) { + EXPECT_FLOAT_EQ(a, b); +} + +template <> +inline void checkElement(double a, double b) { + EXPECT_DOUBLE_EQ(a, b); +} + +template +void checkList(T reader, std::initializer_list expected) { + ASSERT_EQ(expected.size(), reader.size()); + for (uint i = 0; i < expected.size(); i++) { + checkElement(expected.begin()[i], reader[i]); + } +} + +template +void checkList(T reader, std::initializer_list expected) { + ASSERT_EQ(expected.size(), reader.size()); + for (uint i = 0; i < expected.size(); i++) { + checkElement(expected.begin()[i], reader[i]); + } +} + +inline void checkList(List::Reader reader, + std::initializer_list expectedData, + std::initializer_list expectedPointers) { + ASSERT_EQ(expectedData.size(), reader.size()); + for (uint i = 0; i < expectedData.size(); i++) { + EXPECT_EQ(expectedData.begin()[i], reader[i].getOld1()); + EXPECT_EQ(expectedPointers.begin()[i], reader[i].getOld2()); + } +} + +// Hack because as<>() is a template-parameter-dependent lookup everywhere below... +#define as template as + +template void expectPrimitiveEq(T a, T b) { EXPECT_EQ(a, b); } +inline void expectPrimitiveEq(float a, float b) { EXPECT_FLOAT_EQ(a, b); } +inline void expectPrimitiveEq(double a, double b) { EXPECT_DOUBLE_EQ(a, b); } +inline void expectPrimitiveEq(Text::Reader a, Text::Builder b) { EXPECT_EQ(a, b); } +inline void expectPrimitiveEq(Data::Reader a, Data::Builder b) { EXPECT_EQ(a, b); } + +#if !CAPNP_LITE +template +void checkList(T reader, std::initializer_list> expected) { + auto list = reader.as(); + ASSERT_EQ(expected.size(), list.size()); + for (uint i = 0; i < expected.size(); i++) { + expectPrimitiveEq(expected.begin()[i], list[i].as()); + } + + auto typed = reader.as>(); + ASSERT_EQ(expected.size(), typed.size()); + for (uint i = 0; i < expected.size(); i++) { + expectPrimitiveEq(expected.begin()[i], typed[i]); + } +} +#endif // !CAPNP_LITE + +#undef as + +// ======================================================================================= +// Interface implementations. + +#if !CAPNP_LITE + +class TestInterfaceImpl final: public test::TestInterface::Server { +public: + TestInterfaceImpl(int& callCount); + + kj::Promise foo(FooContext context) override; + + kj::Promise baz(BazContext context) override; + +private: + int& callCount; +}; + +class TestExtendsImpl final: public test::TestExtends2::Server { +public: + TestExtendsImpl(int& callCount); + + kj::Promise foo(FooContext context) override; + + kj::Promise grault(GraultContext context) override; + +private: + int& callCount; +}; + +class TestPipelineImpl final: public test::TestPipeline::Server { +public: + TestPipelineImpl(int& callCount); + + kj::Promise getCap(GetCapContext context) override; + kj::Promise getAnyCap(GetAnyCapContext context) override; + +private: + int& callCount; +}; + +class TestCallOrderImpl final: public test::TestCallOrder::Server { +public: + kj::Promise getCallSequence(GetCallSequenceContext context) override; + +private: + uint count = 0; +}; + +class TestTailCallerImpl final: public test::TestTailCaller::Server { +public: + TestTailCallerImpl(int& callCount); + + kj::Promise foo(FooContext context) override; + +private: + int& callCount; +}; + +class TestTailCalleeImpl final: public test::TestTailCallee::Server { +public: + TestTailCalleeImpl(int& callCount); + + kj::Promise foo(FooContext context) override; + +private: + int& callCount; +}; + +class TestMoreStuffImpl final: public test::TestMoreStuff::Server { +public: + TestMoreStuffImpl(int& callCount, int& handleCount); + + kj::Promise getCallSequence(GetCallSequenceContext context) override; + + kj::Promise callFoo(CallFooContext context) override; + + kj::Promise callFooWhenResolved(CallFooWhenResolvedContext context) override; + + kj::Promise neverReturn(NeverReturnContext context) override; + + kj::Promise hold(HoldContext context) override; + + kj::Promise callHeld(CallHeldContext context) override; + + kj::Promise getHeld(GetHeldContext context) override; + + kj::Promise echo(EchoContext context) override; + + kj::Promise expectCancel(ExpectCancelContext context) override; + + kj::Promise getHandle(GetHandleContext context) override; + + kj::Promise getNull(GetNullContext context) override; + + kj::Promise getEnormousString(GetEnormousStringContext context) override; + +private: + int& callCount; + int& handleCount; + test::TestInterface::Client clientToHold = nullptr; + + kj::Promise loop(uint depth, test::TestInterface::Client cap, ExpectCancelContext context); +}; + +class TestCapDestructor final: public test::TestInterface::Server { + // Implementation of TestInterface that notifies when it is destroyed. + +public: + TestCapDestructor(kj::Own>&& fulfiller) + : fulfiller(kj::mv(fulfiller)), impl(dummy) {} + + ~TestCapDestructor() { + fulfiller->fulfill(); + } + + kj::Promise foo(FooContext context) { + return impl.foo(context); + } + +private: + kj::Own> fulfiller; + int dummy = 0; + TestInterfaceImpl impl; +}; + +#endif // !CAPNP_LITE + +} // namespace _ (private) +} // namespace capnp + +#endif // TEST_UTIL_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/test.capnp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/test.capnp Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,962 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xd508eebdc2dc42b8; + +using Cxx = import "c++.capnp"; + +# Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified +# names for stuff in the capnproto namespace. +$Cxx.namespace("capnproto_test::capnp::test"); + +enum TestEnum { + foo @0; + bar @1; + baz @2; + qux @3; + quux @4; + corge @5; + grault @6; + garply @7; +} + +struct TestAllTypes { + voidField @0 : Void; + boolField @1 : Bool; + int8Field @2 : Int8; + int16Field @3 : Int16; + int32Field @4 : Int32; + int64Field @5 : Int64; + uInt8Field @6 : UInt8; + uInt16Field @7 : UInt16; + uInt32Field @8 : UInt32; + uInt64Field @9 : UInt64; + float32Field @10 : Float32; + float64Field @11 : Float64; + textField @12 : Text; + dataField @13 : Data; + structField @14 : TestAllTypes; + enumField @15 : TestEnum; + interfaceField @16 : Void; # TODO + + voidList @17 : List(Void); + boolList @18 : List(Bool); + int8List @19 : List(Int8); + int16List @20 : List(Int16); + int32List @21 : List(Int32); + int64List @22 : List(Int64); + uInt8List @23 : List(UInt8); + uInt16List @24 : List(UInt16); + uInt32List @25 : List(UInt32); + uInt64List @26 : List(UInt64); + float32List @27 : List(Float32); + float64List @28 : List(Float64); + textList @29 : List(Text); + dataList @30 : List(Data); + structList @31 : List(TestAllTypes); + enumList @32 : List(TestEnum); + interfaceList @33 : List(Void); # TODO +} + +struct TestDefaults { + voidField @0 : Void = void; + boolField @1 : Bool = true; + int8Field @2 : Int8 = -123; + int16Field @3 : Int16 = -12345; + int32Field @4 : Int32 = -12345678; + int64Field @5 : Int64 = -123456789012345; + uInt8Field @6 : UInt8 = 234; + uInt16Field @7 : UInt16 = 45678; + uInt32Field @8 : UInt32 = 3456789012; + uInt64Field @9 : UInt64 = 12345678901234567890; + float32Field @10 : Float32 = 1234.5; + float64Field @11 : Float64 = -123e45; + textField @12 : Text = "foo"; + dataField @13 : Data = 0x"62 61 72"; # "bar" + structField @14 : TestAllTypes = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + textField = "nested", + structField = (textField = "really nested")), + enumField = baz, + # interfaceField can't have a default + + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -0x80, 0x7f], + int16List = [1234, -5678, -0x8000, 0x7fff], + int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], + int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], + uInt8List = [12, 34, 0, 0xff], + uInt16List = [1234, 5678, 0, 0xffff], + uInt32List = [12345678, 90123456, 0, 0xffffffff], + uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + (textField = "x structlist 1"), + (textField = "x structlist 2"), + (textField = "x structlist 3")], + enumList = [qux, bar, grault] + # interfaceList can't have a default + ); + enumField @15 : TestEnum = corge; + interfaceField @16 : Void; # TODO + + voidList @17 : List(Void) = [void, void, void, void, void, void]; + boolList @18 : List(Bool) = [true, false, false, true]; + int8List @19 : List(Int8) = [111, -111]; + int16List @20 : List(Int16) = [11111, -11111]; + int32List @21 : List(Int32) = [111111111, -111111111]; + int64List @22 : List(Int64) = [1111111111111111111, -1111111111111111111]; + uInt8List @23 : List(UInt8) = [111, 222] ; + uInt16List @24 : List(UInt16) = [33333, 44444]; + uInt32List @25 : List(UInt32) = [3333333333]; + uInt64List @26 : List(UInt64) = [11111111111111111111]; + float32List @27 : List(Float32) = [5555.5, inf, -inf, nan]; + float64List @28 : List(Float64) = [7777.75, inf, -inf, nan]; + textList @29 : List(Text) = ["plugh", "xyzzy", "thud"]; + dataList @30 : List(Data) = ["oops", "exhausted", "rfc3092"]; + structList @31 : List(TestAllTypes) = [ + (textField = "structlist 1"), + (textField = "structlist 2"), + (textField = "structlist 3")]; + enumList @32 : List(TestEnum) = [foo, garply]; + interfaceList @33 : List(Void); # TODO +} + +struct TestAnyPointer { + anyPointerField @0 :AnyPointer; + + # Do not add any other fields here! Some tests rely on anyPointerField being the last pointer + # in the struct. +} + +struct TestAnyOthers { + anyStructField @0 :AnyStruct; + anyListField @1 :AnyList; + capabilityField @2 :Capability; +} + +struct TestOutOfOrder { + foo @3 :Text; + bar @2 :Text; + baz @8 :Text; + qux @0 :Text; + quux @6 :Text; + corge @4 :Text; + grault @1 :Text; + garply @7 :Text; + waldo @5 :Text; +} + +struct TestUnion { + union0 @0! :union { + # Pack union 0 under ideal conditions: there is no unused padding space prior to it. + u0f0s0 @4: Void; + u0f0s1 @5: Bool; + u0f0s8 @6: Int8; + u0f0s16 @7: Int16; + u0f0s32 @8: Int32; + u0f0s64 @9: Int64; + u0f0sp @10: Text; + + # Pack more stuff into union0 -- should go in same space. + u0f1s0 @11: Void; + u0f1s1 @12: Bool; + u0f1s8 @13: Int8; + u0f1s16 @14: Int16; + u0f1s32 @15: Int32; + u0f1s64 @16: Int64; + u0f1sp @17: Text; + } + + # Pack one bit in order to make pathological situation for union1. + bit0 @18: Bool; + + union1 @1! :union { + # Pack pathologically bad case. Each field takes up new space. + u1f0s0 @19: Void; + u1f0s1 @20: Bool; + u1f1s1 @21: Bool; + u1f0s8 @22: Int8; + u1f1s8 @23: Int8; + u1f0s16 @24: Int16; + u1f1s16 @25: Int16; + u1f0s32 @26: Int32; + u1f1s32 @27: Int32; + u1f0s64 @28: Int64; + u1f1s64 @29: Int64; + u1f0sp @30: Text; + u1f1sp @31: Text; + + # Pack more stuff into union1 -- each should go into the same space as corresponding u1f0s*. + u1f2s0 @32: Void; + u1f2s1 @33: Bool; + u1f2s8 @34: Int8; + u1f2s16 @35: Int16; + u1f2s32 @36: Int32; + u1f2s64 @37: Int64; + u1f2sp @38: Text; + } + + # Fill in the rest of that bitfield from earlier. + bit2 @39: Bool; + bit3 @40: Bool; + bit4 @41: Bool; + bit5 @42: Bool; + bit6 @43: Bool; + bit7 @44: Bool; + + # Interleave two unions to be really annoying. + # Also declare in reverse order to make sure union discriminant values are sorted by field number + # and not by declaration order. + union2 @2! :union { + u2f0s64 @54: Int64; + u2f0s32 @52: Int32; + u2f0s16 @50: Int16; + u2f0s8 @47: Int8; + u2f0s1 @45: Bool; + } + + union3 @3! :union { + u3f0s64 @55: Int64; + u3f0s32 @53: Int32; + u3f0s16 @51: Int16; + u3f0s8 @48: Int8; + u3f0s1 @46: Bool; + } + + byte0 @49: UInt8; +} + +struct TestUnnamedUnion { + before @0 :Text; + + union { + foo @1 :UInt16; + bar @3 :UInt32; + } + + middle @2 :UInt16; + + after @4 :Text; +} + +struct TestUnionInUnion { + # There is no reason to ever do this. + outer :union { + inner :union { + foo @0 :Int32; + bar @1 :Int32; + } + baz @2 :Int32; + } +} + +struct TestGroups { + groups :union { + foo :group { + corge @0 :Int32; + grault @2 :Int64; + garply @8 :Text; + } + bar :group { + corge @3 :Int32; + grault @4 :Text; + garply @5 :Int64; + } + baz :group { + corge @1 :Int32; + grault @6 :Text; + garply @7 :Text; + } + } +} + +struct TestInterleavedGroups { + group1 :group { + foo @0 :UInt32; + bar @2 :UInt64; + union { + qux @4 :UInt16; + corge :group { + grault @6 :UInt64; + garply @8 :UInt16; + plugh @14 :Text; + xyzzy @16 :Text; + } + + fred @12 :Text; + } + + waldo @10 :Text; + } + + group2 :group { + foo @1 :UInt32; + bar @3 :UInt64; + union { + qux @5 :UInt16; + corge :group { + grault @7 :UInt64; + garply @9 :UInt16; + plugh @15 :Text; + xyzzy @17 :Text; + } + + fred @13 :Text; + } + + waldo @11 :Text; + } +} + +struct TestUnionDefaults { + s16s8s64s8Set @0 :TestUnion = + (union0 = (u0f0s16 = 321), union1 = (u1f0s8 = 123), union2 = (u2f0s64 = 12345678901234567), + union3 = (u3f0s8 = 55)); + s0sps1s32Set @1 :TestUnion = + (union0 = (u0f1s0 = void), union1 = (u1f0sp = "foo"), union2 = (u2f0s1 = true), + union3 = (u3f0s32 = 12345678)); + + unnamed1 @2 :TestUnnamedUnion = (foo = 123); + unnamed2 @3 :TestUnnamedUnion = (bar = 321, before = "foo", after = "bar"); +} + +struct TestNestedTypes { + enum NestedEnum { + foo @0; + bar @1; + } + + struct NestedStruct { + enum NestedEnum { + baz @0; + qux @1; + quux @2; + } + + outerNestedEnum @0 :TestNestedTypes.NestedEnum = bar; + innerNestedEnum @1 :NestedEnum = quux; + } + + nestedStruct @0 :NestedStruct; + + outerNestedEnum @1 :NestedEnum = bar; + innerNestedEnum @2 :NestedStruct.NestedEnum = quux; +} + +struct TestUsing { + using OuterNestedEnum = TestNestedTypes.NestedEnum; + using TestNestedTypes.NestedStruct.NestedEnum; + + outerNestedEnum @1 :OuterNestedEnum = bar; + innerNestedEnum @0 :NestedEnum = quux; +} + +struct TestLists { + # Small structs, when encoded as list, will be encoded as primitive lists rather than struct + # lists, to save space. + struct Struct0 { f @0 :Void; } + struct Struct1 { f @0 :Bool; } + struct Struct8 { f @0 :UInt8; } + struct Struct16 { f @0 :UInt16; } + struct Struct32 { f @0 :UInt32; } + struct Struct64 { f @0 :UInt64; } + struct StructP { f @0 :Text; } + + # Versions of the above which cannot be encoded as primitive lists. + struct Struct0c { f @0 :Void; pad @1 :Text; } + struct Struct1c { f @0 :Bool; pad @1 :Text; } + struct Struct8c { f @0 :UInt8; pad @1 :Text; } + struct Struct16c { f @0 :UInt16; pad @1 :Text; } + struct Struct32c { f @0 :UInt32; pad @1 :Text; } + struct Struct64c { f @0 :UInt64; pad @1 :Text; } + struct StructPc { f @0 :Text; pad @1 :UInt64; } + + list0 @0 :List(Struct0); + list1 @1 :List(Struct1); + list8 @2 :List(Struct8); + list16 @3 :List(Struct16); + list32 @4 :List(Struct32); + list64 @5 :List(Struct64); + listP @6 :List(StructP); + + int32ListList @7 :List(List(Int32)); + textListList @8 :List(List(Text)); + structListList @9 :List(List(TestAllTypes)); +} + +struct TestFieldZeroIsBit { + bit @0 :Bool; + secondBit @1 :Bool = true; + thirdField @2 :UInt8 = 123; +} + +struct TestListDefaults { + lists @0 :TestLists = ( + list0 = [(f = void), (f = void)], + list1 = [(f = true), (f = false), (f = true), (f = true)], + list8 = [(f = 123), (f = 45)], + list16 = [(f = 12345), (f = 6789)], + list32 = [(f = 123456789), (f = 234567890)], + list64 = [(f = 1234567890123456), (f = 2345678901234567)], + listP = [(f = "foo"), (f = "bar")], + int32ListList = [[1, 2, 3], [4, 5], [12341234]], + textListList = [["foo", "bar"], ["baz"], ["qux", "corge"]], + structListList = [[(int32Field = 123), (int32Field = 456)], [(int32Field = 789)]]); +} + +struct TestLateUnion { + # Test what happens if the unions are not the first ordinals in the struct. At one point this + # was broken for the dynamic API. + + foo @0 :Int32; + bar @1 :Text; + baz @2 :Int16; + + theUnion @3! :union { + qux @4 :Text; + corge @5 :List(Int32); + grault @6 :Float32; + } + + anotherUnion @7! :union { + qux @8 :Text; + corge @9 :List(Int32); + grault @10 :Float32; + } +} + +struct TestOldVersion { + # A subset of TestNewVersion. + old1 @0 :Int64; + old2 @1 :Text; + old3 @2 :TestOldVersion; +} + +struct TestNewVersion { + # A superset of TestOldVersion. + old1 @0 :Int64; + old2 @1 :Text; + old3 @2 :TestNewVersion; + new1 @3 :Int64 = 987; + new2 @4 :Text = "baz"; +} + +struct TestOldUnionVersion { + union { + a @0 :Void; + b @1 :UInt64; + } +} + +struct TestNewUnionVersion { + union { + a :union { + a0 @0 :Void; + a1 @2 :UInt64; + } + b @1 :UInt64; + } +} + +struct TestStructUnion { + un @0! :union { + struct @1 :SomeStruct; + object @2 :TestAnyPointer; + } + + struct SomeStruct { + someText @0 :Text; + moreText @1 :Text; + } +} + +struct TestPrintInlineStructs { + someText @0 :Text; + + structList @1 :List(InlineStruct); + struct InlineStruct { + int32Field @0 :Int32; + textField @1 :Text; + } +} + +struct TestWholeFloatDefault { + # At one point, these failed to compile in C++ because it would produce literals like "123f", + # which is not valid; it needs to be "123.0f". + field @0 :Float32 = 123; + bigField @1 :Float32 = 2e30; + const constant :Float32 = 456; + const bigConstant :Float32 = 4e30; +} + +struct TestGenerics(Foo, Bar) { + foo @0 :Foo; + rev @1 :TestGenerics(Bar, Foo); + + union { + uv @2:Void; + ug :group { + ugfoo @3:Int32; + } + } + + struct Inner { + foo @0 :Foo; + bar @1 :Bar; + } + + struct Inner2(Baz) { + bar @0 :Bar; + baz @1 :Baz; + innerBound @2 :Inner; + innerUnbound @3 :TestGenerics.Inner; + + struct DeepNest(Qux) { + foo @0 :Foo; + bar @1 :Bar; + baz @2 :Baz; + qux @3 :Qux; + + interface DeepNestInterface(Quux) { + # At one time this failed to compile. + call @0 () -> (); + } + } + } + + interface Interface(Qux) { + call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestAnyPointer)); + } + + annotation ann(struct) :Foo; + + using AliasFoo = Foo; + using AliasInner = Inner; + using AliasInner2 = Inner2; + using AliasInner2Text = Inner2(Text); + using AliasRev = TestGenerics(Bar, Foo); + + struct UseAliases { + foo @0 :AliasFoo; + inner @1 :AliasInner; + inner2 @2 :AliasInner2; + inner2Bind @3 :AliasInner2(Text); + inner2Text @4 :AliasInner2Text; + revFoo @5 :AliasRev.AliasFoo; + } +} + +struct TestGenericsWrapper(Foo, Bar) { + value @0 :TestGenerics(Foo, Bar); +} + +struct TestGenericsWrapper2 { + value @0 :TestGenericsWrapper(Text, TestAllTypes); +} + +interface TestImplicitMethodParams { + call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); +} + +interface TestImplicitMethodParamsInGeneric(V) { + call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); +} + +struct TestGenericsUnion(Foo, Bar) { + # At one point this failed to compile. + + union { + foo @0 :Foo; + bar @1 :Bar; + } +} + +struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { + basic @0 :TestGenerics(TestAllTypes, TestAnyPointer); + inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner; + inner2 @2 :TestGenerics(TestAllTypes, TestAnyPointer).Inner2(Text); + unspecified @3 :TestGenerics; + unspecifiedInner @4 :TestGenerics.Inner2(Text); + wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer); + cap @18 :TestGenerics(TestInterface, Text); + genericCap @19 :TestGenerics(TestAllTypes, List(UInt32)).Interface(Data); + + default @5 :TestGenerics(TestAllTypes, Text) = + (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); + defaultInner @6 :TestGenerics(TestAllTypes, Text).Inner = + (foo = (int16Field = 123), bar = "text"); + defaultUser @7 :TestUseGenerics = (basic = (foo = (int16Field = 123))); + defaultWrapper @9 :TestGenericsWrapper(Text, TestAllTypes) = + (value = (foo = "text", rev = (foo = (int16Field = 321)))); + defaultWrapper2 @10 :TestGenericsWrapper2 = + (value = (value = (foo = "text", rev = (foo = (int16Field = 321))))); + + aliasFoo @11 :TestGenerics(TestAllTypes, TestAnyPointer).AliasFoo = (int16Field = 123); + aliasInner @12 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner + = (foo = (int16Field = 123)); + aliasInner2 @13 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2 + = (innerBound = (foo = (int16Field = 123))); + aliasInner2Bind @14 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2(List(UInt32)) + = (baz = [12, 34], innerBound = (foo = (int16Field = 123))); + aliasInner2Text @15 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2Text + = (baz = "text", innerBound = (foo = (int16Field = 123))); + aliasRev @16 :TestGenerics(TestAnyPointer, Text).AliasRev.AliasFoo = "text"; + + useAliases @17 :TestGenerics(TestAllTypes, List(UInt32)).UseAliases = ( + foo = (int16Field = 123), + inner = (foo = (int16Field = 123)), + inner2 = (innerBound = (foo = (int16Field = 123))), + inner2Bind = (baz = "text", innerBound = (foo = (int16Field = 123))), + inner2Text = (baz = "text", innerBound = (foo = (int16Field = 123))), + revFoo = [12, 34, 56]); +} + +struct TestEmptyStruct {} + +struct TestConstants { + const voidConst :Void = void; + const boolConst :Bool = true; + const int8Const :Int8 = -123; + const int16Const :Int16 = -12345; + const int32Const :Int32 = -12345678; + const int64Const :Int64 = -123456789012345; + const uint8Const :UInt8 = 234; + const uint16Const :UInt16 = 45678; + const uint32Const :UInt32 = 3456789012; + const uint64Const :UInt64 = 12345678901234567890; + const float32Const :Float32 = 1234.5; + const float64Const :Float64 = -123e45; + const textConst :Text = "foo"; + const dataConst :Data = "bar"; + const structConst :TestAllTypes = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + textField = "nested", + structField = (textField = "really nested")), + enumField = baz, + # interfaceField can't have a default + + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -0x80, 0x7f], + int16List = [1234, -5678, -0x8000, 0x7fff], + int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], + int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], + uInt8List = [12, 34, 0, 0xff], + uInt16List = [1234, 5678, 0, 0xffff], + uInt32List = [12345678, 90123456, 0, 0xffffffff], + uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + (textField = "x structlist 1"), + (textField = "x structlist 2"), + (textField = "x structlist 3")], + enumList = [qux, bar, grault] + # interfaceList can't have a default + ); + const enumConst :TestEnum = corge; + + const voidListConst :List(Void) = [void, void, void, void, void, void]; + const boolListConst :List(Bool) = [true, false, false, true]; + const int8ListConst :List(Int8) = [111, -111]; + const int16ListConst :List(Int16) = [11111, -11111]; + const int32ListConst :List(Int32) = [111111111, -111111111]; + const int64ListConst :List(Int64) = [1111111111111111111, -1111111111111111111]; + const uint8ListConst :List(UInt8) = [111, 222] ; + const uint16ListConst :List(UInt16) = [33333, 44444]; + const uint32ListConst :List(UInt32) = [3333333333]; + const uint64ListConst :List(UInt64) = [11111111111111111111]; + const float32ListConst :List(Float32) = [5555.5, inf, -inf, nan]; + const float64ListConst :List(Float64) = [7777.75, inf, -inf, nan]; + const textListConst :List(Text) = ["plugh", "xyzzy", "thud"]; + const dataListConst :List(Data) = ["oops", "exhausted", "rfc3092"]; + const structListConst :List(TestAllTypes) = [ + (textField = "structlist 1"), + (textField = "structlist 2"), + (textField = "structlist 3")]; + const enumListConst :List(TestEnum) = [foo, garply]; +} + +const globalInt :UInt32 = 12345; +const globalText :Text = "foobar"; +const globalStruct :TestAllTypes = (int32Field = 54321); +const globalPrintableStruct :TestPrintInlineStructs = (someText = "foo"); +const derivedConstant :TestAllTypes = ( + uInt32Field = .globalInt, + textField = TestConstants.textConst, + structField = TestConstants.structConst, + int16List = TestConstants.int16ListConst, + structList = TestConstants.structListConst); + +const genericConstant :TestGenerics(TestAllTypes, Text) = + (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); + +const embeddedData :Data = embed "testdata/packed"; +const embeddedText :Text = embed "testdata/short.txt"; +const embeddedStruct :TestAllTypes = embed "testdata/binary"; + +const nonAsciiText :Text = "♫ é ✓"; + +struct TestAnyPointerConstants { + anyKindAsStruct @0 :AnyPointer; + anyStructAsStruct @1 :AnyStruct; + anyKindAsList @2 :AnyPointer; + anyListAsList @3 :AnyList; + +} + +const anyPointerConstants :TestAnyPointerConstants = ( + anyKindAsStruct = TestConstants.structConst, + anyStructAsStruct = TestConstants.structConst, + anyKindAsList = TestConstants.int32ListConst, + anyListAsList = TestConstants.int32ListConst, +); + +interface TestInterface { + foo @0 (i :UInt32, j :Bool) -> (x :Text); + bar @1 () -> (); + baz @2 (s: TestAllTypes); +} + +interface TestExtends extends(TestInterface) { + qux @0 (); + corge @1 TestAllTypes -> (); + grault @2 () -> TestAllTypes; +} + +interface TestExtends2 extends(TestExtends) {} + +interface TestPipeline { + getCap @0 (n: UInt32, inCap :TestInterface) -> (s: Text, outBox :Box); + testPointers @1 (cap :TestInterface, obj :AnyPointer, list :List(TestInterface)) -> (); + getAnyCap @2 (n: UInt32, inCap :Capability) -> (s: Text, outBox :AnyBox); + + struct Box { + cap @0 :TestInterface; + } + struct AnyBox { + cap @0 :Capability; + } +} + +interface TestCallOrder { + getCallSequence @0 (expected: UInt32) -> (n: UInt32); + # First call returns 0, next returns 1, ... + # + # The input `expected` is ignored but useful for disambiguating debug logs. +} + +interface TestTailCallee { + struct TailResult { + i @0 :UInt32; + t @1 :Text; + c @2 :TestCallOrder; + } + + foo @0 (i :Int32, t :Text) -> TailResult; +} + +interface TestTailCaller { + foo @0 (i :Int32, callee :TestTailCallee) -> TestTailCallee.TailResult; +} + +interface TestHandle {} + +interface TestMoreStuff extends(TestCallOrder) { + # Catch-all type that contains lots of testing methods. + + callFoo @0 (cap :TestInterface) -> (s: Text); + # Call `cap.foo()`, check the result, and return "bar". + + callFooWhenResolved @1 (cap :TestInterface) -> (s: Text); + # Like callFoo but waits for `cap` to resolve first. + + neverReturn @2 (cap :TestInterface) -> (capCopy :TestInterface); + # Doesn't return. You should cancel it. + + hold @3 (cap :TestInterface) -> (); + # Returns immediately but holds on to the capability. + + callHeld @4 () -> (s: Text); + # Calls the capability previously held using `hold` (and keeps holding it). + + getHeld @5 () -> (cap :TestInterface); + # Returns the capability previously held using `hold` (and keeps holding it). + + echo @6 (cap :TestCallOrder) -> (cap :TestCallOrder); + # Just returns the input cap. + + expectCancel @7 (cap :TestInterface) -> (); + # evalLater()-loops forever, holding `cap`. Must be canceled. + + methodWithDefaults @8 (a :Text, b :UInt32 = 123, c :Text = "foo") -> (d :Text, e :Text = "bar"); + + methodWithNullDefault @12 (a :Text, b :TestInterface = null); + + getHandle @9 () -> (handle :TestHandle); + # Get a new handle. Tests have an out-of-band way to check the current number of live handles, so + # this can be used to test garbage collection. + + getNull @10 () -> (nullCap :TestMoreStuff); + # Always returns a null capability. + + getEnormousString @11 () -> (str :Text); + # Attempts to return an 100MB string. Should always fail. +} + +interface TestMembrane { + makeThing @0 () -> (thing :Thing); + callPassThrough @1 (thing :Thing, tailCall :Bool) -> Result; + callIntercept @2 (thing :Thing, tailCall :Bool) -> Result; + loopback @3 (thing :Thing) -> (thing :Thing); + + interface Thing { + passThrough @0 () -> Result; + intercept @1 () -> Result; + } + + struct Result { + text @0 :Text; + } +} + +struct TestContainMembrane { + cap @0 :TestMembrane.Thing; + list @1 :List(TestMembrane.Thing); +} + +struct TestTransferCap { + list @0 :List(Element); + struct Element { + text @0 :Text; + cap @1 :TestInterface; + } +} + +interface TestKeywordMethods { + delete @0 (); + class @1 (); + void @2 (); + return @3 (); +} + +interface TestAuthenticatedBootstrap(VatId) { + getCallerId @0 () -> (caller :VatId); +} + +struct TestSturdyRef { + hostId @0 :TestSturdyRefHostId; + objectId @1 :AnyPointer; +} + +struct TestSturdyRefHostId { + host @0 :Text; +} + +struct TestSturdyRefObjectId { + tag @0 :Tag; + enum Tag { + testInterface @0; + testExtends @1; + testPipeline @2; + testTailCallee @3; + testTailCaller @4; + testMoreStuff @5; + } +} + +struct TestProvisionId {} +struct TestRecipientId {} +struct TestThirdPartyCapId {} +struct TestJoinResult {} + +struct TestNameAnnotation $Cxx.name("RenamedStruct") { + union { + badFieldName @0 :Bool $Cxx.name("goodFieldName"); + bar @1 :Int8; + } + + enum BadlyNamedEnum $Cxx.name("RenamedEnum") { + foo @0; + bar @1; + baz @2 $Cxx.name("qux"); + } + + anotherBadFieldName @2 :BadlyNamedEnum $Cxx.name("anotherGoodFieldName"); + + struct NestedStruct $Cxx.name("RenamedNestedStruct") { + badNestedFieldName @0 :Bool $Cxx.name("goodNestedFieldName"); + anotherBadNestedFieldName @1 :NestedStruct $Cxx.name("anotherGoodNestedFieldName"); + + enum DeeplyNestedEnum $Cxx.name("RenamedDeeplyNestedEnum") { + quux @0; + corge @1; + grault @2 $Cxx.name("garply"); + } + } + + badlyNamedUnion :union $Cxx.name("renamedUnion") { + badlyNamedGroup :group $Cxx.name("renamedGroup") { + foo @3 :Void; + bar @4 :Void; + } + baz @5 :NestedStruct $Cxx.name("qux"); + } +} + +interface TestNameAnnotationInterface $Cxx.name("RenamedInterface") { + badlyNamedMethod @0 (badlyNamedParam :UInt8 $Cxx.name("renamedParam")) $Cxx.name("renamedMethod"); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/binary Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/binary has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/errors.capnp.nobuild --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/testdata/errors.capnp.nobuild Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,161 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This file is intended to test that various error cases are detected as errors. The error +# output is matched against a golden file. The file name has the .nobuild extension to make +# sure that a build system which automatically builds .capnp files does not try to build this one. + +# + +@0xccd0890aa4926a9b; +# Can't really test the missing-ID error because the output is intentionally unpredictable. + +const notType :Int32 = 123; +annotation notFieldAnnotation(struct) :Int32; +annotation fieldAnnotation(field) :Int32; + +struct Foo { + dupName @0 :Int32; + dupName @1 :Int32; + dupNumber1 @2 :Int32; + dupNumber2 @2 :Int32; + + missingNumber @4 :Int32; + next @5 :Int32; + + emptyUnion :union {} + emptyGroup :group {} + + singletonUnion :union { + field @6 :Int32; + } + + union { + dupName @7 :Int32; + f8 @8 :Int32; + } + union { + f9 @9 :Int32; + f10 @10 :Int32; + } + + struct wrongTypeStyle {} + WrongFieldStyle @11 :Int32; + under_score @12 :Int32; + + containsStruct :group { + f13 @13 :Int32; + struct CantNestHere {} + } + + retroUnion @16! :union { + f14 @14 :Int32; + f15 @15 :Int32; + } + + missingColonAndEclamation @18 union { + f19 @19 :Int32; + f20 @20 :Int32; + } + + missingExclamation @21 :union { + f22 @22 :Int32; + f23 @23 :Int32; + } + + missingColon @24! union { + f19 @25 :Int32; + f20 @26 :Int32; + } + + unnamedInNamed :union { + f27 @27 :Int32; + f28 @28 :Int32; + union { + # content is ignored + } + } + + listWithoutParam @31 :List; + listWithTooManyParams @32 :List(Int32, Int64); + listAnyPointer @33 :List(AnyPointer); + notAType @34 :notType; + noParams @35 :Foo(Int32); + + defaultOutOfRange @36 :Int16 = 1234567; + defaultOutOfRange2 @37 :UInt16 = -1; + defaultWrongType @38 :Text = 123; + defaultWrongType2 @39 :Text = [123]; + defaultWrongType3 @40 :Text = (foo = 123, bar = 456); + defaultTooBigToBeNegative @41 :Int64 = -0x8000000000000001; + defaultNotConstant @42 :Int32 = .Foo; + defaultConstantNotQualified @43 :Int32 = notType; + + notAnnotation @44 :Int32 $Foo(123); + badAnnotation @45 :Int32 $notFieldAnnotation(123); + notVoidAnnotation @46 :Int32 $fieldAnnotation; + + undefinedImport @17 :import "noshuchfile.capnp".Bar; + undefinedAbsolute @47 : .NoSuch; + undefinedRelative @29 :NoSuch; + undefinedMember @30 :Foo.NoSuch; +} + +struct Bar { + x @3 :Text; + someGroup :group { + defaultMissingFieldName @2 :Bar = (x = "abcd", 456); + defaultNoSuchField @0 :Bar = (nosuchfield = 123); + defaultGroupMismatch @1 :Bar = (someGroup = 123); + } +} + + +using Bar; + +enum DupEnumerants { + dupName @0; + dupName @1; + dupNumber1 @2; + dupNumber2 @2; +} + +const recursive: UInt32 = .recursive; + +struct Generic(T, U) { +} + +struct UseGeneric { + tooFew @0 :Generic(Text); + tooMany @1 :Generic(Text, Data, List(Int32)); + doubleBind @2 :Generic(Text, Data)(Data, Text); + primitiveBinding @3 :Generic(Text, Int32); +} + +const embedBadType :UInt32 = embed "binary"; +const embedNoSuchFile :Data = embed "no-such-file"; + +using Baz = import "nosuchfile-unused.capnp".Baz; +# Check that an import in an unused `using` still reports error. + +interface TestInterface { + foo @0 (a :UInt32 = null); +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/errors.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/testdata/errors.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,60 @@ +file:74:30-32: error: As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to unions. However, removing the number will break binary compatibility. If this is an old protocol and you need to retain compatibility, please add an exclamation point after the number to indicate that it is really needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility doesn't matter, just remove the @n entirely. Sorry for the inconvenience, and thanks for being an early adopter! :) +file:74:30-32: error: As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon for named unions, e.g. `foo :union {`. +file:79:23-25: error: As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to unions. However, removing the number will break binary compatibility. If this is an old protocol and you need to retain compatibility, please add an exclamation point after the number to indicate that it is really needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility doesn't matter, just remove the @n entirely. Sorry for the inconvenience, and thanks for being an early adopter! :) +file:84:17-19: error: As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon for named unions, e.g. `foo :union {`. +file:132:7-10: error: 'using' declaration without '=' must specify a named declaration from a different scope. +file:37:3-10: error: 'dupName' is already defined in this scope. +file:36:3-10: error: 'dupName' previously defined here. +file:52:5-12: error: 'dupName' is already defined in this scope. +file:36:3-10: error: 'dupName' previously defined here. +file:55:3-8: error: An unnamed union is already defined in this scope. +file:51:3-8: error: Previously defined here. +file:60:10-24: error: Type names must begin with a capital letter. +file:61:3-18: error: Non-type names must begin with a lower-case letter. +file:62:3-14: error: Cap'n Proto declaration names should use camelCase and must not contain underscores. (Code generators may convert names to the appropriate style for the target language.) +file:66:5-27: error: This kind of declaration doesn't belong here. +file:44:3-23: error: Union must have at least two members. +file:45:3-23: error: Group must have at least one member. +file:47: error: Union must have at least two members. +file:92: error: Unions cannot contain unnamed unions. +file:39:15-16: error: Duplicate ordinal number. +file:38:15-16: error: Ordinal @2 originally used here. +file:41:18-19: error: Skipped ordinal @3. Ordinals must be sequential with no holes. +file:69:15-17: error: Union ordinal, if specified, must be greater than no more than one of its member ordinals (i.e. there can only be one field retroactively unionized). +file:116:31-50: error: Import failed: noshuchfile.capnp +file:118:26-32: error: Not defined: NoSuch +file:119:28-34: error: 'Foo' has no member named 'NoSuch' +file:97:25-29: error: 'List' requires exactly one parameter. +file:98:30-48: error: Too many generic parameters. +file:98:30-34: error: 'List' requires exactly one parameter. +file:99:23-39: error: 'List(AnyPointer)' is not supported. +file:100:17-24: error: 'notType' is not a type. +file:101:17-27: error: Declaration does not accept generic parameters. +file:103:34-41: error: Integer value out of range. +file:104:37-38: error: Integer value out of range. +file:105:32-35: error: Type mismatch; expected Text. +file:106:33-38: error: Type mismatch; expected Text. +file:107:33-55: error: Type mismatch; expected Text. +file:108:43-61: error: Integer is too big to be negative. +file:109:35-39: error: '.Foo' does not refer to a constant. +file:110:44-51: error: Constant names must be qualified to avoid confusion. Please replace 'notType' with '.notType', if that's what you intended. +file:117:28-34: error: Not defined: NoSuch +file:112:29-32: error: 'Foo' is not an annotation. +file:113:29-47: error: 'notFieldAnnotation' cannot be applied to this kind of declaration. +file:114:33-48: error: 'fieldAnnotation' requires a value. +file:126:35-46: error: Struct has no field named 'nosuchfield'. +file:127:49-52: error: Type mismatch; expected group. +file:125:52-55: error: Missing field name. +file:136:3-10: error: 'dupName' is already defined in this scope. +file:135:3-10: error: 'dupName' previously defined here. +file:138:15-16: error: Duplicate ordinal number. +file:137:15-16: error: Ordinal @2 originally used here. +file:141:7-16: error: Declaration recursively depends on itself. +file:147:14-27: error: Not enough generic parameters. +file:148:15-47: error: Too many generic parameters. +file:149:18-49: error: Double-application of generic parameters. +file:150:38-43: error: Sorry, only pointer types can be used as generic parameters. +file:153:30-44: error: Embeds can only be used when Text, Data, or a struct is expected. +file:154:37-51: error: Couldn't read file for embed: no-such-file +file:160:23-27: error: Only pointer parameters can declare their default as 'null'. +file:156:20-45: error: Import failed: nosuchfile-unused.capnp diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/flat Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/flat has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/lists.binary Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/lists.binary has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/packed Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/packed has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/packedflat Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/packedflat has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/pretty.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/testdata/pretty.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,187 @@ +( voidField = void, + boolField = true, + int8Field = -123, + int16Field = -12345, + int32Field = -12345678, + int64Field = -123456789012345, + uInt8Field = 234, + uInt16Field = 45678, + uInt32Field = 3456789012, + uInt64Field = 12345678901234567890, + float32Field = 1234.5, + float64Field = -1.23e47, + textField = "foo", + dataField = "bar", + structField = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "nested", + structField = ( + voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "really nested", + enumField = foo, + interfaceField = void ), + enumField = foo, + interfaceField = void ), + enumField = baz, + interfaceField = void, + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -128, 127], + int16List = [1234, -5678, -32768, 32767], + int32List = [12345678, -90123456, -2147483648, 2147483647], + int64List = [123456789012345, -678901234567890, -9223372036854775808, 9223372036854775807], + uInt8List = [12, 34, 0, 255], + uInt16List = [1234, 5678, 0, 65535], + uInt32List = [12345678, 90123456, 0, 4294967295], + uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 1", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 2", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 3", + enumField = foo, + interfaceField = void ) ], + enumList = [qux, bar, grault] ), + enumField = corge, + interfaceField = void, + voidList = [void, void, void, void, void, void], + boolList = [true, false, false, true], + int8List = [111, -111], + int16List = [11111, -11111], + int32List = [111111111, -111111111], + int64List = [1111111111111111111, -1111111111111111111], + uInt8List = [111, 222], + uInt16List = [33333, 44444], + uInt32List = [3333333333], + uInt64List = [11111111111111111111], + float32List = [5555.5, inf, -inf, nan], + float64List = [7777.75, inf, -inf, nan], + textList = ["plugh", "xyzzy", "thud"], + dataList = ["oops", "exhausted", "rfc3092"], + structList = [ + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 1", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 2", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 3", + enumField = foo, + interfaceField = void ) ], + enumList = [foo, garply] ) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/segmented Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/segmented has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/segmented-packed Binary file src/capnproto-0.6.0/c++/src/capnp/testdata/segmented-packed has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/capnp/testdata/short.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/capnp/testdata/short.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1 @@ +(voidField = void, boolField = true, int8Field = -123, int16Field = -12345, int32Field = -12345678, int64Field = -123456789012345, uInt8Field = 234, uInt16Field = 45678, uInt32Field = 3456789012, uInt64Field = 12345678901234567890, float32Field = 1234.5, float64Field = -1.23e47, textField = "foo", dataField = "bar", structField = (voidField = void, boolField = true, int8Field = -12, int16Field = 3456, int32Field = -78901234, int64Field = 56789012345678, uInt8Field = 90, uInt16Field = 1234, uInt32Field = 56789012, uInt64Field = 345678901234567890, float32Field = -1.25e-10, float64Field = 345, textField = "baz", dataField = "qux", structField = (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "nested", structField = (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "really nested", enumField = foo, interfaceField = void), enumField = foo, interfaceField = void), enumField = baz, interfaceField = void, voidList = [void, void, void], boolList = [false, true, false, true, true], int8List = [12, -34, -128, 127], int16List = [1234, -5678, -32768, 32767], int32List = [12345678, -90123456, -2147483648, 2147483647], int64List = [123456789012345, -678901234567890, -9223372036854775808, 9223372036854775807], uInt8List = [12, 34, 0, 255], uInt16List = [1234, 5678, 0, 65535], uInt32List = [12345678, 90123456, 0, 4294967295], uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615], float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], textList = ["quux", "corge", "grault"], dataList = ["garply", "waldo", "fred"], structList = [(voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "x structlist 1", enumField = foo, interfaceField = void), (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "x structlist 2", enumField = foo, interfaceField = void), (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "x structlist 3", enumField = foo, interfaceField = void)], enumList = [qux, bar, grault]), enumField = corge, interfaceField = void, voidList = [void, void, void, void, void, void], boolList = [true, false, false, true], int8List = [111, -111], int16List = [11111, -11111], int32List = [111111111, -111111111], int64List = [1111111111111111111, -1111111111111111111], uInt8List = [111, 222], uInt16List = [33333, 44444], uInt32List = [3333333333], uInt64List = [11111111111111111111], float32List = [5555.5, inf, -inf, nan], float64List = [7777.75, inf, -inf, nan], textList = ["plugh", "xyzzy", "thud"], dataList = ["oops", "exhausted", "rfc3092"], structList = [(voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "structlist 1", enumField = foo, interfaceField = void), (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "structlist 2", enumField = foo, interfaceField = void), (voidField = void, boolField = false, int8Field = 0, int16Field = 0, int32Field = 0, int64Field = 0, uInt8Field = 0, uInt16Field = 0, uInt32Field = 0, uInt64Field = 0, float32Field = 0, float64Field = 0, textField = "structlist 3", enumField = foo, interfaceField = void)], enumList = [foo, garply]) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/CMakeLists.txt Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,187 @@ + +# kj =========================================================================== + +set(kj_sources_lite + array.c++ + common.c++ + debug.c++ + exception.c++ + io.c++ + memory.c++ + mutex.c++ + string.c++ + thread.c++ + main.c++ + arena.c++ + test-helpers.c++ +) +set(kj_sources_heavy + units.c++ + refcount.c++ + string-tree.c++ + parse/char.c++ +) +if(NOT CAPNP_LITE) + set(kj_sources ${kj_sources_lite} ${kj_sources_heavy}) +else() + set(kj_sources ${kj_sources_lite}) +endif() + +set(kj_headers + common.h + units.h + memory.h + refcount.h + array.h + vector.h + string.h + string-tree.h + exception.h + debug.h + arena.h + miniposix.h + io.h + tuple.h + one-of.h + function.h + mutex.h + thread.h + threadlocal.h + main.h + windows-sanity.h +) +set(kj-parse_headers + parse/common.h + parse/char.h +) +set(kj-std_headers + std/iostream.h +) +add_library(kj ${kj_sources}) +add_library(CapnProto::kj ALIAS kj) +target_compile_features(kj PUBLIC cxx_constexpr) +# Requiring the cxx_std_11 metafeature would be preferable, but that doesn't exist until CMake 3.8. + +if(UNIX AND NOT ANDROID) + target_link_libraries(kj PUBLIC pthread) +endif() +#make sure the lite flag propagates to all users (internal + external) of this library +target_compile_definitions(kj PUBLIC ${CAPNP_LITE_FLAG}) +#make sure external consumers don't need to manually set the include dirs +target_include_directories(kj INTERFACE + $ + $ +) +install(TARGETS kj ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES ${kj_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj") +install(FILES ${kj-parse_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj/parse") +install(FILES ${kj-std_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj/std") + +set(kj-test_sources + test.c++ +) +set(kj-test_headers + test.h +) +set(kj-test-compat_headers + compat/gtest.h +) +add_library(kj-test ${kj-test_sources}) +add_library(CapnProto::kj-test ALIAS kj-test) +target_link_libraries(kj-test PUBLIC kj) +install(TARGETS kj-test ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(FILES ${kj-test_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj") +install(FILES ${kj-test-compat_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj/compat") + +set(kj-async_sources + async.c++ + async-unix.c++ + async-win32.c++ + async-io-win32.c++ + async-io.c++ + async-io-unix.c++ + time.c++ +) +set(kj-async_headers + async-prelude.h + async.h + async-inl.h + async-unix.h + async-win32.h + async-io.h + time.h +) +if(NOT CAPNP_LITE) + add_library(kj-async ${kj-async_sources}) + add_library(CapnProto::kj-async ALIAS kj-async) + target_link_libraries(kj-async PUBLIC kj) + if(UNIX) + # external clients of this library need to link to pthreads + target_compile_options(kj-async INTERFACE "-pthread") + elseif(WIN32) + target_link_libraries(kj-async PUBLIC ws2_32) + endif() + install(TARGETS kj-async ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES ${kj-async_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj") +endif() + +# kj-http ====================================================================== + +set(kj-http_sources + compat/http.c++ +) +set(kj-http_headers + compat/http.h +) +if(NOT CAPNP_LITE) + add_library(kj-http ${kj-http_sources}) + add_library(CapnProto::kj-http ALIAS kj-http) + target_link_libraries(kj-http PUBLIC kj-async kj) + install(TARGETS kj-http ${INSTALL_TARGETS_DEFAULT_ARGS}) + install(FILES ${kj-http_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kj/compat") +endif() + +# Tests ======================================================================== + +if(BUILD_TESTING) + add_executable(kj-tests + common-test.c++ + memory-test.c++ + array-test.c++ + string-test.c++ + exception-test.c++ + debug-test.c++ + io-test.c++ + mutex-test.c++ + threadlocal-test.c++ + test-test.c++ + std/iostream-test.c++ + ) + # TODO: Link with librt on Solaris for sched_yield + target_link_libraries(kj-tests kj-test kj) + add_dependencies(check kj-tests) + add_test(NAME kj-tests-run COMMAND kj-tests) + + if(NOT CAPNP_LITE) + add_executable(kj-heavy-tests + async-test.c++ + async-unix-test.c++ + async-win32-test.c++ + async-io-test.c++ + refcount-test.c++ + string-tree-test.c++ + arena-test.c++ + units-test.c++ + tuple-test.c++ + one-of-test.c++ + function-test.c++ + threadlocal-pthread-test.c++ + parse/common-test.c++ + parse/char-test.c++ + compat/http-test.c++ + ) + target_link_libraries(kj-heavy-tests kj-http kj-async kj-test kj) + add_dependencies(check kj-heavy-tests) + add_test(NAME kj-heavy-tests-run COMMAND kj-heavy-tests) + endif() # NOT CAPNP_LITE +endif() # BUILD_TESTING diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/arena-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/arena-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,308 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "arena.h" +#include "debug.h" +#include +#include + +namespace kj { +namespace { + +struct TestObject { + TestObject() { + index = count; + KJ_ASSERT(index != throwAt); + ++count; + } + TestObject(const TestObject& other) { + KJ_ASSERT(other.index != throwAt); + index = -1; + copiedCount++; + } + ~TestObject() noexcept(false) { + if (index == -1) { + --copiedCount; + } else { + --count; + EXPECT_EQ(index, count); + KJ_ASSERT(count != throwAt); + } + } + + int index; + + static int count; + static int copiedCount; + static int throwAt; +}; + +int TestObject::count = 0; +int TestObject::copiedCount = 0; +int TestObject::throwAt = -1; + +TEST(Arena, Object) { + TestObject::count = 0; + TestObject::throwAt = -1; + + { + Arena arena; + + TestObject& obj1 = arena.allocate(); + TestObject& obj2 = arena.allocate(); + + EXPECT_LT(&obj1, &obj2); + + EXPECT_EQ(2, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +TEST(Arena, TrivialObject) { + Arena arena; + + int& i1 = arena.allocate(); + int& i2 = arena.allocate(); + + // Trivial objects should be tightly-packed. + EXPECT_EQ(&i1 + 1, &i2); +} + +TEST(Arena, OwnObject) { + TestObject::count = 0; + TestObject::throwAt = -1; + + Arena arena; + + { + Own obj1 = arena.allocateOwn(); + Own obj2 = arena.allocateOwn(); + EXPECT_LT(obj1.get(), obj2.get()); + + EXPECT_EQ(2, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +TEST(Arena, Array) { + TestObject::count = 0; + TestObject::throwAt = -1; + + { + Arena arena; + ArrayPtr arr1 = arena.allocateArray(4); + ArrayPtr arr2 = arena.allocateArray(2); + EXPECT_EQ(4u, arr1.size()); + EXPECT_EQ(2u, arr2.size()); + EXPECT_LE(arr1.end(), arr2.begin()); + EXPECT_EQ(6, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +TEST(Arena, TrivialArray) { + Arena arena; + ArrayPtr arr1 = arena.allocateArray(16); + ArrayPtr arr2 = arena.allocateArray(8); + + // Trivial arrays should be tightly-packed. + EXPECT_EQ(arr1.end(), arr2.begin()); +} + +TEST(Arena, OwnArray) { + TestObject::count = 0; + TestObject::throwAt = -1; + + Arena arena; + + { + Array arr1 = arena.allocateOwnArray(4); + Array arr2 = arena.allocateOwnArray(2); + EXPECT_EQ(4u, arr1.size()); + EXPECT_EQ(2u, arr2.size()); + EXPECT_LE(arr1.end(), arr2.begin()); + EXPECT_EQ(6, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +#ifndef KJ_NO_EXCEPTIONS + +TEST(Arena, ObjectThrow) { + TestObject::count = 0; + TestObject::throwAt = 1; + + { + Arena arena; + + arena.allocate(); + EXPECT_ANY_THROW(arena.allocate()); + EXPECT_EQ(1, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +TEST(Arena, ArrayThrow) { + TestObject::count = 0; + TestObject::throwAt = 2; + + { + Arena arena; + EXPECT_ANY_THROW(arena.allocateArray(4)); + EXPECT_EQ(2, TestObject::count); + } + + EXPECT_EQ(0, TestObject::count); +} + +#endif + +TEST(Arena, Alignment) { + Arena arena; + + char& c = arena.allocate(); + long& l = arena.allocate(); + char& c2 = arena.allocate(); + ArrayPtr arr = arena.allocateArray(8); + + EXPECT_EQ(alignof(long) + sizeof(long), implicitCast(&c2 - &c)); + EXPECT_EQ(alignof(long), implicitCast(reinterpret_cast(&l) - &c)); + EXPECT_EQ(sizeof(char), implicitCast(arr.begin() - &c2)); +} + +TEST(Arena, EndOfChunk) { + union { + byte scratch[64]; + uint64_t align; + }; + Arena arena(arrayPtr(scratch, sizeof(scratch))); + + // First allocation will come from somewhere in the scratch space (after the chunk header). + uint64_t& i = arena.allocate(); + EXPECT_GE(reinterpret_cast(&i), scratch); + EXPECT_LT(reinterpret_cast(&i), scratch + sizeof(scratch)); + + // Next allocation will come at the next position. + uint64_t& i2 = arena.allocate(); + EXPECT_EQ(&i + 1, &i2); + + // Allocate the rest of the scratch space. + size_t spaceLeft = scratch + sizeof(scratch) - reinterpret_cast(&i2 + 1); + ArrayPtr remaining = arena.allocateArray(spaceLeft); + EXPECT_EQ(reinterpret_cast(&i2 + 1), remaining.begin()); + + // Next allocation comes from somewhere new. + uint64_t& i3 = arena.allocate(); + EXPECT_NE(remaining.end(), reinterpret_cast(&i3)); +} + +TEST(Arena, EndOfChunkAlignment) { + union { + byte scratch[34]; + uint64_t align; + }; + Arena arena(arrayPtr(scratch, sizeof(scratch))); + + // Figure out where we are... + byte* start = arena.allocateArray(0).begin(); + + // Allocate enough space so that we're 24 bytes into the scratch space. (On 64-bit systems, this + // should be zero.) + arena.allocateArray(24 - (start - scratch)); + + // Allocating a 16-bit integer works. Now we're at 26 bytes; 8 bytes are left. + uint16_t& i = arena.allocate(); + EXPECT_EQ(scratch + 24, reinterpret_cast(&i)); + + // Although there is technically enough space to allocate a uint64, it is not aligned correctly, + // so it will be allocated elsewhere instead. + uint64_t& i2 = arena.allocate(); + EXPECT_TRUE(reinterpret_cast(&i2) < scratch || + reinterpret_cast(&i2) > scratch + sizeof(scratch)); +} + +TEST(Arena, TooBig) { + Arena arena(1024); + + byte& b1 = arena.allocate(); + + ArrayPtr arr = arena.allocateArray(1024); + + byte& b2 = arena.allocate(); + + // The array should not have been allocated anywhere near that first byte. + EXPECT_TRUE(arr.begin() < &b1 || arr.begin() > &b1 + 512); + + // The next byte should have been allocated after the array. + EXPECT_EQ(arr.end(), &b2); + + // Write to the array to make sure it's valid. + memset(arr.begin(), 0xbe, arr.size()); +} + +TEST(Arena, MultiSegment) { + // Sorry, this test makes assumptions about the size of ChunkHeader. + Arena arena(sizeof(void*) == 4 ? 32 : 40); + + uint64_t& i1 = arena.allocate(); + uint64_t& i2 = arena.allocate(); + uint64_t& i3 = arena.allocate(); + + EXPECT_EQ(&i1 + 1, &i2); + EXPECT_NE(&i2 + 1, &i3); + + i1 = 1234; + i2 = 5678; + i3 = 9012; +} + +TEST(Arena, Constructor) { + Arena arena; + + EXPECT_EQ(123u, arena.allocate(123)); + EXPECT_EQ("foo", arena.allocate("foo", 3)); +} + +TEST(Arena, Strings) { + Arena arena; + + StringPtr foo = arena.copyString("foo"); + StringPtr bar = arena.copyString("bar"); + StringPtr quux = arena.copyString("quux"); + StringPtr corge = arena.copyString("corge"); + + EXPECT_EQ("foo", foo); + EXPECT_EQ("bar", bar); + EXPECT_EQ("quux", quux); + EXPECT_EQ("corge", corge); + + EXPECT_EQ(foo.end() + 1, bar.begin()); + EXPECT_EQ(bar.end() + 1, quux.begin()); + EXPECT_EQ(quux.end() + 1, corge.begin()); +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/arena.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/arena.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,167 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "arena.h" +#include "debug.h" +#include + +namespace kj { + +Arena::Arena(size_t chunkSizeHint): nextChunkSize(kj::max(sizeof(ChunkHeader), chunkSizeHint)) {} + +Arena::Arena(ArrayPtr scratch) + : nextChunkSize(kj::max(sizeof(ChunkHeader), scratch.size())) { + if (scratch.size() > sizeof(ChunkHeader)) { + ChunkHeader* chunk = reinterpret_cast(scratch.begin()); + chunk->end = scratch.end(); + chunk->pos = reinterpret_cast(chunk + 1); + chunk->next = nullptr; // Never actually observed. + + // Don't place the chunk in the chunk list because it's not ours to delete. Just make it the + // current chunk so that we'll allocate from it until it is empty. + currentChunk = chunk; + } +} + +Arena::~Arena() noexcept(false) { + // Run cleanup() explicitly, but if it throws an exception, make sure to run it again as part of + // unwind. The second call will not throw because destructors are required to guard against + // exceptions when already unwinding. + KJ_ON_SCOPE_FAILURE(cleanup()); + cleanup(); +} + +void Arena::cleanup() { + while (objectList != nullptr) { + void* ptr = objectList + 1; + auto destructor = objectList->destructor; + objectList = objectList->next; + destructor(ptr); + } + + while (chunkList != nullptr) { + void* ptr = chunkList; + chunkList = chunkList->next; + operator delete(ptr); + } +} + +namespace { + +constexpr bool KJ_UNUSED isPowerOfTwo(size_t value) { + return (value & (value - 1)) == 0; +} + +inline byte* alignTo(byte* p, uint alignment) { + // Round the pointer up to the next aligned value. + + KJ_DASSERT(isPowerOfTwo(alignment), alignment); + uintptr_t mask = alignment - 1; + uintptr_t i = reinterpret_cast(p); + return reinterpret_cast((i + mask) & ~mask); +} + +inline size_t alignTo(size_t s, uint alignment) { + // Round the pointer up to the next aligned value. + + KJ_DASSERT(isPowerOfTwo(alignment), alignment); + size_t mask = alignment - 1; + return (s + mask) & ~mask; +} + +} // namespace + +void* Arena::allocateBytes(size_t amount, uint alignment, bool hasDisposer) { + if (hasDisposer) { + alignment = kj::max(alignment, alignof(ObjectHeader)); + amount += alignTo(sizeof(ObjectHeader), alignment); + } + + void* result = allocateBytesInternal(amount, alignment); + + if (hasDisposer) { + // Reserve space for the ObjectHeader, but don't add it to the object list yet. + result = alignTo(reinterpret_cast(result) + sizeof(ObjectHeader), alignment); + } + + KJ_DASSERT(reinterpret_cast(result) % alignment == 0); + return result; +} + +void* Arena::allocateBytesInternal(size_t amount, uint alignment) { + if (currentChunk != nullptr) { + ChunkHeader* chunk = currentChunk; + byte* alignedPos = alignTo(chunk->pos, alignment); + + // Careful about overflow here. + if (amount + (alignedPos - chunk->pos) <= chunk->end - chunk->pos) { + // There's enough space in this chunk. + chunk->pos = alignedPos + amount; + return alignedPos; + } + } + + // Not enough space in the current chunk. Allocate a new one. + + // We need to allocate at least enough space for the ChunkHeader and the requested allocation. + + // If the alignment is less than that of the chunk header, we'll need to increase it. + alignment = kj::max(alignment, alignof(ChunkHeader)); + + // If the ChunkHeader size does not match the alignment, we'll need to pad it up. + amount += alignTo(sizeof(ChunkHeader), alignment); + + // Make sure we're going to allocate enough space. + while (nextChunkSize < amount) { + nextChunkSize *= 2; + } + + // Allocate. + byte* bytes = reinterpret_cast(operator new(nextChunkSize)); + + // Set up the ChunkHeader at the beginning of the allocation. + ChunkHeader* newChunk = reinterpret_cast(bytes); + newChunk->next = chunkList; + newChunk->pos = bytes + amount; + newChunk->end = bytes + nextChunkSize; + currentChunk = newChunk; + chunkList = newChunk; + nextChunkSize *= 2; + + // Move past the ChunkHeader to find the position of the allocated object. + return alignTo(bytes + sizeof(ChunkHeader), alignment); +} + +StringPtr Arena::copyString(StringPtr content) { + char* data = reinterpret_cast(allocateBytes(content.size() + 1, 1, false)); + memcpy(data, content.cStr(), content.size() + 1); + return StringPtr(data, content.size()); +} + +void Arena::setDestructor(void* ptr, void (*destructor)(void*)) { + ObjectHeader* header = reinterpret_cast(ptr) - 1; + KJ_DASSERT(reinterpret_cast(header) % alignof(ObjectHeader) == 0); + header->destructor = destructor; + header->next = objectList; + objectList = header; +} + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/arena.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/arena.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,213 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ARENA_H_ +#define KJ_ARENA_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" +#include "array.h" +#include "string.h" + +namespace kj { + +class Arena { + // A class which allows several objects to be allocated in contiguous chunks of memory, then + // frees them all at once. + // + // Allocating from the same Arena in multiple threads concurrently is NOT safe, because making + // it safe would require atomic operations that would slow down allocation even when + // single-threaded. If you need to use arena allocation in a multithreaded context, consider + // allocating thread-local arenas. + +public: + explicit Arena(size_t chunkSizeHint = 1024); + // Create an Arena. `chunkSizeHint` hints at where to start when allocating chunks, but is only + // a hint -- the Arena will, for example, allocate progressively larger chunks as time goes on, + // in order to reduce overall allocation overhead. + + explicit Arena(ArrayPtr scratch); + // Allocates from the given scratch space first, only resorting to the heap when it runs out. + + KJ_DISALLOW_COPY(Arena); + ~Arena() noexcept(false); + + template + T& allocate(Params&&... params); + template + ArrayPtr allocateArray(size_t size); + // Allocate an object or array of type T. If T has a non-trivial destructor, that destructor + // will be run during the Arena's destructor. Such destructors are run in opposite order of + // allocation. Note that these methods must maintain a list of destructors to call, which has + // overhead, but this overhead only applies if T has a non-trivial destructor. + + template + Own allocateOwn(Params&&... params); + template + Array allocateOwnArray(size_t size); + template + ArrayBuilder allocateOwnArrayBuilder(size_t capacity); + // Allocate an object or array of type T. Destructors are executed when the returned Own + // or Array goes out-of-scope, which must happen before the Arena is destroyed. This variant + // is useful when you need to control when the destructor is called. This variant also avoids + // the need for the Arena itself to keep track of destructors to call later, which may make it + // slightly more efficient. + + template + inline T& copy(T&& value) { return allocate>(kj::fwd(value)); } + // Allocate a copy of the given value in the arena. This is just a shortcut for calling the + // type's copy (or move) constructor. + + StringPtr copyString(StringPtr content); + // Make a copy of the given string inside the arena, and return a pointer to the copy. + +private: + struct ChunkHeader { + ChunkHeader* next; + byte* pos; // first unallocated byte in this chunk + byte* end; // end of this chunk + }; + struct ObjectHeader { + void (*destructor)(void*); + ObjectHeader* next; + }; + + size_t nextChunkSize; + ChunkHeader* chunkList = nullptr; + ObjectHeader* objectList = nullptr; + + ChunkHeader* currentChunk = nullptr; + + void cleanup(); + // Run all destructors, leaving the above pointers null. If a destructor throws, the State is + // left in a consistent state, such that if cleanup() is called again, it will pick up where + // it left off. + + void* allocateBytes(size_t amount, uint alignment, bool hasDisposer); + // Allocate the given number of bytes. `hasDisposer` must be true if `setDisposer()` may be + // called on this pointer later. + + void* allocateBytesInternal(size_t amount, uint alignment); + // Try to allocate the given number of bytes without taking a lock. Fails if and only if there + // is no space left in the current chunk. + + void setDestructor(void* ptr, void (*destructor)(void*)); + // Schedule the given destructor to be executed when the Arena is destroyed. `ptr` must be a + // pointer previously returned by an `allocateBytes()` call for which `hasDisposer` was true. + + template + static void destroyArray(void* pointer) { + size_t elementCount = *reinterpret_cast(pointer); + constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); + DestructorOnlyArrayDisposer::instance.disposeImpl( + reinterpret_cast(pointer) + prefixSize, + sizeof(T), elementCount, elementCount, &destroyObject); + } + + template + static void destroyObject(void* pointer) { + dtor(*reinterpret_cast(pointer)); + } +}; + +// ======================================================================================= +// Inline implementation details + +template +T& Arena::allocate(Params&&... params) { + T& result = *reinterpret_cast(allocateBytes( + sizeof(T), alignof(T), !__has_trivial_destructor(T))); + if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { + ctor(result, kj::fwd(params)...); + } + if (!__has_trivial_destructor(T)) { + setDestructor(&result, &destroyObject); + } + return result; +} + +template +ArrayPtr Arena::allocateArray(size_t size) { + if (__has_trivial_destructor(T)) { + ArrayPtr result = + arrayPtr(reinterpret_cast(allocateBytes( + sizeof(T) * size, alignof(T), false)), size); + if (!__has_trivial_constructor(T)) { + for (size_t i = 0; i < size; i++) { + ctor(result[i]); + } + } + return result; + } else { + // Allocate with a 64-bit prefix in which we store the array size. + constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t)); + void* base = allocateBytes(sizeof(T) * size + prefixSize, alignof(T), true); + size_t& tag = *reinterpret_cast(base); + ArrayPtr result = + arrayPtr(reinterpret_cast(reinterpret_cast(base) + prefixSize), size); + setDestructor(base, &destroyArray); + + if (__has_trivial_constructor(T)) { + tag = size; + } else { + // In case of constructor exceptions, we need the tag to end up storing the number of objects + // that were successfully constructed, so that they'll be properly destroyed. + tag = 0; + for (size_t i = 0; i < size; i++) { + ctor(result[i]); + tag = i + 1; + } + } + return result; + } +} + +template +Own Arena::allocateOwn(Params&&... params) { + T& result = *reinterpret_cast(allocateBytes(sizeof(T), alignof(T), false)); + if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) { + ctor(result, kj::fwd(params)...); + } + return Own(&result, DestructorOnlyDisposer::instance); +} + +template +Array Arena::allocateOwnArray(size_t size) { + ArrayBuilder result = allocateOwnArrayBuilder(size); + for (size_t i = 0; i < size; i++) { + result.add(); + } + return result.finish(); +} + +template +ArrayBuilder Arena::allocateOwnArrayBuilder(size_t capacity) { + return ArrayBuilder( + reinterpret_cast(allocateBytes(sizeof(T) * capacity, alignof(T), false)), + capacity, DestructorOnlyArrayDisposer::instance); +} + +} // namespace kj + +#endif // KJ_ARENA_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/array-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/array-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,382 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "array.h" +#include "debug.h" +#include +#include +#include + +namespace kj { +namespace { + +struct TestObject { + TestObject() { + index = count; + KJ_ASSERT(index != throwAt); + ++count; + } + TestObject(const TestObject& other) { + KJ_ASSERT(other.index != throwAt); + index = -1; + copiedCount++; + } + ~TestObject() noexcept(false) { + if (index == -1) { + --copiedCount; + } else { + --count; + EXPECT_EQ(index, count); + KJ_ASSERT(count != throwAt); + } + } + + int index; + + static int count; + static int copiedCount; + static int throwAt; +}; + +int TestObject::count = 0; +int TestObject::copiedCount = 0; +int TestObject::throwAt = -1; + +struct TestNoexceptObject { + TestNoexceptObject() noexcept { + index = count; + ++count; + } + TestNoexceptObject(const TestNoexceptObject& other) noexcept { + index = -1; + copiedCount++; + } + ~TestNoexceptObject() noexcept { + if (index == -1) { + --copiedCount; + } else { + --count; + EXPECT_EQ(index, count); + } + } + + int index; + + static int count; + static int copiedCount; +}; + +int TestNoexceptObject::count = 0; +int TestNoexceptObject::copiedCount = 0; + +TEST(Array, TrivialConstructor) { +// char* ptr; + { + Array chars = heapArray(32); +// ptr = chars.begin(); + chars[0] = 12; + chars[1] = 34; + } + + { + Array chars = heapArray(32); + + // TODO(test): The following doesn't work in opt mode -- I guess some allocators zero the + // memory? Is there some other way we can test this? Maybe override malloc()? +// // Somewhat hacky: We can't guarantee that the new array is allocated in the same place, but +// // any reasonable allocator is highly likely to do so. If it does, then we expect that the +// // memory has not been initialized. +// if (chars.begin() == ptr) { +// EXPECT_NE(chars[0], 0); +// EXPECT_NE(chars[1], 0); +// } + } +} + +TEST(Array, ComplexConstructor) { + TestObject::count = 0; + TestObject::throwAt = -1; + + { + Array array = heapArray(32); + EXPECT_EQ(32, TestObject::count); + } + EXPECT_EQ(0, TestObject::count); +} + +#if !KJ_NO_EXCEPTIONS +TEST(Array, ThrowingConstructor) { + TestObject::count = 0; + TestObject::throwAt = 16; + + // If a constructor throws, the previous elements should still be destroyed. + EXPECT_ANY_THROW(heapArray(32)); + EXPECT_EQ(0, TestObject::count); +} + +TEST(Array, ThrowingDestructor) { + TestObject::count = 0; + TestObject::throwAt = -1; + + Array array = heapArray(32); + EXPECT_EQ(32, TestObject::count); + + // If a destructor throws, all elements should still be destroyed. + TestObject::throwAt = 16; + EXPECT_ANY_THROW(array = nullptr); + EXPECT_EQ(0, TestObject::count); +} +#endif // !KJ_NO_EXCEPTIONS + +TEST(Array, AraryBuilder) { + TestObject::count = 0; + TestObject::throwAt = -1; + + Array array; + + { + ArrayBuilder builder = heapArrayBuilder(32); + + for (int i = 0; i < 32; i++) { + EXPECT_EQ(i, TestObject::count); + builder.add(); + } + + EXPECT_EQ(32, TestObject::count); + array = builder.finish(); + EXPECT_EQ(32, TestObject::count); + } + + EXPECT_EQ(32, TestObject::count); + array = nullptr; + EXPECT_EQ(0, TestObject::count); +} + +TEST(Array, AraryBuilderAddAll) { + { + // Trivial case. + char text[] = "foo"; + ArrayBuilder builder = heapArrayBuilder(5); + builder.add('<'); + builder.addAll(text, text + 3); + builder.add('>'); + auto array = builder.finish(); + EXPECT_EQ("", std::string(array.begin(), array.end())); + } + + { + // Trivial case, const. + const char* text = "foo"; + ArrayBuilder builder = heapArrayBuilder(5); + builder.add('<'); + builder.addAll(text, text + 3); + builder.add('>'); + auto array = builder.finish(); + EXPECT_EQ("", std::string(array.begin(), array.end())); + } + + { + // Trivial case, non-pointer iterator. + std::list text = {'f', 'o', 'o'}; + ArrayBuilder builder = heapArrayBuilder(5); + builder.add('<'); + builder.addAll(text); + builder.add('>'); + auto array = builder.finish(); + EXPECT_EQ("", std::string(array.begin(), array.end())); + } + + { + // Complex case. + std::string strs[] = {"foo", "bar", "baz"}; + ArrayBuilder builder = heapArrayBuilder(5); + builder.add("qux"); + builder.addAll(strs, strs + 3); + builder.add("quux"); + auto array = builder.finish(); + EXPECT_EQ("qux", array[0]); + EXPECT_EQ("foo", array[1]); + EXPECT_EQ("bar", array[2]); + EXPECT_EQ("baz", array[3]); + EXPECT_EQ("quux", array[4]); + } + + { + // Complex case, noexcept. + TestNoexceptObject::count = 0; + TestNoexceptObject::copiedCount = 0; + TestNoexceptObject objs[3]; + EXPECT_EQ(3, TestNoexceptObject::count); + EXPECT_EQ(0, TestNoexceptObject::copiedCount); + ArrayBuilder builder = heapArrayBuilder(3); + EXPECT_EQ(3, TestNoexceptObject::count); + EXPECT_EQ(0, TestNoexceptObject::copiedCount); + builder.addAll(objs, objs + 3); + EXPECT_EQ(3, TestNoexceptObject::count); + EXPECT_EQ(3, TestNoexceptObject::copiedCount); + auto array = builder.finish(); + EXPECT_EQ(3, TestNoexceptObject::count); + EXPECT_EQ(3, TestNoexceptObject::copiedCount); + } + EXPECT_EQ(0, TestNoexceptObject::count); + EXPECT_EQ(0, TestNoexceptObject::copiedCount); + + { + // Complex case, exceptions possible. + TestObject::count = 0; + TestObject::copiedCount = 0; + TestObject::throwAt = -1; + TestObject objs[3]; + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + ArrayBuilder builder = heapArrayBuilder(3); + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + builder.addAll(objs, objs + 3); + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(3, TestObject::copiedCount); + auto array = builder.finish(); + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(3, TestObject::copiedCount); + } + EXPECT_EQ(0, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + +#if !KJ_NO_EXCEPTIONS + { + // Complex case, exceptions occur. + TestObject::count = 0; + TestObject::copiedCount = 0; + TestObject::throwAt = -1; + TestObject objs[3]; + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + + TestObject::throwAt = 1; + + ArrayBuilder builder = heapArrayBuilder(3); + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + + EXPECT_ANY_THROW(builder.addAll(objs, objs + 3)); + TestObject::throwAt = -1; + + EXPECT_EQ(3, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); + } + EXPECT_EQ(0, TestObject::count); + EXPECT_EQ(0, TestObject::copiedCount); +#endif // !KJ_NO_EXCEPTIONS +} + +TEST(Array, HeapCopy) { + { + Array copy = heapArray("foo", 3); + EXPECT_EQ(3u, copy.size()); + EXPECT_EQ("foo", std::string(copy.begin(), 3)); + } + { + Array copy = heapArray(ArrayPtr("bar", 3)); + EXPECT_EQ(3u, copy.size()); + EXPECT_EQ("bar", std::string(copy.begin(), 3)); + } + { + const char* ptr = "baz"; + Array copy = heapArray(ptr, ptr + 3); + EXPECT_EQ(3u, copy.size()); + EXPECT_EQ("baz", std::string(copy.begin(), 3)); + } +} + +TEST(Array, OwnConst) { + ArrayBuilder builder = heapArrayBuilder(2); + int x[2] = {123, 234}; + builder.addAll(x, x + 2); + + Array i = builder.finish(); //heapArray({123, 234}); + ASSERT_EQ(2u, i.size()); + EXPECT_EQ(123, i[0]); + EXPECT_EQ(234, i[1]); + + Array ci = mv(i); + ASSERT_EQ(2u, ci.size()); + EXPECT_EQ(123, ci[0]); + EXPECT_EQ(234, ci[1]); + + Array ci2 = heapArray({345, 456}); + ASSERT_EQ(2u, ci2.size()); + EXPECT_EQ(345, ci2[0]); + EXPECT_EQ(456, ci2[1]); +} + +TEST(Array, Map) { + StringPtr foo = "abcd"; + Array bar = KJ_MAP(c, foo) -> char { return c + 1; }; + EXPECT_STREQ("bcde", str(bar).cStr()); +} + +TEST(Array, MapRawArray) { + uint foo[4] = {1, 2, 3, 4}; + Array bar = KJ_MAP(i, foo) -> uint { return i * i; }; + ASSERT_EQ(4, bar.size()); + EXPECT_EQ(1, bar[0]); + EXPECT_EQ(4, bar[1]); + EXPECT_EQ(9, bar[2]); + EXPECT_EQ(16, bar[3]); +} + +TEST(Array, ReleaseAsBytesOrChars) { + { + Array chars = kj::heapArray("foo", 3); + Array bytes = chars.releaseAsBytes(); + EXPECT_TRUE(chars == nullptr); + ASSERT_EQ(3, bytes.size()); + EXPECT_EQ('f', bytes[0]); + EXPECT_EQ('o', bytes[1]); + EXPECT_EQ('o', bytes[2]); + + chars = bytes.releaseAsChars(); + EXPECT_TRUE(bytes == nullptr); + ASSERT_EQ(3, chars.size()); + EXPECT_EQ('f', chars[0]); + EXPECT_EQ('o', chars[1]); + EXPECT_EQ('o', chars[2]); + } + { + Array chars = kj::heapArray("foo", 3); + Array bytes = chars.releaseAsBytes(); + EXPECT_TRUE(chars == nullptr); + ASSERT_EQ(3, bytes.size()); + EXPECT_EQ('f', bytes[0]); + EXPECT_EQ('o', bytes[1]); + EXPECT_EQ('o', bytes[2]); + + chars = bytes.releaseAsChars(); + EXPECT_TRUE(bytes == nullptr); + ASSERT_EQ(3, chars.size()); + EXPECT_EQ('f', chars[0]); + EXPECT_EQ('o', chars[1]); + EXPECT_EQ('o', chars[2]); + } +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/array.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/array.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,109 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "array.h" +#include "exception.h" + +namespace kj { + +void ExceptionSafeArrayUtil::construct(size_t count, void (*constructElement)(void*)) { + while (count > 0) { + constructElement(pos); + pos += elementSize; + ++constructedElementCount; + --count; + } +} + +void ExceptionSafeArrayUtil::destroyAll() { + while (constructedElementCount > 0) { + pos -= elementSize; + --constructedElementCount; + destroyElement(pos); + } +} + +const DestructorOnlyArrayDisposer DestructorOnlyArrayDisposer::instance = + DestructorOnlyArrayDisposer(); + +void DestructorOnlyArrayDisposer::disposeImpl( + void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const { + if (destroyElement != nullptr) { + ExceptionSafeArrayUtil guard(firstElement, elementSize, elementCount, destroyElement); + guard.destroyAll(); + } +} + +const NullArrayDisposer NullArrayDisposer::instance = NullArrayDisposer(); + +void NullArrayDisposer::disposeImpl( + void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const {} + +namespace _ { // private + +struct AutoDeleter { + void* ptr; + inline void* release() { void* result = ptr; ptr = nullptr; return result; } + inline AutoDeleter(void* ptr): ptr(ptr) {} + inline ~AutoDeleter() { operator delete(ptr); } +}; + +void* HeapArrayDisposer::allocateImpl(size_t elementSize, size_t elementCount, size_t capacity, + void (*constructElement)(void*), + void (*destroyElement)(void*)) { + AutoDeleter result(operator new(elementSize * capacity)); + + if (constructElement == nullptr) { + // Nothing to do. + } else if (destroyElement == nullptr) { + byte* pos = reinterpret_cast(result.ptr); + while (elementCount > 0) { + constructElement(pos); + pos += elementSize; + --elementCount; + } + } else { + ExceptionSafeArrayUtil guard(result.ptr, elementSize, 0, destroyElement); + guard.construct(elementCount, constructElement); + guard.release(); + } + + return result.release(); +} + +void HeapArrayDisposer::disposeImpl( + void* firstElement, size_t elementSize, size_t elementCount, size_t capacity, + void (*destroyElement)(void*)) const { + // Note that capacity is ignored since operator delete() doesn't care about it. + AutoDeleter deleter(firstElement); + + if (destroyElement != nullptr) { + ExceptionSafeArrayUtil guard(firstElement, elementSize, elementCount, destroyElement); + guard.destroyAll(); + } +} + +const HeapArrayDisposer HeapArrayDisposer::instance = HeapArrayDisposer(); + +} // namespace _ (private) +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/array.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,813 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ARRAY_H_ +#define KJ_ARRAY_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "common.h" +#include +#include + +namespace kj { + +// ======================================================================================= +// ArrayDisposer -- Implementation details. + +class ArrayDisposer { + // Much like Disposer from memory.h. + +protected: + // Do not declare a destructor, as doing so will force a global initializer for + // HeapArrayDisposer::instance. + + virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const = 0; + // Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr + // if the elements have trivial destructors. `capacity` is the amount of space that was + // allocated while `elementCount` is the number of elements that were actually constructed; + // these are always the same number for Array but may be different when using ArrayBuilder. + +public: + + template + void dispose(T* firstElement, size_t elementCount, size_t capacity) const; + // Helper wrapper around disposeImpl(). + // + // Callers must not call dispose() on the same array twice, even if the first call throws + // an exception. + +private: + template + struct Dispose_; +}; + +class ExceptionSafeArrayUtil { + // Utility class that assists in constructing or destroying elements of an array, where the + // constructor or destructor could throw exceptions. In case of an exception, + // ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been + // constructed but not destroyed. Remember that destructors that throw exceptions are required + // to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more + // than one exception will be thrown (and the program will not terminate). + +public: + inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount, + void (*destroyElement)(void*)) + : pos(reinterpret_cast(ptr) + elementSize * constructedElementCount), + elementSize(elementSize), constructedElementCount(constructedElementCount), + destroyElement(destroyElement) {} + KJ_DISALLOW_COPY(ExceptionSafeArrayUtil); + + inline ~ExceptionSafeArrayUtil() noexcept(false) { + if (constructedElementCount > 0) destroyAll(); + } + + void construct(size_t count, void (*constructElement)(void*)); + // Construct the given number of elements. + + void destroyAll(); + // Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope + // to ensure that one element throwing an exception does not prevent the others from being + // destroyed. + + void release() { constructedElementCount = 0; } + // Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements. + // Call this after you've successfully finished constructing. + +private: + byte* pos; + size_t elementSize; + size_t constructedElementCount; + void (*destroyElement)(void*); +}; + +class DestructorOnlyArrayDisposer: public ArrayDisposer { +public: + static const DestructorOnlyArrayDisposer instance; + + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; +}; + +class NullArrayDisposer: public ArrayDisposer { + // An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't + // actually own its content. + +public: + static const NullArrayDisposer instance; + + void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; +}; + +// ======================================================================================= +// Array + +template +class Array { + // An owned array which will automatically be disposed of (using an ArrayDisposer) in the + // destructor. Can be moved, but not copied. Much like Own, but for arrays rather than + // single objects. + +public: + inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {} + inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {} + inline Array(Array&& other) noexcept + : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { + other.ptr = nullptr; + other.size_ = 0; + } + inline Array(Array>&& other) noexcept + : ptr(other.ptr), size_(other.size_), disposer(other.disposer) { + other.ptr = nullptr; + other.size_ = 0; + } + inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer) + : ptr(firstElement), size_(size), disposer(&disposer) {} + + KJ_DISALLOW_COPY(Array); + inline ~Array() noexcept { dispose(); } + + inline operator ArrayPtr() { + return ArrayPtr(ptr, size_); + } + inline operator ArrayPtr() const { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asPtr() { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asPtr() const { + return ArrayPtr(ptr, size_); + } + + inline size_t size() const { return size_; } + inline T& operator[](size_t index) const { + KJ_IREQUIRE(index < size_, "Out-of-bounds Array access."); + return ptr[index]; + } + + inline const T* begin() const { return ptr; } + inline const T* end() const { return ptr + size_; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(ptr + size_ - 1); } + inline T* begin() { return ptr; } + inline T* end() { return ptr + size_; } + inline T& front() { return *ptr; } + inline T& back() { return *(ptr + size_ - 1); } + + inline ArrayPtr slice(size_t start, size_t end) { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); + return ArrayPtr(ptr + start, end - start); + } + inline ArrayPtr slice(size_t start, size_t end) const { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice()."); + return ArrayPtr(ptr + start, end - start); + } + + inline ArrayPtr asBytes() const { return asPtr().asBytes(); } + inline ArrayPtr> asBytes() { return asPtr().asBytes(); } + inline ArrayPtr asChars() const { return asPtr().asChars(); } + inline ArrayPtr> asChars() { return asPtr().asChars(); } + + inline Array> releaseAsBytes() { + // Like asBytes() but transfers ownership. + static_assert(sizeof(T) == sizeof(byte), + "releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars)."); + Array> result( + reinterpret_cast*>(ptr), size_, *disposer); + ptr = nullptr; + size_ = 0; + return result; + } + inline Array> releaseAsChars() { + // Like asChars() but transfers ownership. + static_assert(sizeof(T) == sizeof(PropagateConst), + "releaseAsChars() only possible on arrays with char-size elements (e.g. bytes)."); + Array> result( + reinterpret_cast*>(ptr), size_, *disposer); + ptr = nullptr; + size_ = 0; + return result; + } + + inline bool operator==(decltype(nullptr)) const { return size_ == 0; } + inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } + + inline Array& operator=(decltype(nullptr)) { + dispose(); + return *this; + } + + inline Array& operator=(Array&& other) { + dispose(); + ptr = other.ptr; + size_ = other.size_; + disposer = other.disposer; + other.ptr = nullptr; + other.size_ = 0; + return *this; + } + +private: + T* ptr; + size_t size_; + const ArrayDisposer* disposer; + + inline void dispose() { + // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly + // dispose again. + T* ptrCopy = ptr; + size_t sizeCopy = size_; + if (ptrCopy != nullptr) { + ptr = nullptr; + size_ = 0; + disposer->dispose(ptrCopy, sizeCopy, sizeCopy); + } + } + + template + friend class Array; +}; + +static_assert(!canMemcpy>(), "canMemcpy<>() is broken"); + +namespace _ { // private + +class HeapArrayDisposer final: public ArrayDisposer { +public: + template + static T* allocate(size_t count); + template + static T* allocateUninitialized(size_t count); + + static const HeapArrayDisposer instance; + +private: + static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity, + void (*constructElement)(void*), void (*destroyElement)(void*)); + // Allocates and constructs the array. Both function pointers are null if the constructor is + // trivial, otherwise destroyElement is null if the constructor doesn't throw. + + virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, + size_t capacity, void (*destroyElement)(void*)) const override; + + template + struct Allocate_; +}; + +} // namespace _ (private) + +template +inline Array heapArray(size_t size) { + // Much like `heap()` from memory.h, allocates a new array on the heap. + + return Array(_::HeapArrayDisposer::allocate(size), size, + _::HeapArrayDisposer::instance); +} + +template Array heapArray(const T* content, size_t size); +template Array heapArray(ArrayPtr content); +template Array heapArray(ArrayPtr content); +template Array heapArray(Iterator begin, Iterator end); +template Array heapArray(std::initializer_list init); +// Allocate a heap array containing a copy of the given content. + +template +Array heapArrayFromIterable(Container&& a) { return heapArray(a.begin(), a.end()); } +template +Array heapArrayFromIterable(Array&& a) { return mv(a); } + +// ======================================================================================= +// ArrayBuilder + +template +class ArrayBuilder { + // Class which lets you build an Array specifying the exact constructor arguments for each + // element, rather than starting by default-constructing them. + +public: + ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} + ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {} + explicit ArrayBuilder(RemoveConst* firstElement, size_t capacity, + const ArrayDisposer& disposer) + : ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity), + disposer(&disposer) {} + ArrayBuilder(ArrayBuilder&& other) + : ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) { + other.ptr = nullptr; + other.pos = nullptr; + other.endPtr = nullptr; + } + KJ_DISALLOW_COPY(ArrayBuilder); + inline ~ArrayBuilder() noexcept(false) { dispose(); } + + inline operator ArrayPtr() { + return arrayPtr(ptr, pos); + } + inline operator ArrayPtr() const { + return arrayPtr(ptr, pos); + } + inline ArrayPtr asPtr() { + return arrayPtr(ptr, pos); + } + inline ArrayPtr asPtr() const { + return arrayPtr(ptr, pos); + } + + inline size_t size() const { return pos - ptr; } + inline size_t capacity() const { return endPtr - ptr; } + inline T& operator[](size_t index) const { + KJ_IREQUIRE(index < implicitCast(pos - ptr), "Out-of-bounds Array access."); + return ptr[index]; + } + + inline const T* begin() const { return ptr; } + inline const T* end() const { return pos; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(pos - 1); } + inline T* begin() { return ptr; } + inline T* end() { return pos; } + inline T& front() { return *ptr; } + inline T& back() { return *(pos - 1); } + + ArrayBuilder& operator=(ArrayBuilder&& other) { + dispose(); + ptr = other.ptr; + pos = other.pos; + endPtr = other.endPtr; + disposer = other.disposer; + other.ptr = nullptr; + other.pos = nullptr; + other.endPtr = nullptr; + return *this; + } + ArrayBuilder& operator=(decltype(nullptr)) { + dispose(); + return *this; + } + + template + T& add(Params&&... params) { + KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder."); + ctor(*pos, kj::fwd(params)...); + return *pos++; + } + + template + void addAll(Container&& container) { + addAll()>( + container.begin(), container.end()); + } + + template + void addAll(Iterator start, Iterator end); + + void removeLast() { + KJ_IREQUIRE(pos > ptr, "No elements present to remove."); + kj::dtor(*--pos); + } + + void truncate(size_t size) { + KJ_IREQUIRE(size <= this->size(), "can't use truncate() to expand"); + + T* target = ptr + size; + if (__has_trivial_destructor(T)) { + pos = target; + } else { + while (pos > target) { + kj::dtor(*--pos); + } + } + } + + void resize(size_t size) { + KJ_IREQUIRE(size <= capacity(), "can't resize past capacity"); + + T* target = ptr + size; + if (target > pos) { + // expand + if (__has_trivial_constructor(T)) { + pos = target; + } else { + while (pos < target) { + kj::ctor(*pos++); + } + } + } else { + // truncate + if (__has_trivial_destructor(T)) { + pos = target; + } else { + while (pos > target) { + kj::dtor(*--pos); + } + } + } + } + + Array finish() { + // We could safely remove this check if we assume that the disposer implementation doesn't + // need to know the original capacity, as is thes case with HeapArrayDisposer since it uses + // operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity + // in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this + // check might catch bugs. Probably people should use Vector if they want to build arrays + // without knowing the final size in advance. + KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely."); + Array result(reinterpret_cast(ptr), pos - ptr, *disposer); + ptr = nullptr; + pos = nullptr; + endPtr = nullptr; + return result; + } + + inline bool isFull() const { + return pos == endPtr; + } + +private: + T* ptr; + RemoveConst* pos; + T* endPtr; + const ArrayDisposer* disposer; + + inline void dispose() { + // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly + // dispose again. + T* ptrCopy = ptr; + T* posCopy = pos; + T* endCopy = endPtr; + if (ptrCopy != nullptr) { + ptr = nullptr; + pos = nullptr; + endPtr = nullptr; + disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy); + } + } +}; + +template +inline ArrayBuilder heapArrayBuilder(size_t size) { + // Like `heapArray()` but does not default-construct the elements. You must construct them + // manually by calling `add()`. + + return ArrayBuilder(_::HeapArrayDisposer::allocateUninitialized>(size), + size, _::HeapArrayDisposer::instance); +} + +// ======================================================================================= +// Inline Arrays + +template +class FixedArray { + // A fixed-width array whose storage is allocated inline rather than on the heap. + +public: + inline size_t size() const { return fixedSize; } + inline T* begin() { return content; } + inline T* end() { return content + fixedSize; } + inline const T* begin() const { return content; } + inline const T* end() const { return content + fixedSize; } + + inline operator ArrayPtr() { + return arrayPtr(content, fixedSize); + } + inline operator ArrayPtr() const { + return arrayPtr(content, fixedSize); + } + + inline T& operator[](size_t index) { return content[index]; } + inline const T& operator[](size_t index) const { return content[index]; } + +private: + T content[fixedSize]; +}; + +template +class CappedArray { + // Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit + // specified by the template parameter. + // + // TODO(someday): Don't construct elements past currentSize? + +public: + inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {} + inline explicit constexpr CappedArray(size_t s): currentSize(s) {} + + inline size_t size() const { return currentSize; } + inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; } + inline T* begin() { return content; } + inline T* end() { return content + currentSize; } + inline const T* begin() const { return content; } + inline const T* end() const { return content + currentSize; } + + inline operator ArrayPtr() { + return arrayPtr(content, currentSize); + } + inline operator ArrayPtr() const { + return arrayPtr(content, currentSize); + } + + inline T& operator[](size_t index) { return content[index]; } + inline const T& operator[](size_t index) const { return content[index]; } + +private: + size_t currentSize; + T content[fixedSize]; +}; + +// ======================================================================================= +// KJ_MAP + +#define KJ_MAP(elementName, array) \ + ::kj::_::Mapper(array) * \ + [&](typename ::kj::_::Mapper::Element elementName) +// Applies some function to every element of an array, returning an Array of the results, with +// nice syntax. Example: +// +// StringPtr foo = "abcd"; +// Array bar = KJ_MAP(c, foo) -> char { return c + 1; }; +// KJ_ASSERT(str(bar) == "bcde"); + +namespace _ { // private + +template +struct Mapper { + T array; + Mapper(T&& array): array(kj::fwd(array)) {} + template + auto operator*(Func&& func) -> Array { + auto builder = heapArrayBuilder(array.size()); + for (auto iter = array.begin(); iter != array.end(); ++iter) { + builder.add(func(*iter)); + } + return builder.finish(); + } + typedef decltype(*kj::instance().begin()) Element; +}; + +template +struct Mapper { + T* array; + Mapper(T* array): array(array) {} + template + auto operator*(Func&& func) -> Array { + auto builder = heapArrayBuilder(s); + for (size_t i = 0; i < s; i++) { + builder.add(func(array[i])); + } + return builder.finish(); + } + typedef decltype(*array)& Element; +}; + +} // namespace _ (private) + +// ======================================================================================= +// Inline implementation details + +template +struct ArrayDisposer::Dispose_ { + static void dispose(T* firstElement, size_t elementCount, size_t capacity, + const ArrayDisposer& disposer) { + disposer.disposeImpl(const_cast*>(firstElement), + sizeof(T), elementCount, capacity, nullptr); + } +}; +template +struct ArrayDisposer::Dispose_ { + static void destruct(void* ptr) { + kj::dtor(*reinterpret_cast(ptr)); + } + + static void dispose(T* firstElement, size_t elementCount, size_t capacity, + const ArrayDisposer& disposer) { + disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct); + } +}; + +template +void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const { + Dispose_::dispose(firstElement, elementCount, capacity, *this); +} + +namespace _ { // private + +template +struct HeapArrayDisposer::Allocate_ { + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, nullptr, nullptr)); + } +}; +template +struct HeapArrayDisposer::Allocate_ { + static void construct(void* ptr) { + kj::ctor(*reinterpret_cast(ptr)); + } + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, &construct, nullptr)); + } +}; +template +struct HeapArrayDisposer::Allocate_ { + static void construct(void* ptr) { + kj::ctor(*reinterpret_cast(ptr)); + } + static void destruct(void* ptr) { + kj::dtor(*reinterpret_cast(ptr)); + } + static T* allocate(size_t elementCount, size_t capacity) { + return reinterpret_cast(allocateImpl( + sizeof(T), elementCount, capacity, &construct, &destruct)); + } +}; + +template +T* HeapArrayDisposer::allocate(size_t count) { + return Allocate_::allocate(count, count); +} + +template +T* HeapArrayDisposer::allocateUninitialized(size_t count) { + return Allocate_::allocate(0, count); +} + +template ()> +struct CopyConstructArray_; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, T* start, T* end) { + memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); + return pos + (end - start); + } +}; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, const T* start, const T* end) { + memcpy(pos, start, reinterpret_cast(end) - reinterpret_cast(start)); + return pos + (end - start); + } +}; + +template +struct CopyConstructArray_ { + static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Since both the copy constructor and assignment operator are trivial, we know that assignment + // is equivalent to copy-constructing. So we can make this case somewhat easier for the + // compiler to optimize. + while (start != end) { + *pos++ = *start++; + } + return pos; + } +}; + +template +struct CopyConstructArray_ { + struct ExceptionGuard { + T* start; + T* pos; + inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {} + ~ExceptionGuard() noexcept(false) { + while (pos > start) { + dtor(*--pos); + } + } + }; + + static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Verify that T can be *implicitly* constructed from the source values. + if (false) implicitCast(*start); + + if (noexcept(T(*start))) { + while (start != end) { + ctor(*pos++, *start++); + } + return pos; + } else { + // Crap. This is complicated. + ExceptionGuard guard(pos); + while (start != end) { + ctor(*guard.pos, *start++); + ++guard.pos; + } + guard.start = guard.pos; + return guard.pos; + } + } +}; + +template +struct CopyConstructArray_ { + // Actually move-construct. + + struct ExceptionGuard { + T* start; + T* pos; + inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {} + ~ExceptionGuard() noexcept(false) { + while (pos > start) { + dtor(*--pos); + } + } + }; + + static T* apply(T* __restrict__ pos, Iterator start, Iterator end) { + // Verify that T can be *implicitly* constructed from the source values. + if (false) implicitCast(kj::mv(*start)); + + if (noexcept(T(kj::mv(*start)))) { + while (start != end) { + ctor(*pos++, kj::mv(*start++)); + } + return pos; + } else { + // Crap. This is complicated. + ExceptionGuard guard(pos); + while (start != end) { + ctor(*guard.pos, kj::mv(*start++)); + ++guard.pos; + } + guard.start = guard.pos; + return guard.pos; + } + } +}; + +} // namespace _ (private) + +template +template +void ArrayBuilder::addAll(Iterator start, Iterator end) { + pos = _::CopyConstructArray_, Decay, move>::apply(pos, start, end); +} + +template +Array heapArray(const T* content, size_t size) { + ArrayBuilder builder = heapArrayBuilder(size); + builder.addAll(content, content + size); + return builder.finish(); +} + +template +Array heapArray(T* content, size_t size) { + ArrayBuilder builder = heapArrayBuilder(size); + builder.addAll(content, content + size); + return builder.finish(); +} + +template +Array heapArray(ArrayPtr content) { + ArrayBuilder builder = heapArrayBuilder(content.size()); + builder.addAll(content); + return builder.finish(); +} + +template +Array heapArray(ArrayPtr content) { + ArrayBuilder builder = heapArrayBuilder(content.size()); + builder.addAll(content); + return builder.finish(); +} + +template Array +heapArray(Iterator begin, Iterator end) { + ArrayBuilder builder = heapArrayBuilder(end - begin); + builder.addAll(begin, end); + return builder.finish(); +} + +template +inline Array heapArray(std::initializer_list init) { + return heapArray(init.begin(), init.end()); +} + +} // namespace kj + +#endif // KJ_ARRAY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-inl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-inl.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1112 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains extended inline implementation details that are required along with async.h. +// We move this all into a separate file to make async.h more readable. +// +// Non-inline declarations here are defined in async.c++. + +#ifndef KJ_ASYNC_H_ +#error "Do not include this directly; include kj/async.h." +#include "async.h" // help IDE parse this file +#endif + +#ifndef KJ_ASYNC_INL_H_ +#define KJ_ASYNC_INL_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +namespace kj { +namespace _ { // private + +template +class ExceptionOr; + +class ExceptionOrValue { +public: + ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {} + KJ_DISALLOW_COPY(ExceptionOrValue); + + void addException(Exception&& exception) { + if (this->exception == nullptr) { + this->exception = kj::mv(exception); + } + } + + template + ExceptionOr& as() { return *static_cast*>(this); } + template + const ExceptionOr& as() const { return *static_cast*>(this); } + + Maybe exception; + +protected: + // Allow subclasses to have move constructor / assignment. + ExceptionOrValue() = default; + ExceptionOrValue(ExceptionOrValue&& other) = default; + ExceptionOrValue& operator=(ExceptionOrValue&& other) = default; +}; + +template +class ExceptionOr: public ExceptionOrValue { +public: + ExceptionOr() = default; + ExceptionOr(T&& value): value(kj::mv(value)) {} + ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {} + ExceptionOr(ExceptionOr&&) = default; + ExceptionOr& operator=(ExceptionOr&&) = default; + + Maybe value; +}; + +class Event { + // An event waiting to be executed. Not for direct use by applications -- promises use this + // internally. + +public: + Event(); + ~Event() noexcept(false); + KJ_DISALLOW_COPY(Event); + + void armDepthFirst(); + // Enqueue this event so that `fire()` will be called from the event loop soon. + // + // Events scheduled in this way are executed in depth-first order: if an event callback arms + // more events, those events are placed at the front of the queue (in the order in which they + // were armed), so that they run immediately after the first event's callback returns. + // + // Depth-first event scheduling is appropriate for events that represent simple continuations + // of a previous event that should be globbed together for performance. Depth-first scheduling + // can lead to starvation, so any long-running task must occasionally yield with + // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses + // breadth-first.) + // + // To use breadth-first scheduling instead, use `armBreadthFirst()`. + + void armBreadthFirst(); + // Like `armDepthFirst()` except that the event is placed at the end of the queue. + + kj::String trace(); + // Dump debug info about this event. + + virtual _::PromiseNode* getInnerForTrace(); + // If this event wraps a PromiseNode, get that node. Used for debug tracing. + // Default implementation returns nullptr. + +protected: + virtual Maybe> fire() = 0; + // Fire the event. Possibly returns a pointer to itself, which will be discarded by the + // caller. This is the only way that an event can delete itself as a result of firing, as + // doing so from within fire() will throw an exception. + +private: + friend class kj::EventLoop; + EventLoop& loop; + Event* next; + Event** prev; + bool firing = false; +}; + +class PromiseNode { + // A Promise contains a chain of PromiseNodes tracking the pending transformations. + // + // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky + // use of pointers to ExceptionOrValue which actually point to ExceptionOr, but are only + // so down-cast in the few places that really need to be templated. Luckily this is all + // internal implementation details. + +public: + virtual void onReady(Event& event) noexcept = 0; + // Arms the given event when ready. + + virtual void setSelfPointer(Own* selfPtr) noexcept; + // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own + // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses + // this to shorten redundant chains. The default implementation does nothing; only + // ChainPromiseNode should implement this. + + virtual void get(ExceptionOrValue& output) noexcept = 0; + // Get the result. `output` points to an ExceptionOr into which the result will be written. + // Can only be called once, and only after the node is ready. Must be called directly from the + // event loop, with no application code on the stack. + + virtual PromiseNode* getInnerForTrace(); + // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing. + // Default implementation returns nullptr. + +protected: + class OnReadyEvent { + // Helper class for implementing onReady(). + + public: + void init(Event& newEvent); + // Returns true if arm() was already called. + + void arm(); + // Arms the event if init() has already been called and makes future calls to init() return + // true. + + private: + Event* event = nullptr; + }; +}; + +// ------------------------------------------------------------------- + +class ImmediatePromiseNodeBase: public PromiseNode { +public: + ImmediatePromiseNodeBase(); + ~ImmediatePromiseNodeBase() noexcept(false); + + void onReady(Event& event) noexcept override; +}; + +template +class ImmediatePromiseNode final: public ImmediatePromiseNodeBase { + // A promise that has already been resolved to an immediate value or exception. + +public: + ImmediatePromiseNode(ExceptionOr&& result): result(kj::mv(result)) {} + + void get(ExceptionOrValue& output) noexcept override { + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; +}; + +class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase { +public: + ImmediateBrokenPromiseNode(Exception&& exception); + + void get(ExceptionOrValue& output) noexcept override; + +private: + Exception exception; +}; + +// ------------------------------------------------------------------- + +class AttachmentPromiseNodeBase: public PromiseNode { +public: + AttachmentPromiseNodeBase(Own&& dependency); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + + void dropDependency(); + + template + friend class AttachmentPromiseNode; +}; + +template +class AttachmentPromiseNode final: public AttachmentPromiseNodeBase { + // A PromiseNode that holds on to some object (usually, an Own, but could be any movable + // object) until the promise resolves. + +public: + AttachmentPromiseNode(Own&& dependency, Attachment&& attachment) + : AttachmentPromiseNodeBase(kj::mv(dependency)), + attachment(kj::mv(attachment)) {} + + ~AttachmentPromiseNode() noexcept(false) { + // We need to make sure the dependency is deleted before we delete the attachment because the + // dependency may be using the attachment. + dropDependency(); + } + +private: + Attachment attachment; +}; + +// ------------------------------------------------------------------- + +class PtmfHelper { + // This class is a private helper for GetFunctorStartAddress. The class represents the internal + // representation of a pointer-to-member-function. + + template + friend struct GetFunctorStartAddress; + +#if __GNUG__ + + void* ptr; + ptrdiff_t adj; + // Layout of a pointer-to-member-function used by GCC and compatible compilers. + + void* apply(void* obj) { +#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) + if (adj & 1) { + ptrdiff_t voff = (ptrdiff_t)ptr; +#else + ptrdiff_t voff = (ptrdiff_t)ptr; + if (voff & 1) { + voff &= ~1; +#endif + return *(void**)(*(char**)obj + voff); + } else { + return ptr; + } + } + +#define BODY \ + PtmfHelper result; \ + static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \ + memcpy(&result, &p, sizeof(result)); \ + return result + +#else // __GNUG__ + + void* apply(void* obj) { return nullptr; } + // TODO(port): PTMF instruction address extraction + +#define BODY return PtmfHelper{} + +#endif // __GNUG__, else + + template + static PtmfHelper from(F p) { BODY; } + // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not + // overloaded nor a template. In this case the compiler is able to deduce the full function + // signature directly given the name since there is only one function with that name. + + template + static PtmfHelper from(R (C::*p)(NoInfer

...)) { BODY; } + template + static PtmfHelper from(R (C::*p)(NoInfer

...) const) { BODY; } + // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case + // the function must match exactly the containing type C, return type R, and parameter types P... + // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a + // guess at P. Luckily, if the function parameters are template parameters then it's not + // necessary to be precise about P. +#undef BODY +}; + +template +struct GetFunctorStartAddress { + // Given a functor (any object defining operator()), return the start address of the function, + // suitable for passing to addr2line to obtain a source file/line for debugging purposes. + // + // This turns out to be incredibly hard to implement in the presence of overloaded or templated + // functors. Therefore, we impose these specific restrictions, specific to our use case: + // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas + // anyway.) + // - The template parameters to GetFunctorStartAddress specify a hint as to the expected + // parameter types. If the functor is templated, its parameters must match exactly these types. + // (If it's not templated, ParamTypes are ignored.) + + template + static void* apply(Func&& func) { + typedef decltype(func(instance()...)) ReturnType; + return PtmfHelper::from, ParamTypes...>( + &Decay::operator()).apply(&func); + } +}; + +template <> +struct GetFunctorStartAddress: public GetFunctorStartAddress<> {}; +// Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function +// actually has no parameters. + +class TransformPromiseNodeBase: public PromiseNode { +public: + TransformPromiseNodeBase(Own&& dependency, void* continuationTracePtr); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + void* continuationTracePtr; + + void dropDependency(); + void getDepResult(ExceptionOrValue& output); + + virtual void getImpl(ExceptionOrValue& output) = 0; + + template + friend class TransformPromiseNode; +}; + +template +class TransformPromiseNode final: public TransformPromiseNodeBase { + // A PromiseNode that transforms the result of another PromiseNode through an application-provided + // function (implements `then()`). + +public: + TransformPromiseNode(Own&& dependency, Func&& func, ErrorFunc&& errorHandler) + : TransformPromiseNodeBase(kj::mv(dependency), + GetFunctorStartAddress::apply(func)), + func(kj::fwd(func)), errorHandler(kj::fwd(errorHandler)) {} + + ~TransformPromiseNode() noexcept(false) { + // We need to make sure the dependency is deleted before we delete the continuations because it + // is a common pattern for the continuations to hold ownership of objects that might be in-use + // by the dependency. + dropDependency(); + } + +private: + Func func; + ErrorFunc errorHandler; + + void getImpl(ExceptionOrValue& output) override { + ExceptionOr depResult; + getDepResult(depResult); + KJ_IF_MAYBE(depException, depResult.exception) { + output.as() = handle( + MaybeVoidCaller>>::apply( + errorHandler, kj::mv(*depException))); + } else KJ_IF_MAYBE(depValue, depResult.value) { + output.as() = handle(MaybeVoidCaller::apply(func, kj::mv(*depValue))); + } + } + + ExceptionOr handle(T&& value) { + return kj::mv(value); + } + ExceptionOr handle(PropagateException::Bottom&& value) { + return ExceptionOr(false, value.asException()); + } +}; + +// ------------------------------------------------------------------- + +class ForkHubBase; + +class ForkBranchBase: public PromiseNode { +public: + ForkBranchBase(Own&& hub); + ~ForkBranchBase() noexcept(false); + + void hubReady() noexcept; + // Called by the hub to indicate that it is ready. + + // implements PromiseNode ------------------------------------------ + void onReady(Event& event) noexcept override; + PromiseNode* getInnerForTrace() override; + +protected: + inline ExceptionOrValue& getHubResultRef(); + + void releaseHub(ExceptionOrValue& output); + // Release the hub. If an exception is thrown, add it to `output`. + +private: + OnReadyEvent onReadyEvent; + + Own hub; + ForkBranchBase* next = nullptr; + ForkBranchBase** prevPtr = nullptr; + + friend class ForkHubBase; +}; + +template T copyOrAddRef(T& t) { return t; } +template Own copyOrAddRef(Own& t) { return t->addRef(); } + +template +class ForkBranch final: public ForkBranchBase { + // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives + // a const reference. + +public: + ForkBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} + + void get(ExceptionOrValue& output) noexcept override { + ExceptionOr& hubResult = getHubResultRef().template as(); + KJ_IF_MAYBE(value, hubResult.value) { + output.as().value = copyOrAddRef(*value); + } else { + output.as().value = nullptr; + } + output.exception = hubResult.exception; + releaseHub(output); + } +}; + +template +class SplitBranch final: public ForkBranchBase { + // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives + // a const reference. + +public: + SplitBranch(Own&& hub): ForkBranchBase(kj::mv(hub)) {} + + typedef kj::Decay(kj::instance()))> Element; + + void get(ExceptionOrValue& output) noexcept override { + ExceptionOr& hubResult = getHubResultRef().template as(); + KJ_IF_MAYBE(value, hubResult.value) { + output.as().value = kj::mv(kj::get(*value)); + } else { + output.as().value = nullptr; + } + output.exception = hubResult.exception; + releaseHub(output); + } +}; + +// ------------------------------------------------------------------- + +class ForkHubBase: public Refcounted, protected Event { +public: + ForkHubBase(Own&& inner, ExceptionOrValue& resultRef); + + inline ExceptionOrValue& getResultRef() { return resultRef; } + +private: + Own inner; + ExceptionOrValue& resultRef; + + ForkBranchBase* headBranch = nullptr; + ForkBranchBase** tailBranch = &headBranch; + // Tail becomes null once the inner promise is ready and all branches have been notified. + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + friend class ForkBranchBase; +}; + +template +class ForkHub final: public ForkHubBase { + // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces + // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if + // possible). + +public: + ForkHub(Own&& inner): ForkHubBase(kj::mv(inner), result) {} + + Promise<_::UnfixVoid> addBranch() { + return Promise<_::UnfixVoid>(false, kj::heap>(addRef(*this))); + } + + _::SplitTuplePromise split() { + return splitImpl(MakeIndexes()>()); + } + +private: + ExceptionOr result; + + template + _::SplitTuplePromise splitImpl(Indexes) { + return kj::tuple(addSplit()...); + } + + template + Promise::Element>> addSplit() { + return Promise::Element>>( + false, maybeChain(kj::heap>(addRef(*this)), + implicitCast::Element*>(nullptr))); + } +}; + +inline ExceptionOrValue& ForkBranchBase::getHubResultRef() { + return hub->getResultRef(); +} + +// ------------------------------------------------------------------- + +class ChainPromiseNode final: public PromiseNode, public Event { + // Promise node which reduces Promise> to Promise. + // + // `Event` is only a public base class because otherwise we can't cast Own to + // Own. Ugh, templates and private... + +public: + explicit ChainPromiseNode(Own inner); + ~ChainPromiseNode() noexcept(false); + + void onReady(Event& event) noexcept override; + void setSelfPointer(Own* selfPtr) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + enum State { + STEP1, + STEP2 + }; + + State state; + + Own inner; + // In STEP1, a PromiseNode for a Promise. + // In STEP2, a PromiseNode for a T. + + Event* onReadyEvent = nullptr; + Own* selfPtr = nullptr; + + Maybe> fire() override; +}; + +template +Own maybeChain(Own&& node, Promise*) { + return heap(kj::mv(node)); +} + +template +Own&& maybeChain(Own&& node, T*) { + return kj::mv(node); +} + +// ------------------------------------------------------------------- + +class ExclusiveJoinPromiseNode final: public PromiseNode { +public: + ExclusiveJoinPromiseNode(Own left, Own right); + ~ExclusiveJoinPromiseNode() noexcept(false); + + void onReady(Event& event) noexcept override; + void get(ExceptionOrValue& output) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + class Branch: public Event { + public: + Branch(ExclusiveJoinPromiseNode& joinNode, Own dependency); + ~Branch() noexcept(false); + + bool get(ExceptionOrValue& output); + // Returns true if this is the side that finished. + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + private: + ExclusiveJoinPromiseNode& joinNode; + Own dependency; + }; + + Branch left; + Branch right; + OnReadyEvent onReadyEvent; +}; + +// ------------------------------------------------------------------- + +class ArrayJoinPromiseNodeBase: public PromiseNode { +public: + ArrayJoinPromiseNodeBase(Array> promises, + ExceptionOrValue* resultParts, size_t partSize); + ~ArrayJoinPromiseNodeBase() noexcept(false); + + void onReady(Event& event) noexcept override final; + void get(ExceptionOrValue& output) noexcept override final; + PromiseNode* getInnerForTrace() override final; + +protected: + virtual void getNoError(ExceptionOrValue& output) noexcept = 0; + // Called to compile the result only in the case where there were no errors. + +private: + uint countLeft; + OnReadyEvent onReadyEvent; + + class Branch final: public Event { + public: + Branch(ArrayJoinPromiseNodeBase& joinNode, Own dependency, + ExceptionOrValue& output); + ~Branch() noexcept(false); + + Maybe> fire() override; + _::PromiseNode* getInnerForTrace() override; + + Maybe getPart(); + // Calls dependency->get(output). If there was an exception, return it. + + private: + ArrayJoinPromiseNodeBase& joinNode; + Own dependency; + ExceptionOrValue& output; + }; + + Array branches; +}; + +template +class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { +public: + ArrayJoinPromiseNode(Array> promises, + Array> resultParts) + : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr)), + resultParts(kj::mv(resultParts)) {} + +protected: + void getNoError(ExceptionOrValue& output) noexcept override { + auto builder = heapArrayBuilder(resultParts.size()); + for (auto& part: resultParts) { + KJ_IASSERT(part.value != nullptr, + "Bug in KJ promise framework: Promise result had neither value no exception."); + builder.add(kj::mv(*_::readMaybe(part.value))); + } + output.as>() = builder.finish(); + } + +private: + Array> resultParts; +}; + +template <> +class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase { +public: + ArrayJoinPromiseNode(Array> promises, + Array> resultParts); + ~ArrayJoinPromiseNode(); + +protected: + void getNoError(ExceptionOrValue& output) noexcept override; + +private: + Array> resultParts; +}; + +// ------------------------------------------------------------------- + +class EagerPromiseNodeBase: public PromiseNode, protected Event { + // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly + // evaluate it. + +public: + EagerPromiseNodeBase(Own&& dependency, ExceptionOrValue& resultRef); + + void onReady(Event& event) noexcept override; + PromiseNode* getInnerForTrace() override; + +private: + Own dependency; + OnReadyEvent onReadyEvent; + + ExceptionOrValue& resultRef; + + Maybe> fire() override; +}; + +template +class EagerPromiseNode final: public EagerPromiseNodeBase { +public: + EagerPromiseNode(Own&& dependency) + : EagerPromiseNodeBase(kj::mv(dependency), result) {} + + void get(ExceptionOrValue& output) noexcept override { + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; +}; + +template +Own spark(Own&& node) { + // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting + // on it. + return heap>(kj::mv(node)); +} + +// ------------------------------------------------------------------- + +class AdapterPromiseNodeBase: public PromiseNode { +public: + void onReady(Event& event) noexcept override; + +protected: + inline void setReady() { + onReadyEvent.arm(); + } + +private: + OnReadyEvent onReadyEvent; +}; + +template +class AdapterPromiseNode final: public AdapterPromiseNodeBase, + private PromiseFulfiller> { + // A PromiseNode that wraps a PromiseAdapter. + +public: + template + AdapterPromiseNode(Params&&... params) + : adapter(static_cast>&>(*this), kj::fwd(params)...) {} + + void get(ExceptionOrValue& output) noexcept override { + KJ_IREQUIRE(!isWaiting()); + output.as() = kj::mv(result); + } + +private: + ExceptionOr result; + bool waiting = true; + Adapter adapter; + + void fulfill(T&& value) override { + if (waiting) { + waiting = false; + result = ExceptionOr(kj::mv(value)); + setReady(); + } + } + + void reject(Exception&& exception) override { + if (waiting) { + waiting = false; + result = ExceptionOr(false, kj::mv(exception)); + setReady(); + } + } + + bool isWaiting() override { + return waiting; + } +}; + +} // namespace _ (private) + +// ======================================================================================= + +template +Promise::Promise(_::FixVoid value) + : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid>>(kj::mv(value))) {} + +template +Promise::Promise(kj::Exception&& exception) + : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {} + +template +template +PromiseForResult Promise::then(Func&& func, ErrorFunc&& errorHandler) { + typedef _::FixVoid<_::ReturnType> ResultT; + + Own<_::PromiseNode> intermediate = + heap<_::TransformPromiseNode, Func, ErrorFunc>>( + kj::mv(node), kj::fwd(func), kj::fwd(errorHandler)); + return PromiseForResult(false, + _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); +} + +namespace _ { // private + +template +struct IdentityFunc { + inline T operator()(T&& value) const { + return kj::mv(value); + } +}; +template +struct IdentityFunc> { + inline Promise operator()(T&& value) const { + return kj::mv(value); + } +}; +template <> +struct IdentityFunc { + inline void operator()() const {} +}; +template <> +struct IdentityFunc> { + Promise operator()() const; + // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly, + // Cap'n Proto relies on being able to include this header without creating such a link-time + // dependency. +}; + +} // namespace _ (private) + +template +template +Promise Promise::catch_(ErrorFunc&& errorHandler) { + // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case, + // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise, + // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually + // return a promise. So we make our Func return match ErrorFunc. + return then(_::IdentityFunc()))>(), + kj::fwd(errorHandler)); +} + +template +T Promise::wait(WaitScope& waitScope) { + _::ExceptionOr<_::FixVoid> result; + + waitImpl(kj::mv(node), result, waitScope); + + KJ_IF_MAYBE(value, result.value) { + KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } + return _::returnMaybeVoid(kj::mv(*value)); + } else KJ_IF_MAYBE(exception, result.exception) { + throwFatalException(kj::mv(*exception)); + } else { + // Result contained neither a value nor an exception? + KJ_UNREACHABLE; + } +} + +template <> +inline void Promise::wait(WaitScope& waitScope) { + // Override case to use throwRecoverableException(). + + _::ExceptionOr<_::Void> result; + + waitImpl(kj::mv(node), result, waitScope); + + if (result.value != nullptr) { + KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } + } else KJ_IF_MAYBE(exception, result.exception) { + throwRecoverableException(kj::mv(*exception)); + } else { + // Result contained neither a value nor an exception? + KJ_UNREACHABLE; + } +} + +template +ForkedPromise Promise::fork() { + return ForkedPromise(false, refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))); +} + +template +Promise ForkedPromise::addBranch() { + return hub->addBranch(); +} + +template +_::SplitTuplePromise Promise::split() { + return refcounted<_::ForkHub<_::FixVoid>>(kj::mv(node))->split(); +} + +template +Promise Promise::exclusiveJoin(Promise&& other) { + return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node))); +} + +template +template +Promise Promise::attach(Attachments&&... attachments) { + return Promise(false, kj::heap<_::AttachmentPromiseNode>>( + kj::mv(node), kj::tuple(kj::fwd(attachments)...))); +} + +template +template +Promise Promise::eagerlyEvaluate(ErrorFunc&& errorHandler) { + // See catch_() for commentary. + return Promise(false, _::spark<_::FixVoid>(then( + _::IdentityFunc()))>(), + kj::fwd(errorHandler)).node)); +} + +template +Promise Promise::eagerlyEvaluate(decltype(nullptr)) { + return Promise(false, _::spark<_::FixVoid>(kj::mv(node))); +} + +template +kj::String Promise::trace() { + return PromiseBase::trace(); +} + +template +inline PromiseForResult evalLater(Func&& func) { + return _::yield().then(kj::fwd(func), _::PropagateException()); +} + +template +inline PromiseForResult evalNow(Func&& func) { + PromiseForResult result = nullptr; + KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() { + result = func(); + })) { + result = kj::mv(*e); + } + return result; +} + +template +template +void Promise::detach(ErrorFunc&& errorHandler) { + return _::detach(then([](T&&) {}, kj::fwd(errorHandler))); +} + +template <> +template +void Promise::detach(ErrorFunc&& errorHandler) { + return _::detach(then([]() {}, kj::fwd(errorHandler))); +} + +template +Promise> joinPromises(Array>&& promises) { + return Promise>(false, kj::heap<_::ArrayJoinPromiseNode>( + KJ_MAP(p, promises) { return kj::mv(p.node); }, + heapArray<_::ExceptionOr>(promises.size()))); +} + +// ======================================================================================= + +namespace _ { // private + +template +class WeakFulfiller final: public PromiseFulfiller, private kj::Disposer { + // A wrapper around PromiseFulfiller which can be detached. + // + // There are a couple non-trivialities here: + // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly + // rejected. + // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been + // detached from the underlying fulfiller, because otherwise the later detach() call will go + // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the + // refcount never goes over 2 and we manually implement the refcounting because we need to do + // other special things when each side detaches anyway. To this end, WeakFulfiller is its own + // Disposer -- dispose() is called when the application discards its owned pointer to the + // fulfiller and detach() is called when the promise is destroyed. + +public: + KJ_DISALLOW_COPY(WeakFulfiller); + + static kj::Own make() { + WeakFulfiller* ptr = new WeakFulfiller; + return Own(ptr, *ptr); + } + + void fulfill(FixVoid&& value) override { + if (inner != nullptr) { + inner->fulfill(kj::mv(value)); + } + } + + void reject(Exception&& exception) override { + if (inner != nullptr) { + inner->reject(kj::mv(exception)); + } + } + + bool isWaiting() override { + return inner != nullptr && inner->isWaiting(); + } + + void attach(PromiseFulfiller& newInner) { + inner = &newInner; + } + + void detach(PromiseFulfiller& from) { + if (inner == nullptr) { + // Already disposed. + delete this; + } else { + KJ_IREQUIRE(inner == &from); + inner = nullptr; + } + } + +private: + mutable PromiseFulfiller* inner; + + WeakFulfiller(): inner(nullptr) {} + + void disposeImpl(void* pointer) const override { + // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type? + + if (inner == nullptr) { + // Already detached. + delete this; + } else { + if (inner->isWaiting()) { + inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, + kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise."))); + } + inner = nullptr; + } + } +}; + +template +class PromiseAndFulfillerAdapter { +public: + PromiseAndFulfillerAdapter(PromiseFulfiller& fulfiller, + WeakFulfiller& wrapper) + : fulfiller(fulfiller), wrapper(wrapper) { + wrapper.attach(fulfiller); + } + + ~PromiseAndFulfillerAdapter() noexcept(false) { + wrapper.detach(fulfiller); + } + +private: + PromiseFulfiller& fulfiller; + WeakFulfiller& wrapper; +}; + +} // namespace _ (private) + +template +template +bool PromiseFulfiller::rejectIfThrows(Func&& func) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { + reject(kj::mv(*exception)); + return false; + } else { + return true; + } +} + +template +bool PromiseFulfiller::rejectIfThrows(Func&& func) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) { + reject(kj::mv(*exception)); + return false; + } else { + return true; + } +} + +template +Promise newAdaptedPromise(Params&&... adapterConstructorParams) { + return Promise(false, heap<_::AdapterPromiseNode<_::FixVoid, Adapter>>( + kj::fwd(adapterConstructorParams)...)); +} + +template +PromiseFulfillerPair newPromiseAndFulfiller() { + auto wrapper = _::WeakFulfiller::make(); + + Own<_::PromiseNode> intermediate( + heap<_::AdapterPromiseNode<_::FixVoid, _::PromiseAndFulfillerAdapter>>(*wrapper)); + Promise<_::JoinPromises> promise(false, + _::maybeChain(kj::mv(intermediate), implicitCast(nullptr))); + + return PromiseFulfillerPair { kj::mv(promise), kj::mv(wrapper) }; +} + +} // namespace kj + +#endif // KJ_ASYNC_INL_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-io-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-io-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,381 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "async-io.h" +#include "debug.h" +#include +#include +#if _WIN32 +#include +#include "windows-sanity.h" +#else +#include +#endif + +namespace kj { +namespace { + +TEST(AsyncIo, SimpleNetwork) { + auto ioContext = setupAsyncIo(); + auto& network = ioContext.provider->getNetwork(); + + Own listener; + Own server; + Own client; + + char receiveBuffer[4]; + + auto port = newPromiseAndFulfiller(); + + port.promise.then([&](uint portnum) { + return network.parseAddress("localhost", portnum); + }).then([&](Own&& result) { + return result->connect(); + }).then([&](Own&& result) { + client = kj::mv(result); + return client->write("foo", 3); + }).detach([](kj::Exception&& exception) { + KJ_FAIL_EXPECT(exception); + }); + + kj::String result = network.parseAddress("*").then([&](Own&& result) { + listener = result->listen(); + port.fulfiller->fulfill(listener->getPort()); + return listener->accept(); + }).then([&](Own&& result) { + server = kj::mv(result); + return server->tryRead(receiveBuffer, 3, 4); + }).then([&](size_t n) { + EXPECT_EQ(3u, n); + return heapString(receiveBuffer, n); + }).wait(ioContext.waitScope); + + EXPECT_EQ("foo", result); +} + +String tryParse(WaitScope& waitScope, Network& network, StringPtr text, uint portHint = 0) { + return network.parseAddress(text, portHint).wait(waitScope)->toString(); +} + +bool hasIpv6() { + // Can getaddrinfo() parse ipv6 addresses? This is only true if ipv6 is configured on at least + // one interface. (The loopback interface usually has it even if others don't... but not always.) + struct addrinfo* list; + int status = getaddrinfo("::", nullptr, nullptr, &list); + if (status == 0) { + freeaddrinfo(list); + return true; + } else { + return false; + } +} + +TEST(AsyncIo, AddressParsing) { + auto ioContext = setupAsyncIo(); + auto& w = ioContext.waitScope; + auto& network = ioContext.provider->getNetwork(); + + EXPECT_EQ("*:0", tryParse(w, network, "*")); + EXPECT_EQ("*:123", tryParse(w, network, "*:123")); + EXPECT_EQ("0.0.0.0:0", tryParse(w, network, "0.0.0.0")); + EXPECT_EQ("1.2.3.4:5678", tryParse(w, network, "1.2.3.4", 5678)); + +#if !_WIN32 + EXPECT_EQ("unix:foo/bar/baz", tryParse(w, network, "unix:foo/bar/baz")); +#endif + + // We can parse services by name... +#if !__ANDROID__ // Service names not supported on Android for some reason? + EXPECT_EQ("1.2.3.4:80", tryParse(w, network, "1.2.3.4:http", 5678)); + EXPECT_EQ("*:80", tryParse(w, network, "*:http", 5678)); +#endif + + // IPv6 tests. Annoyingly, these don't work on machines that don't have IPv6 configured on any + // interfaces. + if (hasIpv6()) { + EXPECT_EQ("[::]:123", tryParse(w, network, "0::0", 123)); + EXPECT_EQ("[12ab:cd::34]:321", tryParse(w, network, "[12ab:cd:0::0:34]:321", 432)); +#if !__ANDROID__ // Service names not supported on Android for some reason? + EXPECT_EQ("[::]:80", tryParse(w, network, "[::]:http", 5678)); + EXPECT_EQ("[12ab:cd::34]:80", tryParse(w, network, "[12ab:cd::34]:http", 5678)); +#endif + } + + // It would be nice to test DNS lookup here but the test would not be very hermetic. Even + // localhost can map to different addresses depending on whether IPv6 is enabled. We do + // connect to "localhost" in a different test, though. +} + +TEST(AsyncIo, OneWayPipe) { + auto ioContext = setupAsyncIo(); + + auto pipe = ioContext.provider->newOneWayPipe(); + char receiveBuffer[4]; + + pipe.out->write("foo", 3).detach([](kj::Exception&& exception) { + KJ_FAIL_EXPECT(exception); + }); + + kj::String result = pipe.in->tryRead(receiveBuffer, 3, 4).then([&](size_t n) { + EXPECT_EQ(3u, n); + return heapString(receiveBuffer, n); + }).wait(ioContext.waitScope); + + EXPECT_EQ("foo", result); +} + +TEST(AsyncIo, TwoWayPipe) { + auto ioContext = setupAsyncIo(); + + auto pipe = ioContext.provider->newTwoWayPipe(); + char receiveBuffer1[4]; + char receiveBuffer2[4]; + + auto promise = pipe.ends[0]->write("foo", 3).then([&]() { + return pipe.ends[0]->tryRead(receiveBuffer1, 3, 4); + }).then([&](size_t n) { + EXPECT_EQ(3u, n); + return heapString(receiveBuffer1, n); + }); + + kj::String result = pipe.ends[1]->write("bar", 3).then([&]() { + return pipe.ends[1]->tryRead(receiveBuffer2, 3, 4); + }).then([&](size_t n) { + EXPECT_EQ(3u, n); + return heapString(receiveBuffer2, n); + }).wait(ioContext.waitScope); + + kj::String result2 = promise.wait(ioContext.waitScope); + + EXPECT_EQ("foo", result); + EXPECT_EQ("bar", result2); +} + +TEST(AsyncIo, PipeThread) { + auto ioContext = setupAsyncIo(); + + auto pipeThread = ioContext.provider->newPipeThread( + [](AsyncIoProvider& ioProvider, AsyncIoStream& stream, WaitScope& waitScope) { + char buf[4]; + stream.write("foo", 3).wait(waitScope); + EXPECT_EQ(3u, stream.tryRead(buf, 3, 4).wait(waitScope)); + EXPECT_EQ("bar", heapString(buf, 3)); + + // Expect disconnect. + EXPECT_EQ(0, stream.tryRead(buf, 1, 1).wait(waitScope)); + }); + + char buf[4]; + pipeThread.pipe->write("bar", 3).wait(ioContext.waitScope); + EXPECT_EQ(3u, pipeThread.pipe->tryRead(buf, 3, 4).wait(ioContext.waitScope)); + EXPECT_EQ("foo", heapString(buf, 3)); +} + +TEST(AsyncIo, PipeThreadDisconnects) { + // Like above, but in this case we expect the main thread to detect the pipe thread disconnecting. + + auto ioContext = setupAsyncIo(); + + auto pipeThread = ioContext.provider->newPipeThread( + [](AsyncIoProvider& ioProvider, AsyncIoStream& stream, WaitScope& waitScope) { + char buf[4]; + stream.write("foo", 3).wait(waitScope); + EXPECT_EQ(3u, stream.tryRead(buf, 3, 4).wait(waitScope)); + EXPECT_EQ("bar", heapString(buf, 3)); + }); + + char buf[4]; + EXPECT_EQ(3u, pipeThread.pipe->tryRead(buf, 3, 4).wait(ioContext.waitScope)); + EXPECT_EQ("foo", heapString(buf, 3)); + + pipeThread.pipe->write("bar", 3).wait(ioContext.waitScope); + + // Expect disconnect. + EXPECT_EQ(0, pipeThread.pipe->tryRead(buf, 1, 1).wait(ioContext.waitScope)); +} + +TEST(AsyncIo, Timeouts) { + auto ioContext = setupAsyncIo(); + + Timer& timer = ioContext.provider->getTimer(); + + auto promise1 = timer.timeoutAfter(10 * MILLISECONDS, kj::Promise(kj::NEVER_DONE)); + auto promise2 = timer.timeoutAfter(100 * MILLISECONDS, kj::Promise(123)); + + EXPECT_TRUE(promise1.then([]() { return false; }, [](kj::Exception&& e) { return true; }) + .wait(ioContext.waitScope)); + EXPECT_EQ(123, promise2.wait(ioContext.waitScope)); +} + +#if !_WIN32 // datagrams not implemented on win32 yet + +TEST(AsyncIo, Udp) { + auto ioContext = setupAsyncIo(); + + auto addr = ioContext.provider->getNetwork().parseAddress("127.0.0.1").wait(ioContext.waitScope); + + auto port1 = addr->bindDatagramPort(); + auto port2 = addr->bindDatagramPort(); + + auto addr1 = ioContext.provider->getNetwork().parseAddress("127.0.0.1", port1->getPort()) + .wait(ioContext.waitScope); + auto addr2 = ioContext.provider->getNetwork().parseAddress("127.0.0.1", port2->getPort()) + .wait(ioContext.waitScope); + + Own receivedAddr; + + { + // Send a message and receive it. + EXPECT_EQ(3, port1->send("foo", 3, *addr2).wait(ioContext.waitScope)); + auto receiver = port2->makeReceiver(); + + receiver->receive().wait(ioContext.waitScope); + { + auto content = receiver->getContent(); + EXPECT_EQ("foo", kj::heapString(content.value.asChars())); + EXPECT_FALSE(content.isTruncated); + } + receivedAddr = receiver->getSource().clone(); + EXPECT_EQ(addr1->toString(), receivedAddr->toString()); + { + auto ancillary = receiver->getAncillary(); + EXPECT_EQ(0, ancillary.value.size()); + EXPECT_FALSE(ancillary.isTruncated); + } + + // Receive a second message with the same receiver. + { + auto promise = receiver->receive(); // This time, start receiving before sending + EXPECT_EQ(6, port1->send("barbaz", 6, *addr2).wait(ioContext.waitScope)); + promise.wait(ioContext.waitScope); + auto content = receiver->getContent(); + EXPECT_EQ("barbaz", kj::heapString(content.value.asChars())); + EXPECT_FALSE(content.isTruncated); + } + } + + DatagramReceiver::Capacity capacity; + capacity.content = 8; + capacity.ancillary = 1024; + + { + // Send a reply that will be truncated. + EXPECT_EQ(16, port2->send("0123456789abcdef", 16, *receivedAddr).wait(ioContext.waitScope)); + auto recv1 = port1->makeReceiver(capacity); + + recv1->receive().wait(ioContext.waitScope); + { + auto content = recv1->getContent(); + EXPECT_EQ("01234567", kj::heapString(content.value.asChars())); + EXPECT_TRUE(content.isTruncated); + } + EXPECT_EQ(addr2->toString(), recv1->getSource().toString()); + { + auto ancillary = recv1->getAncillary(); + EXPECT_EQ(0, ancillary.value.size()); + EXPECT_FALSE(ancillary.isTruncated); + } + +#if defined(IP_PKTINFO) && !__CYGWIN__ + // Set IP_PKTINFO header and try to receive it. + // Doesn't work on Cygwin; see: https://cygwin.com/ml/cygwin/2009-01/msg00350.html + // TODO(someday): Might work on more-recent Cygwin; I'm still testing against 1.7. + int one = 1; + port1->setsockopt(IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + + EXPECT_EQ(3, port2->send("foo", 3, *addr1).wait(ioContext.waitScope)); + + recv1->receive().wait(ioContext.waitScope); + { + auto content = recv1->getContent(); + EXPECT_EQ("foo", kj::heapString(content.value.asChars())); + EXPECT_FALSE(content.isTruncated); + } + EXPECT_EQ(addr2->toString(), recv1->getSource().toString()); + { + auto ancillary = recv1->getAncillary(); + EXPECT_FALSE(ancillary.isTruncated); + ASSERT_EQ(1, ancillary.value.size()); + + auto message = ancillary.value[0]; + EXPECT_EQ(IPPROTO_IP, message.getLevel()); + EXPECT_EQ(IP_PKTINFO, message.getType()); + EXPECT_EQ(sizeof(struct in_pktinfo), message.asArray().size()); + auto& pktinfo = KJ_ASSERT_NONNULL(message.as()); + EXPECT_EQ(htonl(0x7F000001), pktinfo.ipi_addr.s_addr); // 127.0.0.1 + } + + // See what happens if there's not quite enough space for in_pktinfo. + capacity.ancillary = CMSG_SPACE(sizeof(struct in_pktinfo)) - 8; + recv1 = port1->makeReceiver(capacity); + + EXPECT_EQ(3, port2->send("bar", 3, *addr1).wait(ioContext.waitScope)); + + recv1->receive().wait(ioContext.waitScope); + { + auto content = recv1->getContent(); + EXPECT_EQ("bar", kj::heapString(content.value.asChars())); + EXPECT_FALSE(content.isTruncated); + } + EXPECT_EQ(addr2->toString(), recv1->getSource().toString()); + { + auto ancillary = recv1->getAncillary(); + EXPECT_TRUE(ancillary.isTruncated); + + // We might get a message, but it will be truncated. + if (ancillary.value.size() != 0) { + EXPECT_EQ(1, ancillary.value.size()); + + auto message = ancillary.value[0]; + EXPECT_EQ(IPPROTO_IP, message.getLevel()); + EXPECT_EQ(IP_PKTINFO, message.getType()); + + EXPECT_TRUE(message.as() == nullptr); + EXPECT_LT(message.asArray().size(), sizeof(struct in_pktinfo)); + } + } + + // See what happens if there's not enough space even for the cmsghdr. + capacity.ancillary = CMSG_SPACE(0) - 8; + recv1 = port1->makeReceiver(capacity); + + EXPECT_EQ(3, port2->send("baz", 3, *addr1).wait(ioContext.waitScope)); + + recv1->receive().wait(ioContext.waitScope); + { + auto content = recv1->getContent(); + EXPECT_EQ("baz", kj::heapString(content.value.asChars())); + EXPECT_FALSE(content.isTruncated); + } + EXPECT_EQ(addr2->toString(), recv1->getSource().toString()); + { + auto ancillary = recv1->getAncillary(); + EXPECT_TRUE(ancillary.isTruncated); + EXPECT_EQ(0, ancillary.value.size()); + } +#endif + } +} + +#endif // !_WIN32 + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-io-unix.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-io-unix.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1331 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !_WIN32 +// For Win32 implementation, see async-io-win32.c++. + +#include "async-io.h" +#include "async-unix.h" +#include "debug.h" +#include "thread.h" +#include "io.h" +#include "miniposix.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kj { + +namespace { + +void setNonblocking(int fd) { + int flags; + KJ_SYSCALL(flags = fcntl(fd, F_GETFL)); + if ((flags & O_NONBLOCK) == 0) { + KJ_SYSCALL(fcntl(fd, F_SETFL, flags | O_NONBLOCK)); + } +} + +void setCloseOnExec(int fd) { + int flags; + KJ_SYSCALL(flags = fcntl(fd, F_GETFD)); + if ((flags & FD_CLOEXEC) == 0) { + KJ_SYSCALL(fcntl(fd, F_SETFD, flags | FD_CLOEXEC)); + } +} + +static constexpr uint NEW_FD_FLAGS = +#if __linux__ && !__BIONIC__ + LowLevelAsyncIoProvider::ALREADY_CLOEXEC | LowLevelAsyncIoProvider::ALREADY_NONBLOCK | +#endif + LowLevelAsyncIoProvider::TAKE_OWNERSHIP; +// We always try to open FDs with CLOEXEC and NONBLOCK already set on Linux, but on other platforms +// this is not possible. + +class OwnedFileDescriptor { +public: + OwnedFileDescriptor(int fd, uint flags): fd(fd), flags(flags) { + if (flags & LowLevelAsyncIoProvider::ALREADY_NONBLOCK) { + KJ_DREQUIRE(fcntl(fd, F_GETFL) & O_NONBLOCK, "You claimed you set NONBLOCK, but you didn't."); + } else { + setNonblocking(fd); + } + + if (flags & LowLevelAsyncIoProvider::TAKE_OWNERSHIP) { + if (flags & LowLevelAsyncIoProvider::ALREADY_CLOEXEC) { + KJ_DREQUIRE(fcntl(fd, F_GETFD) & FD_CLOEXEC, + "You claimed you set CLOEXEC, but you didn't."); + } else { + setCloseOnExec(fd); + } + } + } + + ~OwnedFileDescriptor() noexcept(false) { + // Don't use SYSCALL() here because close() should not be repeated on EINTR. + if ((flags & LowLevelAsyncIoProvider::TAKE_OWNERSHIP) && close(fd) < 0) { + KJ_FAIL_SYSCALL("close", errno, fd) { + // Recoverable exceptions are safe in destructors. + break; + } + } + } + +protected: + const int fd; + +private: + uint flags; +}; + +// ======================================================================================= + +class AsyncStreamFd: public OwnedFileDescriptor, public AsyncIoStream { +public: + AsyncStreamFd(UnixEventPort& eventPort, int fd, uint flags) + : OwnedFileDescriptor(fd, flags), + observer(eventPort, fd, UnixEventPort::FdObserver::OBSERVE_READ_WRITE) {} + virtual ~AsyncStreamFd() noexcept(false) {} + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + return tryReadInternal(buffer, minBytes, maxBytes, 0); + } + + Promise write(const void* buffer, size_t size) override { + ssize_t writeResult; + KJ_NONBLOCKING_SYSCALL(writeResult = ::write(fd, buffer, size)) { + // Error. + + // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to + // a bug that exists in both Clang and GCC: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799 + // http://llvm.org/bugs/show_bug.cgi?id=12286 + goto error; + } + if (false) { + error: + return kj::READY_NOW; + } + + // A negative result means EAGAIN, which we can treat the same as having written zero bytes. + size_t n = writeResult < 0 ? 0 : writeResult; + + if (n == size) { + return READY_NOW; + } + + // Fewer than `size` bytes were written, therefore we must be out of buffer space. Wait until + // the fd becomes writable again. + buffer = reinterpret_cast(buffer) + n; + size -= n; + + return observer.whenBecomesWritable().then([=]() { + return write(buffer, size); + }); + } + + Promise write(ArrayPtr> pieces) override { + if (pieces.size() == 0) { + return writeInternal(nullptr, nullptr); + } else { + return writeInternal(pieces[0], pieces.slice(1, pieces.size())); + } + } + + void shutdownWrite() override { + // There's no legitimate way to get an AsyncStreamFd that isn't a socket through the + // UnixAsyncIoProvider interface. + KJ_SYSCALL(shutdown(fd, SHUT_WR)); + } + + void abortRead() override { + // There's no legitimate way to get an AsyncStreamFd that isn't a socket through the + // UnixAsyncIoProvider interface. + KJ_SYSCALL(shutdown(fd, SHUT_RD)); + } + + void getsockopt(int level, int option, void* value, uint* length) override { + socklen_t socklen = *length; + KJ_SYSCALL(::getsockopt(fd, level, option, value, &socklen)); + *length = socklen; + } + + void setsockopt(int level, int option, const void* value, uint length) override { + KJ_SYSCALL(::setsockopt(fd, level, option, value, length)); + } + + void getsockname(struct sockaddr* addr, uint* length) override { + socklen_t socklen = *length; + KJ_SYSCALL(::getsockname(fd, addr, &socklen)); + *length = socklen; + } + + void getpeername(struct sockaddr* addr, uint* length) override { + socklen_t socklen = *length; + KJ_SYSCALL(::getpeername(fd, addr, &socklen)); + *length = socklen; + } + + Promise waitConnected() { + // Wait until initial connection has completed. This actually just waits until it is writable. + + // Can't just go directly to writeObserver.whenBecomesWritable() because of edge triggering. We + // need to explicitly check if the socket is already connected. + + struct pollfd pollfd; + memset(&pollfd, 0, sizeof(pollfd)); + pollfd.fd = fd; + pollfd.events = POLLOUT; + + int pollResult; + KJ_SYSCALL(pollResult = poll(&pollfd, 1, 0)); + + if (pollResult == 0) { + // Not ready yet. We can safely use the edge-triggered observer. + return observer.whenBecomesWritable(); + } else { + // Ready now. + return kj::READY_NOW; + } + } + +private: + UnixEventPort::FdObserver observer; + + Promise tryReadInternal(void* buffer, size_t minBytes, size_t maxBytes, + size_t alreadyRead) { + // `alreadyRead` is the number of bytes we have already received via previous reads -- minBytes, + // maxBytes, and buffer have already been adjusted to account for them, but this count must + // be included in the final return value. + + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = ::read(fd, buffer, maxBytes)) { + // Error. + + // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to + // a bug that exists in both Clang and GCC: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799 + // http://llvm.org/bugs/show_bug.cgi?id=12286 + goto error; + } + if (false) { + error: + return alreadyRead; + } + + if (n < 0) { + // Read would block. + return observer.whenBecomesReadable().then([=]() { + return tryReadInternal(buffer, minBytes, maxBytes, alreadyRead); + }); + } else if (n == 0) { + // EOF -OR- maxBytes == 0. + return alreadyRead; + } else if (implicitCast(n) >= minBytes) { + // We read enough to stop here. + return alreadyRead + n; + } else { + // The kernel returned fewer bytes than we asked for (and fewer than we need). + + buffer = reinterpret_cast(buffer) + n; + minBytes -= n; + maxBytes -= n; + alreadyRead += n; + + KJ_IF_MAYBE(atEnd, observer.atEndHint()) { + if (*atEnd) { + // We've already received an indication that the next read() will return EOF, so there's + // nothing to wait for. + return alreadyRead; + } else { + // As of the last time the event queue was checked, the kernel reported that we were + // *not* at the end of the stream. It's unlikely that this has changed in the short time + // it took to handle the event, therefore calling read() now will almost certainly fail + // with EAGAIN. Moreover, since EOF had not been received as of the last check, we know + // that even if it was received since then, whenBecomesReadable() will catch that. So, + // let's go ahead and skip calling read() here and instead go straight to waiting for + // more input. + return observer.whenBecomesReadable().then([=]() { + return tryReadInternal(buffer, minBytes, maxBytes, alreadyRead); + }); + } + } else { + // The kernel has not indicated one way or the other whether we are likely to be at EOF. + // In this case we *must* keep calling read() until we either get a return of zero or + // EAGAIN. + return tryReadInternal(buffer, minBytes, maxBytes, alreadyRead); + } + } + } + + Promise writeInternal(ArrayPtr firstPiece, + ArrayPtr> morePieces) { + const size_t iovmax = kj::miniposix::iovMax(1 + morePieces.size()); + // If there are more than IOV_MAX pieces, we'll only write the first IOV_MAX for now, and + // then we'll loop later. + KJ_STACK_ARRAY(struct iovec, iov, kj::min(1 + morePieces.size(), iovmax), 16, 128); + size_t iovTotal = 0; + + // writev() interface is not const-correct. :( + iov[0].iov_base = const_cast(firstPiece.begin()); + iov[0].iov_len = firstPiece.size(); + iovTotal += iov[0].iov_len; + for (uint i = 1; i < iov.size(); i++) { + iov[i].iov_base = const_cast(morePieces[i - 1].begin()); + iov[i].iov_len = morePieces[i - 1].size(); + iovTotal += iov[i].iov_len; + } + + ssize_t writeResult; + KJ_NONBLOCKING_SYSCALL(writeResult = ::writev(fd, iov.begin(), iov.size())) { + // Error. + + // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to + // a bug that exists in both Clang and GCC: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799 + // http://llvm.org/bugs/show_bug.cgi?id=12286 + goto error; + } + if (false) { + error: + return kj::READY_NOW; + } + + // A negative result means EAGAIN, which we can treat the same as having written zero bytes. + size_t n = writeResult < 0 ? 0 : writeResult; + + // Discard all data that was written, then issue a new write for what's left (if any). + for (;;) { + if (n < firstPiece.size()) { + // Only part of the first piece was consumed. Wait for buffer space and then write again. + firstPiece = firstPiece.slice(n, firstPiece.size()); + iovTotal -= n; + + if (iovTotal == 0) { + // Oops, what actually happened is that we hit the IOV_MAX limit. Don't wait. + return writeInternal(firstPiece, morePieces); + } + + return observer.whenBecomesWritable().then([=]() { + return writeInternal(firstPiece, morePieces); + }); + } else if (morePieces.size() == 0) { + // First piece was fully-consumed and there are no more pieces, so we're done. + KJ_DASSERT(n == firstPiece.size(), n); + return READY_NOW; + } else { + // First piece was fully consumed, so move on to the next piece. + n -= firstPiece.size(); + iovTotal -= firstPiece.size(); + firstPiece = morePieces[0]; + morePieces = morePieces.slice(1, morePieces.size()); + } + } + } +}; + +// ======================================================================================= + +class SocketAddress { +public: + SocketAddress(const void* sockaddr, uint len): addrlen(len) { + KJ_REQUIRE(len <= sizeof(addr), "Sorry, your sockaddr is too big for me."); + memcpy(&addr.generic, sockaddr, len); + } + + bool operator<(const SocketAddress& other) const { + // So we can use std::set... see DNS lookup code. + + if (wildcard < other.wildcard) return true; + if (wildcard > other.wildcard) return false; + + if (addrlen < other.addrlen) return true; + if (addrlen > other.addrlen) return false; + + return memcmp(&addr.generic, &other.addr.generic, addrlen) < 0; + } + + const struct sockaddr* getRaw() const { return &addr.generic; } + socklen_t getRawSize() const { return addrlen; } + + int socket(int type) const { + bool isStream = type == SOCK_STREAM; + + int result; +#if __linux__ && !__BIONIC__ + type |= SOCK_NONBLOCK | SOCK_CLOEXEC; +#endif + KJ_SYSCALL(result = ::socket(addr.generic.sa_family, type, 0)); + + if (isStream && (addr.generic.sa_family == AF_INET || + addr.generic.sa_family == AF_INET6)) { + // TODO(perf): As a hack for the 0.4 release we are always setting + // TCP_NODELAY because Nagle's algorithm pretty much kills Cap'n Proto's + // RPC protocol. Later, we should extend the interface to provide more + // control over this. Perhaps write() should have a flag which + // specifies whether to pass MSG_MORE. + int one = 1; + KJ_SYSCALL(setsockopt( + result, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one))); + } + + return result; + } + + void bind(int sockfd) const { +#if !defined(__OpenBSD__) + if (wildcard) { + // Disable IPV6_V6ONLY because we want to handle both ipv4 and ipv6 on this socket. (The + // default value of this option varies across platforms.) + int value = 0; + KJ_SYSCALL(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value))); + } +#endif + + KJ_SYSCALL(::bind(sockfd, &addr.generic, addrlen), toString()); + } + + uint getPort() const { + switch (addr.generic.sa_family) { + case AF_INET: return ntohs(addr.inet4.sin_port); + case AF_INET6: return ntohs(addr.inet6.sin6_port); + default: return 0; + } + } + + String toString() const { + if (wildcard) { + return str("*:", getPort()); + } + + switch (addr.generic.sa_family) { + case AF_INET: { + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(addr.inet4.sin_family, &addr.inet4.sin_addr, + buffer, sizeof(buffer)) == nullptr) { + KJ_FAIL_SYSCALL("inet_ntop", errno) { break; } + return heapString("(inet_ntop error)"); + } + return str(buffer, ':', ntohs(addr.inet4.sin_port)); + } + case AF_INET6: { + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(addr.inet6.sin6_family, &addr.inet6.sin6_addr, + buffer, sizeof(buffer)) == nullptr) { + KJ_FAIL_SYSCALL("inet_ntop", errno) { break; } + return heapString("(inet_ntop error)"); + } + return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port)); + } + case AF_UNIX: { + return str("unix:", addr.unixDomain.sun_path); + } + default: + return str("(unknown address family ", addr.generic.sa_family, ")"); + } + } + + static Promise> lookupHost( + LowLevelAsyncIoProvider& lowLevel, kj::String host, kj::String service, uint portHint); + // Perform a DNS lookup. + + static Promise> parse( + LowLevelAsyncIoProvider& lowLevel, StringPtr str, uint portHint) { + // TODO(someday): Allow commas in `str`. + + SocketAddress result; + + if (str.startsWith("unix:")) { + StringPtr path = str.slice(strlen("unix:")); + KJ_REQUIRE(path.size() < sizeof(addr.unixDomain.sun_path), + "Unix domain socket address is too long.", str); + result.addr.unixDomain.sun_family = AF_UNIX; + strcpy(result.addr.unixDomain.sun_path, path.cStr()); + result.addrlen = offsetof(struct sockaddr_un, sun_path) + path.size() + 1; + auto array = kj::heapArrayBuilder(1); + array.add(result); + return array.finish(); + } + + // Try to separate the address and port. + ArrayPtr addrPart; + Maybe portPart; + + int af; + + if (str.startsWith("[")) { + // Address starts with a bracket, which is a common way to write an ip6 address with a port, + // since without brackets around the address part, the port looks like another segment of + // the address. + af = AF_INET6; + size_t closeBracket = KJ_ASSERT_NONNULL(str.findLast(']'), + "Unclosed '[' in address string.", str); + + addrPart = str.slice(1, closeBracket); + if (str.size() > closeBracket + 1) { + KJ_REQUIRE(str.slice(closeBracket + 1).startsWith(":"), + "Expected port suffix after ']'.", str); + portPart = str.slice(closeBracket + 2); + } + } else { + KJ_IF_MAYBE(colon, str.findFirst(':')) { + if (str.slice(*colon + 1).findFirst(':') == nullptr) { + // There is exactly one colon and no brackets, so it must be an ip4 address with port. + af = AF_INET; + addrPart = str.slice(0, *colon); + portPart = str.slice(*colon + 1); + } else { + // There are two or more colons and no brackets, so the whole thing must be an ip6 + // address with no port. + af = AF_INET6; + addrPart = str; + } + } else { + // No colons, so it must be an ip4 address without port. + af = AF_INET; + addrPart = str; + } + } + + // Parse the port. + unsigned long port; + KJ_IF_MAYBE(portText, portPart) { + char* endptr; + port = strtoul(portText->cStr(), &endptr, 0); + if (portText->size() == 0 || *endptr != '\0') { + // Not a number. Maybe it's a service name. Fall back to DNS. + return lookupHost(lowLevel, kj::heapString(addrPart), kj::heapString(*portText), portHint); + } + KJ_REQUIRE(port < 65536, "Port number too large."); + } else { + port = portHint; + } + + // Check for wildcard. + if (addrPart.size() == 1 && addrPart[0] == '*') { + result.wildcard = true; +#if defined(__OpenBSD__) + // On OpenBSD, all sockets are either v4-only or v6-only, so use v4 as a + // temporary workaround for wildcards. + result.addrlen = sizeof(addr.inet4); + result.addr.inet4.sin_family = AF_INET; + result.addr.inet4.sin_port = htons(port); +#else + // Create an ip6 socket and set IPV6_V6ONLY to 0 later. + result.addrlen = sizeof(addr.inet6); + result.addr.inet6.sin6_family = AF_INET6; + result.addr.inet6.sin6_port = htons(port); +#endif + auto array = kj::heapArrayBuilder(1); + array.add(result); + return array.finish(); + } + + void* addrTarget; + if (af == AF_INET6) { + result.addrlen = sizeof(addr.inet6); + result.addr.inet6.sin6_family = AF_INET6; + result.addr.inet6.sin6_port = htons(port); + addrTarget = &result.addr.inet6.sin6_addr; + } else { + result.addrlen = sizeof(addr.inet4); + result.addr.inet4.sin_family = AF_INET; + result.addr.inet4.sin_port = htons(port); + addrTarget = &result.addr.inet4.sin_addr; + } + + // addrPart is not necessarily NUL-terminated so we have to make a copy. :( + KJ_REQUIRE(addrPart.size() < INET6_ADDRSTRLEN - 1, "IP address too long.", addrPart); + char buffer[INET6_ADDRSTRLEN]; + memcpy(buffer, addrPart.begin(), addrPart.size()); + buffer[addrPart.size()] = '\0'; + + // OK, parse it! + switch (inet_pton(af, buffer, addrTarget)) { + case 1: { + // success. + auto array = kj::heapArrayBuilder(1); + array.add(result); + return array.finish(); + } + case 0: + // It's apparently not a simple address... fall back to DNS. + return lookupHost(lowLevel, kj::heapString(addrPart), nullptr, port); + default: + KJ_FAIL_SYSCALL("inet_pton", errno, af, addrPart); + } + } + + static SocketAddress getLocalAddress(int sockfd) { + SocketAddress result; + result.addrlen = sizeof(addr); + KJ_SYSCALL(getsockname(sockfd, &result.addr.generic, &result.addrlen)); + return result; + } + +private: + SocketAddress(): addrlen(0) { + memset(&addr, 0, sizeof(addr)); + } + + socklen_t addrlen; + bool wildcard = false; + union { + struct sockaddr generic; + struct sockaddr_in inet4; + struct sockaddr_in6 inet6; + struct sockaddr_un unixDomain; + struct sockaddr_storage storage; + } addr; + + struct LookupParams; + class LookupReader; +}; + +class SocketAddress::LookupReader { + // Reads SocketAddresses off of a pipe coming from another thread that is performing + // getaddrinfo. + +public: + LookupReader(kj::Own&& thread, kj::Own&& input) + : thread(kj::mv(thread)), input(kj::mv(input)) {} + + ~LookupReader() { + if (thread) thread->detach(); + } + + Promise> read() { + return input->tryRead(¤t, sizeof(current), sizeof(current)).then( + [this](size_t n) -> Promise> { + if (n < sizeof(current)) { + thread = nullptr; + // getaddrinfo()'s docs seem to say it will never return an empty list, but let's check + // anyway. + KJ_REQUIRE(addresses.size() > 0, "DNS lookup returned no addresses.") { break; } + return addresses.releaseAsArray(); + } else { + // getaddrinfo() can return multiple copies of the same address for several reasons. + // A major one is that we don't give it a socket type (SOCK_STREAM vs. SOCK_DGRAM), so + // it may return two copies of the same address, one for each type, unless it explicitly + // knows that the service name given is specific to one type. But we can't tell it a type, + // because we don't actually know which one the user wants, and if we specify SOCK_STREAM + // while the user specified a UDP service name then they'll get a resolution error which + // is lame. (At least, I think that's how it works.) + // + // So we instead resort to de-duping results. + if (alreadySeen.insert(current).second) { + addresses.add(current); + } + return read(); + } + }); + } + +private: + kj::Own thread; + kj::Own input; + SocketAddress current; + kj::Vector addresses; + std::set alreadySeen; +}; + +struct SocketAddress::LookupParams { + kj::String host; + kj::String service; +}; + +Promise> SocketAddress::lookupHost( + LowLevelAsyncIoProvider& lowLevel, kj::String host, kj::String service, uint portHint) { + // This shitty function spawns a thread to run getaddrinfo(). Unfortunately, getaddrinfo() is + // the only cross-platform DNS API and it is blocking. + // + // TODO(perf): Use a thread pool? Maybe kj::Thread should use a thread pool automatically? + // Maybe use the various platform-specific asynchronous DNS libraries? Please do not implement + // a custom DNS resolver... + + int fds[2]; +#if __linux__ && !__BIONIC__ + KJ_SYSCALL(pipe2(fds, O_NONBLOCK | O_CLOEXEC)); +#else + KJ_SYSCALL(pipe(fds)); +#endif + + auto input = lowLevel.wrapInputFd(fds[0], NEW_FD_FLAGS); + + int outFd = fds[1]; + + LookupParams params = { kj::mv(host), kj::mv(service) }; + + auto thread = heap(kj::mvCapture(params, [outFd,portHint](LookupParams&& params) { + FdOutputStream output((AutoCloseFd(outFd))); + + struct addrinfo* list; + int status = getaddrinfo( + params.host == "*" ? nullptr : params.host.cStr(), + params.service == nullptr ? nullptr : params.service.cStr(), + nullptr, &list); + if (status == 0) { + KJ_DEFER(freeaddrinfo(list)); + + struct addrinfo* cur = list; + while (cur != nullptr) { + if (params.service == nullptr) { + switch (cur->ai_addr->sa_family) { + case AF_INET: + ((struct sockaddr_in*)cur->ai_addr)->sin_port = htons(portHint); + break; + case AF_INET6: + ((struct sockaddr_in6*)cur->ai_addr)->sin6_port = htons(portHint); + break; + default: + break; + } + } + + SocketAddress addr; + memset(&addr, 0, sizeof(addr)); // mollify valgrind + if (params.host == "*") { + // Set up a wildcard SocketAddress. Only use the port number returned by getaddrinfo(). + addr.wildcard = true; + addr.addrlen = sizeof(addr.addr.inet6); + addr.addr.inet6.sin6_family = AF_INET6; + switch (cur->ai_addr->sa_family) { + case AF_INET: + addr.addr.inet6.sin6_port = ((struct sockaddr_in*)cur->ai_addr)->sin_port; + break; + case AF_INET6: + addr.addr.inet6.sin6_port = ((struct sockaddr_in6*)cur->ai_addr)->sin6_port; + break; + default: + addr.addr.inet6.sin6_port = portHint; + break; + } + } else { + addr.addrlen = cur->ai_addrlen; + memcpy(&addr.addr.generic, cur->ai_addr, cur->ai_addrlen); + } + KJ_ASSERT_CAN_MEMCPY(SocketAddress); + output.write(&addr, sizeof(addr)); + cur = cur->ai_next; + } + } else if (status == EAI_SYSTEM) { + KJ_FAIL_SYSCALL("getaddrinfo", errno, params.host, params.service) { + return; + } + } else { + KJ_FAIL_REQUIRE("DNS lookup failed.", + params.host, params.service, gai_strerror(status)) { + return; + } + } + })); + + auto reader = heap(kj::mv(thread), kj::mv(input)); + return reader->read().attach(kj::mv(reader)); +} + +// ======================================================================================= + +class FdConnectionReceiver final: public ConnectionReceiver, public OwnedFileDescriptor { +public: + FdConnectionReceiver(UnixEventPort& eventPort, int fd, uint flags) + : OwnedFileDescriptor(fd, flags), eventPort(eventPort), + observer(eventPort, fd, UnixEventPort::FdObserver::OBSERVE_READ) {} + + Promise> accept() override { + int newFd; + + retry: +#if __linux__ && !__BIONIC__ + newFd = ::accept4(fd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC); +#else + newFd = ::accept(fd, nullptr, nullptr); +#endif + + if (newFd >= 0) { + return Own(heap(eventPort, newFd, NEW_FD_FLAGS)); + } else { + int error = errno; + + switch (error) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + // Not ready yet. + return observer.whenBecomesReadable().then([this]() { + return accept(); + }); + + case EINTR: + case ENETDOWN: +#ifdef EPROTO + // EPROTO is not defined on OpenBSD. + case EPROTO: +#endif + case EHOSTDOWN: + case EHOSTUNREACH: + case ENETUNREACH: + case ECONNABORTED: + case ETIMEDOUT: + // According to the Linux man page, accept() may report an error if the accepted + // connection is already broken. In this case, we really ought to just ignore it and + // keep waiting. But it's hard to say exactly what errors are such network errors and + // which ones are permanent errors. We've made a guess here. + goto retry; + + default: + KJ_FAIL_SYSCALL("accept", error); + } + + } + } + + uint getPort() override { + return SocketAddress::getLocalAddress(fd).getPort(); + } + + void getsockopt(int level, int option, void* value, uint* length) override { + socklen_t socklen = *length; + KJ_SYSCALL(::getsockopt(fd, level, option, value, &socklen)); + *length = socklen; + } + void setsockopt(int level, int option, const void* value, uint length) override { + KJ_SYSCALL(::setsockopt(fd, level, option, value, length)); + } + +public: + UnixEventPort& eventPort; + UnixEventPort::FdObserver observer; +}; + +class DatagramPortImpl final: public DatagramPort, public OwnedFileDescriptor { +public: + DatagramPortImpl(LowLevelAsyncIoProvider& lowLevel, UnixEventPort& eventPort, int fd, uint flags) + : OwnedFileDescriptor(fd, flags), lowLevel(lowLevel), eventPort(eventPort), + observer(eventPort, fd, UnixEventPort::FdObserver::OBSERVE_READ | + UnixEventPort::FdObserver::OBSERVE_WRITE) {} + + Promise send(const void* buffer, size_t size, NetworkAddress& destination) override; + Promise send( + ArrayPtr> pieces, NetworkAddress& destination) override; + + class ReceiverImpl; + + Own makeReceiver(DatagramReceiver::Capacity capacity) override; + + uint getPort() override { + return SocketAddress::getLocalAddress(fd).getPort(); + } + + void getsockopt(int level, int option, void* value, uint* length) override { + socklen_t socklen = *length; + KJ_SYSCALL(::getsockopt(fd, level, option, value, &socklen)); + *length = socklen; + } + void setsockopt(int level, int option, const void* value, uint length) override { + KJ_SYSCALL(::setsockopt(fd, level, option, value, length)); + } + +public: + LowLevelAsyncIoProvider& lowLevel; + UnixEventPort& eventPort; + UnixEventPort::FdObserver observer; +}; + +class LowLevelAsyncIoProviderImpl final: public LowLevelAsyncIoProvider { +public: + LowLevelAsyncIoProviderImpl() + : eventLoop(eventPort), waitScope(eventLoop) {} + + inline WaitScope& getWaitScope() { return waitScope; } + + Own wrapInputFd(int fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Own wrapOutputFd(int fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Own wrapSocketFd(int fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Promise> wrapConnectingSocketFd( + int fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) override { + // Unfortunately connect() doesn't fit the mold of KJ_NONBLOCKING_SYSCALL, since it indicates + // non-blocking using EINPROGRESS. + for (;;) { + if (::connect(fd, addr, addrlen) < 0) { + int error = errno; + if (error == EINPROGRESS) { + // Fine. + break; + } else if (error != EINTR) { + KJ_FAIL_SYSCALL("connect()", error) { break; } + return Own(); + } + } else { + // no error + break; + } + } + + auto result = heap(eventPort, fd, flags); + + auto connected = result->waitConnected(); + return connected.then(kj::mvCapture(result, [fd](Own&& stream) { + int err; + socklen_t errlen = sizeof(err); + KJ_SYSCALL(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen)); + if (err != 0) { + KJ_FAIL_SYSCALL("connect()", err) { break; } + } + return kj::mv(stream); + })); + } + Own wrapListenSocketFd(int fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Own wrapDatagramSocketFd(int fd, uint flags = 0) override { + return heap(*this, eventPort, fd, flags); + } + + Timer& getTimer() override { return eventPort.getTimer(); } + + UnixEventPort& getEventPort() { return eventPort; } + +private: + UnixEventPort eventPort; + EventLoop eventLoop; + WaitScope waitScope; +}; + +// ======================================================================================= + +class NetworkAddressImpl final: public NetworkAddress { +public: + NetworkAddressImpl(LowLevelAsyncIoProvider& lowLevel, Array addrs) + : lowLevel(lowLevel), addrs(kj::mv(addrs)) {} + + Promise> connect() override { + auto addrsCopy = heapArray(addrs.asPtr()); + auto promise = connectImpl(lowLevel, addrsCopy); + return promise.attach(kj::mv(addrsCopy)); + } + + Own listen() override { + if (addrs.size() > 1) { + KJ_LOG(WARNING, "Bind address resolved to multiple addresses. Only the first address will " + "be used. If this is incorrect, specify the address numerically. This may be fixed " + "in the future.", addrs[0].toString()); + } + + int fd = addrs[0].socket(SOCK_STREAM); + + { + KJ_ON_SCOPE_FAILURE(close(fd)); + + // We always enable SO_REUSEADDR because having to take your server down for five minutes + // before it can restart really sucks. + int optval = 1; + KJ_SYSCALL(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))); + + addrs[0].bind(fd); + + // TODO(someday): Let queue size be specified explicitly in string addresses. + KJ_SYSCALL(::listen(fd, SOMAXCONN)); + } + + return lowLevel.wrapListenSocketFd(fd, NEW_FD_FLAGS); + } + + Own bindDatagramPort() override { + if (addrs.size() > 1) { + KJ_LOG(WARNING, "Bind address resolved to multiple addresses. Only the first address will " + "be used. If this is incorrect, specify the address numerically. This may be fixed " + "in the future.", addrs[0].toString()); + } + + int fd = addrs[0].socket(SOCK_DGRAM); + + { + KJ_ON_SCOPE_FAILURE(close(fd)); + + // We always enable SO_REUSEADDR because having to take your server down for five minutes + // before it can restart really sucks. + int optval = 1; + KJ_SYSCALL(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))); + + addrs[0].bind(fd); + } + + return lowLevel.wrapDatagramSocketFd(fd, NEW_FD_FLAGS); + } + + Own clone() override { + return kj::heap(lowLevel, kj::heapArray(addrs.asPtr())); + } + + String toString() override { + return strArray(KJ_MAP(addr, addrs) { return addr.toString(); }, ","); + } + + const SocketAddress& chooseOneAddress() { + KJ_REQUIRE(addrs.size() > 0, "No addresses available."); + return addrs[counter++ % addrs.size()]; + } + +private: + LowLevelAsyncIoProvider& lowLevel; + Array addrs; + uint counter = 0; + + static Promise> connectImpl( + LowLevelAsyncIoProvider& lowLevel, ArrayPtr addrs) { + KJ_ASSERT(addrs.size() > 0); + + int fd = addrs[0].socket(SOCK_STREAM); + + return kj::evalNow([&]() { + return lowLevel.wrapConnectingSocketFd( + fd, addrs[0].getRaw(), addrs[0].getRawSize(), NEW_FD_FLAGS); + }).then([](Own&& stream) -> Promise> { + // Success, pass along. + return kj::mv(stream); + }, [&lowLevel,addrs](Exception&& exception) mutable -> Promise> { + // Connect failed. + if (addrs.size() > 1) { + // Try the next address instead. + return connectImpl(lowLevel, addrs.slice(1, addrs.size())); + } else { + // No more addresses to try, so propagate the exception. + return kj::mv(exception); + } + }); + } +}; + +class SocketNetwork final: public Network { +public: + explicit SocketNetwork(LowLevelAsyncIoProvider& lowLevel): lowLevel(lowLevel) {} + + Promise> parseAddress(StringPtr addr, uint portHint = 0) override { + auto& lowLevelCopy = lowLevel; + return evalLater(mvCapture(heapString(addr), + [&lowLevelCopy,portHint](String&& addr) { + return SocketAddress::parse(lowLevelCopy, addr, portHint); + })).then([&lowLevelCopy](Array addresses) -> Own { + return heap(lowLevelCopy, kj::mv(addresses)); + }); + } + + Own getSockaddr(const void* sockaddr, uint len) override { + auto array = kj::heapArrayBuilder(1); + array.add(SocketAddress(sockaddr, len)); + return Own(heap(lowLevel, array.finish())); + } + +private: + LowLevelAsyncIoProvider& lowLevel; +}; + +// ======================================================================================= + +Promise DatagramPortImpl::send( + const void* buffer, size_t size, NetworkAddress& destination) { + auto& addr = downcast(destination).chooseOneAddress(); + + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = sendto(fd, buffer, size, 0, addr.getRaw(), addr.getRawSize())); + if (n < 0) { + // Write buffer full. + return observer.whenBecomesWritable().then([this, buffer, size, &destination]() { + return send(buffer, size, destination); + }); + } else { + // If less than the whole message was sent, then it got truncated, and there's nothing we can + // do about it. + return n; + } +} + +Promise DatagramPortImpl::send( + ArrayPtr> pieces, NetworkAddress& destination) { + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + + auto& addr = downcast(destination).chooseOneAddress(); + msg.msg_name = const_cast(implicitCast(addr.getRaw())); + msg.msg_namelen = addr.getRawSize(); + + const size_t iovmax = kj::miniposix::iovMax(pieces.size()); + KJ_STACK_ARRAY(struct iovec, iov, kj::min(pieces.size(), iovmax), 16, 64); + + for (size_t i: kj::indices(pieces)) { + iov[i].iov_base = const_cast(implicitCast(pieces[i].begin())); + iov[i].iov_len = pieces[i].size(); + } + + Array extra; + if (pieces.size() > iovmax) { + // Too many pieces, but we can't use multiple syscalls because they'd send separate + // datagrams. We'll have to copy the trailing pieces into a temporary array. + // + // TODO(perf): On Linux we could use multiple syscalls via MSG_MORE. + size_t extraSize = 0; + for (size_t i = iovmax - 1; i < pieces.size(); i++) { + extraSize += pieces[i].size(); + } + extra = kj::heapArray(extraSize); + extraSize = 0; + for (size_t i = iovmax - 1; i < pieces.size(); i++) { + memcpy(extra.begin() + extraSize, pieces[i].begin(), pieces[i].size()); + extraSize += pieces[i].size(); + } + iov[iovmax - 1].iov_base = extra.begin(); + iov[iovmax - 1].iov_len = extra.size(); + } + + msg.msg_iov = iov.begin(); + msg.msg_iovlen = iov.size(); + + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = sendmsg(fd, &msg, 0)); + if (n < 0) { + // Write buffer full. + return observer.whenBecomesWritable().then([this, pieces, &destination]() { + return send(pieces, destination); + }); + } else { + // If less than the whole message was sent, then it was truncated, and there's nothing we can + // do about that now. + return n; + } +} + +class DatagramPortImpl::ReceiverImpl final: public DatagramReceiver { +public: + explicit ReceiverImpl(DatagramPortImpl& port, Capacity capacity) + : port(port), + contentBuffer(heapArray(capacity.content)), + ancillaryBuffer(capacity.ancillary > 0 ? heapArray(capacity.ancillary) + : Array(nullptr)) {} + + Promise receive() override { + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + + struct sockaddr_storage addr; + memset(&addr, 0, sizeof(addr)); + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + + struct iovec iov; + iov.iov_base = contentBuffer.begin(); + iov.iov_len = contentBuffer.size(); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = ancillaryBuffer.begin(); + msg.msg_controllen = ancillaryBuffer.size(); + + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = recvmsg(port.fd, &msg, 0)); + + if (n < 0) { + // No data available. Wait. + return port.observer.whenBecomesReadable().then([this]() { + return receive(); + }); + } else { + receivedSize = n; + contentTruncated = msg.msg_flags & MSG_TRUNC; + + source.emplace(port.lowLevel, msg.msg_name, msg.msg_namelen); + + ancillaryList.resize(0); + ancillaryTruncated = msg.msg_flags & MSG_CTRUNC; + + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + // On some platforms (OSX), a cmsghdr's length may cross the end of the ancillary buffer + // when truncated. On other platforms (Linux) the length in cmsghdr will itself be + // truncated to fit within the buffer. + + const byte* pos = reinterpret_cast(cmsg); + size_t available = ancillaryBuffer.end() - pos; + if (available < CMSG_SPACE(0)) { + // The buffer ends in the middle of the header. We can't use this message. + // (On Linux, this never happens, because the message is not included if there isn't + // space for a header. I'm not sure how other systems behave, though, so let's be safe.) + break; + } + + // OK, we know the cmsghdr is valid, at least. + + // Find the start of the message payload. + const byte* begin = (const byte *)CMSG_DATA(cmsg); + + // Cap the message length to the available space. + const byte* end = pos + kj::min(available, cmsg->cmsg_len); + + ancillaryList.add(AncillaryMessage( + cmsg->cmsg_level, cmsg->cmsg_type, arrayPtr(begin, end))); + } + + return READY_NOW; + } + } + + MaybeTruncated> getContent() override { + return { contentBuffer.slice(0, receivedSize), contentTruncated }; + } + + MaybeTruncated> getAncillary() override { + return { ancillaryList.asPtr(), ancillaryTruncated }; + } + + NetworkAddress& getSource() override { + return KJ_REQUIRE_NONNULL(source, "Haven't sent a message yet.").abstract; + } + +private: + DatagramPortImpl& port; + Array contentBuffer; + Array ancillaryBuffer; + Vector ancillaryList; + size_t receivedSize = 0; + bool contentTruncated = false; + bool ancillaryTruncated = false; + + struct StoredAddress { + StoredAddress(LowLevelAsyncIoProvider& lowLevel, const void* sockaddr, uint length) + : raw(sockaddr, length), + abstract(lowLevel, Array(&raw, 1, NullArrayDisposer::instance)) {} + + SocketAddress raw; + NetworkAddressImpl abstract; + }; + + kj::Maybe source; +}; + +Own DatagramPortImpl::makeReceiver(DatagramReceiver::Capacity capacity) { + return kj::heap(*this, capacity); +} + +// ======================================================================================= + +class AsyncIoProviderImpl final: public AsyncIoProvider { +public: + AsyncIoProviderImpl(LowLevelAsyncIoProvider& lowLevel) + : lowLevel(lowLevel), network(lowLevel) {} + + OneWayPipe newOneWayPipe() override { + int fds[2]; +#if __linux__ && !__BIONIC__ + KJ_SYSCALL(pipe2(fds, O_NONBLOCK | O_CLOEXEC)); +#else + KJ_SYSCALL(pipe(fds)); +#endif + return OneWayPipe { + lowLevel.wrapInputFd(fds[0], NEW_FD_FLAGS), + lowLevel.wrapOutputFd(fds[1], NEW_FD_FLAGS) + }; + } + + TwoWayPipe newTwoWayPipe() override { + int fds[2]; + int type = SOCK_STREAM; +#if __linux__ && !__BIONIC__ + type |= SOCK_NONBLOCK | SOCK_CLOEXEC; +#endif + KJ_SYSCALL(socketpair(AF_UNIX, type, 0, fds)); + return TwoWayPipe { { + lowLevel.wrapSocketFd(fds[0], NEW_FD_FLAGS), + lowLevel.wrapSocketFd(fds[1], NEW_FD_FLAGS) + } }; + } + + Network& getNetwork() override { + return network; + } + + PipeThread newPipeThread( + Function startFunc) override { + int fds[2]; + int type = SOCK_STREAM; +#if __linux__ && !__BIONIC__ + type |= SOCK_NONBLOCK | SOCK_CLOEXEC; +#endif + KJ_SYSCALL(socketpair(AF_UNIX, type, 0, fds)); + + int threadFd = fds[1]; + KJ_ON_SCOPE_FAILURE(close(threadFd)); + + auto pipe = lowLevel.wrapSocketFd(fds[0], NEW_FD_FLAGS); + + auto thread = heap(kj::mvCapture(startFunc, + [threadFd](Function&& startFunc) { + LowLevelAsyncIoProviderImpl lowLevel; + auto stream = lowLevel.wrapSocketFd(threadFd, NEW_FD_FLAGS); + AsyncIoProviderImpl ioProvider(lowLevel); + startFunc(ioProvider, *stream, lowLevel.getWaitScope()); + })); + + return { kj::mv(thread), kj::mv(pipe) }; + } + + Timer& getTimer() override { return lowLevel.getTimer(); } + +private: + LowLevelAsyncIoProvider& lowLevel; + SocketNetwork network; +}; + +} // namespace + +Own newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel) { + return kj::heap(lowLevel); +} + +AsyncIoContext setupAsyncIo() { + auto lowLevel = heap(); + auto ioProvider = kj::heap(*lowLevel); + auto& waitScope = lowLevel->getWaitScope(); + auto& eventPort = lowLevel->getEventPort(); + return { kj::mv(lowLevel), kj::mv(ioProvider), waitScope, eventPort }; +} + +} // namespace kj + +#endif // !_WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-io-win32.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-io-win32.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1146 @@ +// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if _WIN32 +// For Unix implementation, see async-io-unix.c++. + +// Request Vista-level APIs. +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 + +#include "async-io.h" +#include "async-win32.h" +#include "debug.h" +#include "thread.h" +#include "io.h" +#include "vector.h" +#include + +#include +#include +#include +#include +#include + +#ifndef IPV6_V6ONLY +// MinGW's headers are missing this. +#define IPV6_V6ONLY 27 +#endif + +namespace kj { + +namespace _ { // private + +struct WinsockInitializer { + WinsockInitializer() { + WSADATA dontcare; + int result = WSAStartup(MAKEWORD(2, 2), &dontcare); + if (result != 0) { + KJ_FAIL_WIN32("WSAStartup()", result); + } + } +}; + +void initWinsockOnce() { + static WinsockInitializer initializer; +} + +int win32Socketpair(SOCKET socks[2]) { + // This function from: https://github.com/ncm/selectable-socketpair/blob/master/socketpair.c + // + // Copyright notice: + // + // Copyright 2007, 2010 by Nathan C. Myers + // Redistribution and use in source and binary forms, with or without modification, + // are permitted provided that the following conditions are met: + // + // Redistributions of source code must retain the above copyright notice, this + // list of conditions and the following disclaimer. + // + // 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. + // + // The name of the author must not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // 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 HOLDER 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. + + // Note: This function is called from some Cap'n Proto unit tests, despite not having a public + // header declaration. + // TODO(cleanup): Consider putting this somewhere public? Note that since it depends on Winsock, + // it needs to be in the kj-async library. + + initWinsockOnce(); + + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + int reuse = 1; + + if (socks == 0) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + socks[0] = socks[1] = -1; + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listener == -1) + return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + for (;;) { + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, + (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) + break; + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + memset(&a, 0, sizeof(a)); + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) + break; + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (listen(listener, 1) == SOCKET_ERROR) + break; + + socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); + if (socks[0] == -1) + break; + if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + socks[1] = accept(listener, NULL, NULL); + if (socks[1] == -1) + break; + + closesocket(listener); + return 0; + } + + e = WSAGetLastError(); + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + WSASetLastError(e); + socks[0] = socks[1] = -1; + return SOCKET_ERROR; +} + +} // namespace _ + +namespace { + +bool detectWine() { + HMODULE hntdll = GetModuleHandle("ntdll.dll"); + if(hntdll == NULL) return false; + return GetProcAddress(hntdll, "wine_get_version") != nullptr; +} + +bool isWine() { + static bool result = detectWine(); + return result; +} + +// ======================================================================================= + +static constexpr uint NEW_FD_FLAGS = LowLevelAsyncIoProvider::TAKE_OWNERSHIP; + +class OwnedFd { +public: + OwnedFd(SOCKET fd, uint flags): fd(fd), flags(flags) { + // TODO(perf): Maybe use SetFileCompletionNotificationModes() to tell Windows not to bother + // delivering an event when the operation completes inline. Not currently implemented on + // Wine, though. + } + + ~OwnedFd() noexcept(false) { + if (flags & LowLevelAsyncIoProvider::TAKE_OWNERSHIP) { + KJ_WINSOCK(closesocket(fd)) { break; } + } + } + +protected: + SOCKET fd; + +private: + uint flags; +}; + +// ======================================================================================= + +class AsyncStreamFd: public OwnedFd, public AsyncIoStream { +public: + AsyncStreamFd(Win32EventPort& eventPort, SOCKET fd, uint flags) + : OwnedFd(fd, flags), + observer(eventPort.observeIo(reinterpret_cast(fd))) {} + virtual ~AsyncStreamFd() noexcept(false) {} + + Promise read(void* buffer, size_t minBytes, size_t maxBytes) override { + return tryRead(buffer, minBytes, maxBytes).then([=](size_t result) { + KJ_REQUIRE(result >= minBytes, "Premature EOF") { + // Pretend we read zeros from the input. + memset(reinterpret_cast(buffer) + result, 0, minBytes - result); + return minBytes; + } + return result; + }); + } + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + auto bufs = heapArray(1); + bufs[0].buf = reinterpret_cast(buffer); + bufs[0].len = maxBytes; + + ArrayPtr ref = bufs; + return tryReadInternal(ref, minBytes, 0).attach(kj::mv(bufs)); + } + + Promise write(const void* buffer, size_t size) override { + auto bufs = heapArray(1); + bufs[0].buf = const_cast(reinterpret_cast(buffer)); + bufs[0].len = size; + + ArrayPtr ref = bufs; + return writeInternal(ref).attach(kj::mv(bufs)); + } + + Promise write(ArrayPtr> pieces) override { + auto bufs = heapArray(pieces.size()); + for (auto i: kj::indices(pieces)) { + bufs[i].buf = const_cast(pieces[i].asChars().begin()); + bufs[i].len = pieces[i].size(); + } + + ArrayPtr ref = bufs; + return writeInternal(ref).attach(kj::mv(bufs)); + } + + kj::Promise connect(const struct sockaddr* addr, uint addrlen) { + // In order to connect asynchronously, we need the ConnectEx() function. Apparently, we have + // to query the socket for it dynamically, I guess because of the insanity in which winsock + // can be implemented in userspace and old implementations may not support it. + GUID guid = WSAID_CONNECTEX; + LPFN_CONNECTEX connectEx = nullptr; + DWORD n = 0; + KJ_WINSOCK(WSAIoctl(fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + &connectEx, sizeof(connectEx), &n, NULL, NULL)) { + goto fail; // avoid memory leak due to compiler bugs + } + if (false) { + fail: + return kj::READY_NOW; + } + + // OK, phew, we now have our ConnectEx function pointer. Call it. + auto op = observer->newOperation(0); + + if (!connectEx(fd, addr, addrlen, NULL, 0, NULL, op->getOverlapped())) { + DWORD error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + KJ_FAIL_WIN32("ConnectEx()", error) { break; } + return kj::READY_NOW; + } + } + + return op->onComplete().then([this](Win32EventPort::IoResult result) { + if (result.errorCode != ERROR_SUCCESS) { + KJ_FAIL_WIN32("ConnectEx()", result.errorCode) { return; } + } + + // Enable shutdown() to work. + setsockopt(SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); + }); + } + + void shutdownWrite() override { + // There's no legitimate way to get an AsyncStreamFd that isn't a socket through the + // Win32AsyncIoProvider interface. + KJ_WINSOCK(shutdown(fd, SD_SEND)); + } + + void abortRead() override { + // There's no legitimate way to get an AsyncStreamFd that isn't a socket through the + // Win32AsyncIoProvider interface. + KJ_WINSOCK(shutdown(fd, SD_RECEIVE)); + } + + void getsockopt(int level, int option, void* value, uint* length) override { + socklen_t socklen = *length; + KJ_WINSOCK(::getsockopt(fd, level, option, + reinterpret_cast(value), &socklen)); + *length = socklen; + } + + void setsockopt(int level, int option, const void* value, uint length) override { + KJ_WINSOCK(::setsockopt(fd, level, option, + reinterpret_cast(value), length)); + } + + void getsockname(struct sockaddr* addr, uint* length) override { + socklen_t socklen = *length; + KJ_WINSOCK(::getsockname(fd, addr, &socklen)); + *length = socklen; + } + + void getpeername(struct sockaddr* addr, uint* length) override { + socklen_t socklen = *length; + KJ_WINSOCK(::getpeername(fd, addr, &socklen)); + *length = socklen; + } + +private: + Own observer; + + Promise tryReadInternal(ArrayPtr bufs, size_t minBytes, size_t alreadyRead) { + // `bufs` will remain valid until the promise completes and may be freely modified. + // + // `alreadyRead` is the number of bytes we have already received via previous reads -- minBytes + // and buffer have already been adjusted to account for them, but this count must be included + // in the final return value. + + auto op = observer->newOperation(0); + + DWORD flags = 0; + if (WSARecv(fd, bufs.begin(), bufs.size(), NULL, &flags, + op->getOverlapped(), NULL) == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + KJ_FAIL_WIN32("WSARecv()", error) { break; } + return alreadyRead; + } + } + + return op->onComplete() + .then([this,KJ_CPCAP(bufs),minBytes,alreadyRead](Win32IocpEventPort::IoResult result) mutable + -> Promise { + if (result.errorCode != ERROR_SUCCESS) { + if (alreadyRead > 0) { + // Report what we already read. + return alreadyRead; + } else { + KJ_FAIL_WIN32("WSARecv()", result.errorCode) { break; } + return size_t(0); + } + } + + if (result.bytesTransferred == 0) { + return alreadyRead; + } + + alreadyRead += result.bytesTransferred; + if (result.bytesTransferred >= minBytes) { + // We can stop here. + return alreadyRead; + } + minBytes -= result.bytesTransferred; + + while (result.bytesTransferred >= bufs[0].len) { + result.bytesTransferred -= bufs[0].len; + bufs = bufs.slice(1, bufs.size()); + } + + if (result.bytesTransferred > 0) { + bufs[0].buf += result.bytesTransferred; + bufs[0].len -= result.bytesTransferred; + } + + return tryReadInternal(bufs, minBytes, alreadyRead); + }).attach(kj::mv(bufs)); + } + + Promise writeInternal(ArrayPtr bufs) { + // `bufs` will remain valid until the promise completes and may be freely modified. + + auto op = observer->newOperation(0); + + if (WSASend(fd, bufs.begin(), bufs.size(), NULL, 0, + op->getOverlapped(), NULL) == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + KJ_FAIL_WIN32("WSASend()", error) { break; } + return kj::READY_NOW; + } + } + + return op->onComplete() + .then([this,KJ_CPCAP(bufs)](Win32IocpEventPort::IoResult result) mutable -> Promise { + if (result.errorCode != ERROR_SUCCESS) { + KJ_FAIL_WIN32("WSASend()", result.errorCode) { break; } + return kj::READY_NOW; + } + + while (bufs.size() > 0 && result.bytesTransferred >= bufs[0].len) { + result.bytesTransferred -= bufs[0].len; + bufs = bufs.slice(1, bufs.size()); + } + + if (result.bytesTransferred > 0) { + bufs[0].buf += result.bytesTransferred; + bufs[0].len -= result.bytesTransferred; + } + + if (bufs.size() > 0) { + return writeInternal(bufs); + } else { + return kj::READY_NOW; + } + }).attach(kj::mv(bufs)); + } +}; + +// ======================================================================================= + +class SocketAddress { +public: + SocketAddress(const void* sockaddr, uint len): addrlen(len) { + KJ_REQUIRE(len <= sizeof(addr), "Sorry, your sockaddr is too big for me."); + memcpy(&addr.generic, sockaddr, len); + } + + bool operator<(const SocketAddress& other) const { + // So we can use std::set... see DNS lookup code. + + if (wildcard < other.wildcard) return true; + if (wildcard > other.wildcard) return false; + + if (addrlen < other.addrlen) return true; + if (addrlen > other.addrlen) return false; + + return memcmp(&addr.generic, &other.addr.generic, addrlen) < 0; + } + + const struct sockaddr* getRaw() const { return &addr.generic; } + int getRawSize() const { return addrlen; } + + SOCKET socket(int type) const { + bool isStream = type == SOCK_STREAM; + + SOCKET result = ::socket(addr.generic.sa_family, type, 0); + + if (result == INVALID_SOCKET) { + KJ_FAIL_WIN32("WSASocket()", WSAGetLastError()) { return INVALID_SOCKET; } + } + + if (isStream && (addr.generic.sa_family == AF_INET || + addr.generic.sa_family == AF_INET6)) { + // TODO(perf): As a hack for the 0.4 release we are always setting + // TCP_NODELAY because Nagle's algorithm pretty much kills Cap'n Proto's + // RPC protocol. Later, we should extend the interface to provide more + // control over this. Perhaps write() should have a flag which + // specifies whether to pass MSG_MORE. + BOOL one = TRUE; + KJ_WINSOCK(setsockopt(result, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one))); + } + + return result; + } + + void bind(SOCKET sockfd) const { + if (wildcard) { + // Disable IPV6_V6ONLY because we want to handle both ipv4 and ipv6 on this socket. (The + // default value of this option varies across platforms.) + DWORD value = 0; + KJ_WINSOCK(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&value), sizeof(value))); + } + + KJ_WINSOCK(::bind(sockfd, &addr.generic, addrlen), toString()); + } + + uint getPort() const { + switch (addr.generic.sa_family) { + case AF_INET: return ntohs(addr.inet4.sin_port); + case AF_INET6: return ntohs(addr.inet6.sin6_port); + default: return 0; + } + } + + String toString() const { + if (wildcard) { + return str("*:", getPort()); + } + + switch (addr.generic.sa_family) { + case AF_INET: { + char buffer[16]; + if (InetNtopA(addr.inet4.sin_family, const_cast(&addr.inet4.sin_addr), + buffer, sizeof(buffer)) == nullptr) { + KJ_FAIL_WIN32("InetNtop", WSAGetLastError()) { break; } + return heapString("(inet_ntop error)"); + } + return str(buffer, ':', ntohs(addr.inet4.sin_port)); + } + case AF_INET6: { + char buffer[46]; + if (InetNtopA(addr.inet6.sin6_family, const_cast(&addr.inet6.sin6_addr), + buffer, sizeof(buffer)) == nullptr) { + KJ_FAIL_WIN32("InetNtop", WSAGetLastError()) { break; } + return heapString("(inet_ntop error)"); + } + return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port)); + } + default: + return str("(unknown address family ", addr.generic.sa_family, ")"); + } + } + + static Promise> lookupHost( + LowLevelAsyncIoProvider& lowLevel, kj::String host, kj::String service, uint portHint); + // Perform a DNS lookup. + + static Promise> parse( + LowLevelAsyncIoProvider& lowLevel, StringPtr str, uint portHint) { + // TODO(someday): Allow commas in `str`. + + SocketAddress result; + + // Try to separate the address and port. + ArrayPtr addrPart; + Maybe portPart; + + int af; + + if (str.startsWith("[")) { + // Address starts with a bracket, which is a common way to write an ip6 address with a port, + // since without brackets around the address part, the port looks like another segment of + // the address. + af = AF_INET6; + size_t closeBracket = KJ_ASSERT_NONNULL(str.findLast(']'), + "Unclosed '[' in address string.", str); + + addrPart = str.slice(1, closeBracket); + if (str.size() > closeBracket + 1) { + KJ_REQUIRE(str.slice(closeBracket + 1).startsWith(":"), + "Expected port suffix after ']'.", str); + portPart = str.slice(closeBracket + 2); + } + } else { + KJ_IF_MAYBE(colon, str.findFirst(':')) { + if (str.slice(*colon + 1).findFirst(':') == nullptr) { + // There is exactly one colon and no brackets, so it must be an ip4 address with port. + af = AF_INET; + addrPart = str.slice(0, *colon); + portPart = str.slice(*colon + 1); + } else { + // There are two or more colons and no brackets, so the whole thing must be an ip6 + // address with no port. + af = AF_INET6; + addrPart = str; + } + } else { + // No colons, so it must be an ip4 address without port. + af = AF_INET; + addrPart = str; + } + } + + // Parse the port. + unsigned long port; + KJ_IF_MAYBE(portText, portPart) { + char* endptr; + port = strtoul(portText->cStr(), &endptr, 0); + if (portText->size() == 0 || *endptr != '\0') { + // Not a number. Maybe it's a service name. Fall back to DNS. + return lookupHost(lowLevel, kj::heapString(addrPart), kj::heapString(*portText), portHint); + } + KJ_REQUIRE(port < 65536, "Port number too large."); + } else { + port = portHint; + } + + // Check for wildcard. + if (addrPart.size() == 1 && addrPart[0] == '*') { + result.wildcard = true; + // Create an ip6 socket and set IPV6_V6ONLY to 0 later. + result.addrlen = sizeof(addr.inet6); + result.addr.inet6.sin6_family = AF_INET6; + result.addr.inet6.sin6_port = htons(port); + auto array = kj::heapArrayBuilder(1); + array.add(result); + return array.finish(); + } + + void* addrTarget; + if (af == AF_INET6) { + result.addrlen = sizeof(addr.inet6); + result.addr.inet6.sin6_family = AF_INET6; + result.addr.inet6.sin6_port = htons(port); + addrTarget = &result.addr.inet6.sin6_addr; + } else { + result.addrlen = sizeof(addr.inet4); + result.addr.inet4.sin_family = AF_INET; + result.addr.inet4.sin_port = htons(port); + addrTarget = &result.addr.inet4.sin_addr; + } + + // addrPart is not necessarily NUL-terminated so we have to make a copy. :( + char buffer[64]; + KJ_REQUIRE(addrPart.size() < sizeof(buffer) - 1, "IP address too long.", addrPart); + memcpy(buffer, addrPart.begin(), addrPart.size()); + buffer[addrPart.size()] = '\0'; + + // OK, parse it! + switch (InetPtonA(af, buffer, addrTarget)) { + case 1: { + // success. + auto array = kj::heapArrayBuilder(1); + array.add(result); + return array.finish(); + } + case 0: + // It's apparently not a simple address... fall back to DNS. + return lookupHost(lowLevel, kj::heapString(addrPart), nullptr, port); + default: + KJ_FAIL_WIN32("InetPton", WSAGetLastError(), af, addrPart); + } + } + + static SocketAddress getLocalAddress(int sockfd) { + SocketAddress result; + result.addrlen = sizeof(addr); + KJ_WINSOCK(getsockname(sockfd, &result.addr.generic, &result.addrlen)); + return result; + } + + static SocketAddress getWildcardForFamily(int family) { + SocketAddress result; + switch (family) { + case AF_INET: + result.addrlen = sizeof(addr.inet4); + result.addr.inet4.sin_family = AF_INET; + return result; + case AF_INET6: + result.addrlen = sizeof(addr.inet6); + result.addr.inet6.sin6_family = AF_INET6; + return result; + default: + KJ_FAIL_REQUIRE("unknown address family", family); + } + } + +private: + SocketAddress(): addrlen(0) { + memset(&addr, 0, sizeof(addr)); + } + + socklen_t addrlen; + bool wildcard = false; + union { + struct sockaddr generic; + struct sockaddr_in inet4; + struct sockaddr_in6 inet6; + struct sockaddr_storage storage; + } addr; + + struct LookupParams; + class LookupReader; +}; + +class SocketAddress::LookupReader { + // Reads SocketAddresses off of a pipe coming from another thread that is performing + // getaddrinfo. + +public: + LookupReader(kj::Own&& thread, kj::Own&& input) + : thread(kj::mv(thread)), input(kj::mv(input)) {} + + ~LookupReader() { + if (thread) thread->detach(); + } + + Promise> read() { + return input->tryRead(¤t, sizeof(current), sizeof(current)).then( + [this](size_t n) -> Promise> { + if (n < sizeof(current)) { + thread = nullptr; + // getaddrinfo()'s docs seem to say it will never return an empty list, but let's check + // anyway. + KJ_REQUIRE(addresses.size() > 0, "DNS lookup returned no addresses.") { break; } + return addresses.releaseAsArray(); + } else { + // getaddrinfo() can return multiple copies of the same address for several reasons. + // A major one is that we don't give it a socket type (SOCK_STREAM vs. SOCK_DGRAM), so + // it may return two copies of the same address, one for each type, unless it explicitly + // knows that the service name given is specific to one type. But we can't tell it a type, + // because we don't actually know which one the user wants, and if we specify SOCK_STREAM + // while the user specified a UDP service name then they'll get a resolution error which + // is lame. (At least, I think that's how it works.) + // + // So we instead resort to de-duping results. + if (alreadySeen.insert(current).second) { + addresses.add(current); + } + return read(); + } + }); + } + +private: + kj::Own thread; + kj::Own input; + SocketAddress current; + kj::Vector addresses; + std::set alreadySeen; +}; + +struct SocketAddress::LookupParams { + kj::String host; + kj::String service; +}; + +Promise> SocketAddress::lookupHost( + LowLevelAsyncIoProvider& lowLevel, kj::String host, kj::String service, uint portHint) { + // This shitty function spawns a thread to run getaddrinfo(). Unfortunately, getaddrinfo() is + // the only cross-platform DNS API and it is blocking. + // + // TODO(perf): Use GetAddrInfoEx(). But there are problems: + // - Not implemented in Wine. + // - Doesn't seem compatible with I/O completion ports, in particular because it's not associated + // with a handle. Could signal completion as an APC instead, but that requires the IOCP code + // to use GetQueuedCompletionStatusEx() which it doesn't right now becaues it's not available + // in Wine. + // - Requires Unicode, for some reason. Only GetAddrInfoExW() supports async, according to the + // docs. Never mind that DNS itself is ASCII... + + SOCKET fds[2]; + KJ_WINSOCK(_::win32Socketpair(fds)); + + auto input = lowLevel.wrapInputFd(fds[0], NEW_FD_FLAGS); + + int outFd = fds[1]; + + LookupParams params = { kj::mv(host), kj::mv(service) }; + + auto thread = heap(kj::mvCapture(params, [outFd,portHint](LookupParams&& params) { + KJ_DEFER(closesocket(outFd)); + + struct addrinfo* list; + int status = getaddrinfo( + params.host == "*" ? nullptr : params.host.cStr(), + params.service == nullptr ? nullptr : params.service.cStr(), + nullptr, &list); + if (status == 0) { + KJ_DEFER(freeaddrinfo(list)); + + struct addrinfo* cur = list; + while (cur != nullptr) { + if (params.service == nullptr) { + switch (cur->ai_addr->sa_family) { + case AF_INET: + ((struct sockaddr_in*)cur->ai_addr)->sin_port = htons(portHint); + break; + case AF_INET6: + ((struct sockaddr_in6*)cur->ai_addr)->sin6_port = htons(portHint); + break; + default: + break; + } + } + + SocketAddress addr; + memset(&addr, 0, sizeof(addr)); // mollify valgrind + if (params.host == "*") { + // Set up a wildcard SocketAddress. Only use the port number returned by getaddrinfo(). + addr.wildcard = true; + addr.addrlen = sizeof(addr.addr.inet6); + addr.addr.inet6.sin6_family = AF_INET6; + switch (cur->ai_addr->sa_family) { + case AF_INET: + addr.addr.inet6.sin6_port = ((struct sockaddr_in*)cur->ai_addr)->sin_port; + break; + case AF_INET6: + addr.addr.inet6.sin6_port = ((struct sockaddr_in6*)cur->ai_addr)->sin6_port; + break; + default: + addr.addr.inet6.sin6_port = portHint; + break; + } + } else { + addr.addrlen = cur->ai_addrlen; + memcpy(&addr.addr.generic, cur->ai_addr, cur->ai_addrlen); + } + KJ_ASSERT_CAN_MEMCPY(SocketAddress); + + const char* data = reinterpret_cast(&addr); + size_t size = sizeof(addr); + while (size > 0) { + int n; + KJ_WINSOCK(n = send(outFd, data, size, 0)); + data += n; + size -= n; + } + + cur = cur->ai_next; + } + } else { + KJ_FAIL_WIN32("getaddrinfo()", status, params.host, params.service) { + return; + } + } + })); + + auto reader = heap(kj::mv(thread), kj::mv(input)); + return reader->read().attach(kj::mv(reader)); +} + +// ======================================================================================= + +class FdConnectionReceiver final: public ConnectionReceiver, public OwnedFd { +public: + FdConnectionReceiver(Win32EventPort& eventPort, SOCKET fd, uint flags) + : OwnedFd(fd, flags), eventPort(eventPort), + observer(eventPort.observeIo(reinterpret_cast(fd))), + address(SocketAddress::getLocalAddress(fd)) { + // In order to accept asynchronously, we need the AcceptEx() function. Apparently, we have + // to query the socket for it dynamically, I guess because of the insanity in which winsock + // can be implemented in userspace and old implementations may not support it. + GUID guid = WSAID_ACCEPTEX; + DWORD n = 0; + KJ_WINSOCK(WSAIoctl(fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), + &acceptEx, sizeof(acceptEx), &n, NULL, NULL)) { + acceptEx = nullptr; + return; + } + } + + Promise> accept() override { + SOCKET newFd = address.socket(SOCK_STREAM); + KJ_ASSERT(newFd != INVALID_SOCKET); + auto result = heap(eventPort, newFd, NEW_FD_FLAGS); + + auto scratch = heapArray(256); + DWORD dummy; + auto op = observer->newOperation(0); + if (!acceptEx(fd, newFd, scratch.begin(), 0, 128, 128, &dummy, op->getOverlapped())) { + DWORD error = WSAGetLastError(); + if (error != ERROR_IO_PENDING) { + KJ_FAIL_WIN32("AcceptEx()", error) { break; } + return Own(kj::mv(result)); // dummy, won't be used + } + } + + return op->onComplete().attach(kj::mv(scratch)).then(mvCapture(result, + [this](Own stream, Win32EventPort::IoResult ioResult) { + if (ioResult.errorCode != ERROR_SUCCESS) { + KJ_FAIL_WIN32("AcceptEx()", ioResult.errorCode) { break; } + } else { + SOCKET me = fd; + stream->setsockopt(SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + reinterpret_cast(&me), sizeof(me)); + } + return kj::mv(stream); + })); + } + + uint getPort() override { + return address.getPort(); + } + + void getsockopt(int level, int option, void* value, uint* length) override { + socklen_t socklen = *length; + KJ_WINSOCK(::getsockopt(fd, level, option, + reinterpret_cast(value), &socklen)); + *length = socklen; + } + void setsockopt(int level, int option, const void* value, uint length) override { + KJ_WINSOCK(::setsockopt(fd, level, option, + reinterpret_cast(value), length)); + } + +public: + Win32EventPort& eventPort; + Own observer; + LPFN_ACCEPTEX acceptEx = nullptr; + SocketAddress address; +}; + +// TODO(someday): DatagramPortImpl + +class LowLevelAsyncIoProviderImpl final: public LowLevelAsyncIoProvider { +public: + LowLevelAsyncIoProviderImpl() + : eventLoop(eventPort), waitScope(eventLoop) {} + + inline WaitScope& getWaitScope() { return waitScope; } + + Own wrapInputFd(SOCKET fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Own wrapOutputFd(SOCKET fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Own wrapSocketFd(SOCKET fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + Promise> wrapConnectingSocketFd( + SOCKET fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) override { + auto result = heap(eventPort, fd, flags); + + // ConnectEx requires that the socket be bound, for some reason. Bind to an arbitrary port. + SocketAddress::getWildcardForFamily(addr->sa_family).bind(fd); + + auto connected = result->connect(addr, addrlen); + return connected.then(kj::mvCapture(result, [](Own&& result) { + return kj::mv(result); + })); + } + Own wrapListenSocketFd(SOCKET fd, uint flags = 0) override { + return heap(eventPort, fd, flags); + } + + Timer& getTimer() override { return eventPort.getTimer(); } + + Win32EventPort& getEventPort() { return eventPort; } + +private: + Win32IocpEventPort eventPort; + EventLoop eventLoop; + WaitScope waitScope; +}; + +// ======================================================================================= + +class NetworkAddressImpl final: public NetworkAddress { +public: + NetworkAddressImpl(LowLevelAsyncIoProvider& lowLevel, Array addrs) + : lowLevel(lowLevel), addrs(kj::mv(addrs)) {} + + Promise> connect() override { + auto addrsCopy = heapArray(addrs.asPtr()); + auto promise = connectImpl(lowLevel, addrsCopy); + return promise.attach(kj::mv(addrsCopy)); + } + + Own listen() override { + if (addrs.size() > 1) { + KJ_LOG(WARNING, "Bind address resolved to multiple addresses. Only the first address will " + "be used. If this is incorrect, specify the address numerically. This may be fixed " + "in the future.", addrs[0].toString()); + } + + int fd = addrs[0].socket(SOCK_STREAM); + + { + KJ_ON_SCOPE_FAILURE(closesocket(fd)); + + // We always enable SO_REUSEADDR because having to take your server down for five minutes + // before it can restart really sucks. + int optval = 1; + KJ_WINSOCK(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&optval), sizeof(optval))); + + addrs[0].bind(fd); + + // TODO(someday): Let queue size be specified explicitly in string addresses. + KJ_WINSOCK(::listen(fd, SOMAXCONN)); + } + + return lowLevel.wrapListenSocketFd(fd, NEW_FD_FLAGS); + } + + Own bindDatagramPort() override { + if (addrs.size() > 1) { + KJ_LOG(WARNING, "Bind address resolved to multiple addresses. Only the first address will " + "be used. If this is incorrect, specify the address numerically. This may be fixed " + "in the future.", addrs[0].toString()); + } + + int fd = addrs[0].socket(SOCK_DGRAM); + + { + KJ_ON_SCOPE_FAILURE(closesocket(fd)); + + // We always enable SO_REUSEADDR because having to take your server down for five minutes + // before it can restart really sucks. + int optval = 1; + KJ_WINSOCK(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&optval), sizeof(optval))); + + addrs[0].bind(fd); + } + + return lowLevel.wrapDatagramSocketFd(fd, NEW_FD_FLAGS); + } + + Own clone() override { + return kj::heap(lowLevel, kj::heapArray(addrs.asPtr())); + } + + String toString() override { + return strArray(KJ_MAP(addr, addrs) { return addr.toString(); }, ","); + } + + const SocketAddress& chooseOneAddress() { + KJ_REQUIRE(addrs.size() > 0, "No addresses available."); + return addrs[counter++ % addrs.size()]; + } + +private: + LowLevelAsyncIoProvider& lowLevel; + Array addrs; + uint counter = 0; + + static Promise> connectImpl( + LowLevelAsyncIoProvider& lowLevel, ArrayPtr addrs) { + KJ_ASSERT(addrs.size() > 0); + + int fd = addrs[0].socket(SOCK_STREAM); + + return kj::evalNow([&]() { + return lowLevel.wrapConnectingSocketFd( + fd, addrs[0].getRaw(), addrs[0].getRawSize(), NEW_FD_FLAGS); + }).then([](Own&& stream) -> Promise> { + // Success, pass along. + return kj::mv(stream); + }, [&lowLevel,KJ_CPCAP(addrs)](Exception&& exception) mutable -> Promise> { + // Connect failed. + if (addrs.size() > 1) { + // Try the next address instead. + return connectImpl(lowLevel, addrs.slice(1, addrs.size())); + } else { + // No more addresses to try, so propagate the exception. + return kj::mv(exception); + } + }); + } +}; + +class SocketNetwork final: public Network { +public: + explicit SocketNetwork(LowLevelAsyncIoProvider& lowLevel): lowLevel(lowLevel) {} + + Promise> parseAddress(StringPtr addr, uint portHint = 0) override { + auto& lowLevelCopy = lowLevel; + return evalLater(mvCapture(heapString(addr), + [&lowLevelCopy,portHint](String&& addr) { + return SocketAddress::parse(lowLevelCopy, addr, portHint); + })).then([&lowLevelCopy](Array addresses) -> Own { + return heap(lowLevelCopy, kj::mv(addresses)); + }); + } + + Own getSockaddr(const void* sockaddr, uint len) override { + auto array = kj::heapArrayBuilder(1); + array.add(SocketAddress(sockaddr, len)); + return Own(heap(lowLevel, array.finish())); + } + +private: + LowLevelAsyncIoProvider& lowLevel; +}; + +// ======================================================================================= + +class AsyncIoProviderImpl final: public AsyncIoProvider { +public: + AsyncIoProviderImpl(LowLevelAsyncIoProvider& lowLevel) + : lowLevel(lowLevel), network(lowLevel) {} + + OneWayPipe newOneWayPipe() override { + SOCKET fds[2]; + KJ_WINSOCK(_::win32Socketpair(fds)); + auto in = lowLevel.wrapSocketFd(fds[0], NEW_FD_FLAGS); + auto out = lowLevel.wrapOutputFd(fds[1], NEW_FD_FLAGS); + in->shutdownWrite(); + return { kj::mv(in), kj::mv(out) }; + } + + TwoWayPipe newTwoWayPipe() override { + SOCKET fds[2]; + KJ_WINSOCK(_::win32Socketpair(fds)); + return TwoWayPipe { { + lowLevel.wrapSocketFd(fds[0], NEW_FD_FLAGS), + lowLevel.wrapSocketFd(fds[1], NEW_FD_FLAGS) + } }; + } + + Network& getNetwork() override { + return network; + } + + PipeThread newPipeThread( + Function startFunc) override { + SOCKET fds[2]; + KJ_WINSOCK(_::win32Socketpair(fds)); + + int threadFd = fds[1]; + KJ_ON_SCOPE_FAILURE(closesocket(threadFd)); + + auto pipe = lowLevel.wrapSocketFd(fds[0], NEW_FD_FLAGS); + + auto thread = heap(kj::mvCapture(startFunc, + [threadFd](Function&& startFunc) { + LowLevelAsyncIoProviderImpl lowLevel; + auto stream = lowLevel.wrapSocketFd(threadFd, NEW_FD_FLAGS); + AsyncIoProviderImpl ioProvider(lowLevel); + startFunc(ioProvider, *stream, lowLevel.getWaitScope()); + })); + + return { kj::mv(thread), kj::mv(pipe) }; + } + + Timer& getTimer() override { return lowLevel.getTimer(); } + +private: + LowLevelAsyncIoProvider& lowLevel; + SocketNetwork network; +}; + +} // namespace + +Own newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel) { + return kj::heap(lowLevel); +} + +AsyncIoContext setupAsyncIo() { + _::initWinsockOnce(); + + auto lowLevel = heap(); + auto ioProvider = kj::heap(*lowLevel); + auto& waitScope = lowLevel->getWaitScope(); + auto& eventPort = lowLevel->getEventPort(); + return { kj::mv(lowLevel), kj::mv(ioProvider), waitScope, eventPort }; +} + +} // namespace kj + +#endif // _WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-io.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-io.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,195 @@ +// Copyright (c) 2013-2017 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "async-io.h" +#include "debug.h" +#include "vector.h" + +namespace kj { + +Promise AsyncInputStream::read(void* buffer, size_t bytes) { + return read(buffer, bytes, bytes).then([](size_t) {}); +} + +Promise AsyncInputStream::read(void* buffer, size_t minBytes, size_t maxBytes) { + return tryRead(buffer, minBytes, maxBytes).then([=](size_t result) { + KJ_REQUIRE(result >= minBytes, "Premature EOF") { + // Pretend we read zeros from the input. + memset(reinterpret_cast(buffer) + result, 0, minBytes - result); + return minBytes; + } + return result; + }); +} + +Maybe AsyncInputStream::tryGetLength() { return nullptr; } + +namespace { + +class AsyncPump { +public: + AsyncPump(AsyncInputStream& input, AsyncOutputStream& output, uint64_t limit) + : input(input), output(output), limit(limit) {} + + Promise pump() { + // TODO(perf): This could be more efficient by reading half a buffer at a time and then + // starting the next read concurrent with writing the data from the previous read. + + uint64_t n = kj::min(limit - doneSoFar, sizeof(buffer)); + if (n == 0) return doneSoFar; + + return input.tryRead(buffer, 1, sizeof(buffer)) + .then([this](size_t amount) -> Promise { + if (amount == 0) return doneSoFar; // EOF + doneSoFar += amount; + return output.write(buffer, amount) + .then([this]() { + return pump(); + }); + }); + } + +private: + AsyncInputStream& input; + AsyncOutputStream& output; + uint64_t limit; + uint64_t doneSoFar = 0; + byte buffer[4096]; +}; + +} // namespace + +Promise AsyncInputStream::pumpTo( + AsyncOutputStream& output, uint64_t amount) { + // See if output wants to dispatch on us. + KJ_IF_MAYBE(result, output.tryPumpFrom(*this, amount)) { + return kj::mv(*result); + } + + // OK, fall back to naive approach. + auto pump = heap(*this, output, amount); + auto promise = pump->pump(); + return promise.attach(kj::mv(pump)); +} + +namespace { + +class AllReader { +public: + AllReader(AsyncInputStream& input): input(input) {} + + Promise> readAllBytes() { + return loop().then([this](uint64_t size) { + auto out = heapArray(size); + copyInto(out); + return out; + }); + } + + Promise readAllText() { + return loop().then([this](uint64_t size) { + auto out = heapArray(size + 1); + copyInto(out.slice(0, out.size() - 1).asBytes()); + out.back() = '\0'; + return String(kj::mv(out)); + }); + } + +private: + AsyncInputStream& input; + Vector> parts; + + Promise loop(uint64_t total = 0) { + auto part = heapArray(4096); + auto partPtr = part.asPtr(); + parts.add(kj::mv(part)); + return input.tryRead(partPtr.begin(), partPtr.size(), partPtr.size()) + .then([this,KJ_CPCAP(partPtr),total](size_t amount) -> Promise { + uint64_t newTotal = total + amount; + if (amount < partPtr.size()) { + return newTotal; + } else { + return loop(newTotal); + } + }); + } + + void copyInto(ArrayPtr out) { + size_t pos = 0; + for (auto& part: parts) { + size_t n = kj::min(part.size(), out.size() - pos); + memcpy(out.begin() + pos, part.begin(), n); + pos += n; + } + } +}; + +} // namespace + +Promise> AsyncInputStream::readAllBytes() { + auto reader = kj::heap(*this); + auto promise = reader->readAllBytes(); + return promise.attach(kj::mv(reader)); +} + +Promise AsyncInputStream::readAllText() { + auto reader = kj::heap(*this); + auto promise = reader->readAllText(); + return promise.attach(kj::mv(reader)); +} + +Maybe> AsyncOutputStream::tryPumpFrom( + AsyncInputStream& input, uint64_t amount) { + return nullptr; +} + +void AsyncIoStream::getsockopt(int level, int option, void* value, uint* length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void AsyncIoStream::setsockopt(int level, int option, const void* value, uint length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void AsyncIoStream::getsockname(struct sockaddr* addr, uint* length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void AsyncIoStream::getpeername(struct sockaddr* addr, uint* length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void ConnectionReceiver::getsockopt(int level, int option, void* value, uint* length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void ConnectionReceiver::setsockopt(int level, int option, const void* value, uint length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void DatagramPort::getsockopt(int level, int option, void* value, uint* length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +void DatagramPort::setsockopt(int level, int option, const void* value, uint length) { + KJ_UNIMPLEMENTED("Not a socket."); +} +Own NetworkAddress::bindDatagramPort() { + KJ_UNIMPLEMENTED("Datagram sockets not implemented."); +} +Own LowLevelAsyncIoProvider::wrapDatagramSocketFd(Fd fd, uint flags) { + KJ_UNIMPLEMENTED("Datagram sockets not implemented."); +} + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-io.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-io.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,560 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_IO_H_ +#define KJ_ASYNC_IO_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async.h" +#include "function.h" +#include "thread.h" +#include "time.h" + +struct sockaddr; + +namespace kj { + +#if _WIN32 +class Win32EventPort; +#else +class UnixEventPort; +#endif + +class NetworkAddress; +class AsyncOutputStream; + +// ======================================================================================= +// Streaming I/O + +class AsyncInputStream { + // Asynchronous equivalent of InputStream (from io.h). + +public: + virtual Promise read(void* buffer, size_t minBytes, size_t maxBytes); + virtual Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; + + Promise read(void* buffer, size_t bytes); + + virtual Maybe tryGetLength(); + // Get the remaining number of bytes that will be produced by this stream, if known. + // + // This is used e.g. to fill in the Content-Length header of an HTTP message. If unknown, the + // HTTP implementation may need to fall back to Transfer-Encoding: chunked. + // + // The default implementation always returns null. + + virtual Promise pumpTo( + AsyncOutputStream& output, uint64_t amount = kj::maxValue); + // Read `amount` bytes from this stream (or to EOF) and write them to `output`, returning the + // total bytes actually pumped (which is only less than `amount` if EOF was reached). + // + // Override this if your stream type knows how to pump itself to certain kinds of output + // streams more efficiently than via the naive approach. You can use + // kj::dynamicDowncastIfAvailable() to test for stream types you recognize, and if none match, + // delegate to the default implementation. + // + // The default implementation first tries calling output.tryPumpFrom(), but if that fails, it + // performs a naive pump by allocating a buffer and reading to it / writing from it in a loop. + + Promise> readAllBytes(); + Promise readAllText(); + // Read until EOF and return as one big byte array or string. +}; + +class AsyncOutputStream { + // Asynchronous equivalent of OutputStream (from io.h). + +public: + virtual Promise write(const void* buffer, size_t size) = 0; + virtual Promise write(ArrayPtr> pieces) = 0; + + virtual Maybe> tryPumpFrom( + AsyncInputStream& input, uint64_t amount = kj::maxValue); + // Implements double-dispatch for AsyncInputStream::pumpTo(). + // + // This method should only be called from within an implementation of pumpTo(). + // + // This method examines the type of `input` to find optimized ways to pump data from it to this + // output stream. If it finds one, it performs the pump. Otherwise, it returns null. + // + // The default implementation always returns null. +}; + +class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream { + // A combination input and output stream. + +public: + virtual void shutdownWrite() = 0; + // Cleanly shut down just the write end of the stream, while keeping the read end open. + + virtual void abortRead() {} + // Similar to shutdownWrite, but this will shut down the read end of the stream, and should only + // be called when an error has occurred. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception + // if the stream is not a socket or the option is not appropriate for the socket type. The + // default implementations always throw "unimplemented". + + virtual void getsockname(struct sockaddr* addr, uint* length); + virtual void getpeername(struct sockaddr* addr, uint* length); + // Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented" + // exception if the stream is not a socket. The default implementations always throw + // "unimplemented". + // + // Note that we don't provide methods that return NetworkAddress because it usually wouldn't + // be useful. You can't connect() to or listen() on these addresses, obviously, because they are + // ephemeral addresses for a single connection. +}; + +struct OneWayPipe { + // A data pipe with an input end and an output end. (Typically backed by pipe() system call.) + + Own in; + Own out; +}; + +struct TwoWayPipe { + // A data pipe that supports sending in both directions. Each end's output sends data to the + // other end's input. (Typically backed by socketpair() system call.) + + Own ends[2]; +}; + +class ConnectionReceiver { + // Represents a server socket listening on a port. + +public: + virtual Promise> accept() = 0; + // Accept the next incoming connection. + + virtual uint getPort() = 0; + // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't + // specify a port when constructing the NetworkAddress -- one will have been assigned + // automatically. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Same as the methods of AsyncIoStream. +}; + +// ======================================================================================= +// Datagram I/O + +class AncillaryMessage { + // Represents an ancillary message (aka control message) received using the recvmsg() system + // call (or equivalent). Most apps will not use this. + +public: + inline AncillaryMessage(int level, int type, ArrayPtr data); + AncillaryMessage() = default; + + inline int getLevel() const; + // Originating protocol / socket level. + + inline int getType() const; + // Protocol-specific message type. + + template + inline Maybe as(); + // Interpret the ancillary message as the given struct type. Most ancillary messages are some + // sort of struct, so this is a convenient way to access it. Returns nullptr if the message + // is smaller than the struct -- this can happen if the message was truncated due to + // insufficient ancillary buffer space. + + template + inline ArrayPtr asArray(); + // Interpret the ancillary message as an array of items. If the message size does not evenly + // divide into elements of type T, the remainder is discarded -- this can happen if the message + // was truncated due to insufficient ancillary buffer space. + +private: + int level; + int type; + ArrayPtr data; + // Message data. In most cases you should use `as()` or `asArray()`. +}; + +class DatagramReceiver { + // Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's + // capacity in advance; if a received packet is larger than the capacity, it will be truncated. + +public: + virtual Promise receive() = 0; + // Receive a new message, overwriting this object's content. + // + // receive() may reuse the same buffers for content and ancillary data with each call. + + template + struct MaybeTruncated { + T value; + + bool isTruncated; + // True if the Receiver's capacity was insufficient to receive the value and therefore the + // value is truncated. + }; + + virtual MaybeTruncated> getContent() = 0; + // Get the content of the datagram. + + virtual MaybeTruncated> getAncillary() = 0; + // Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr + // struct. Most apps don't need this. + // + // If the returned value is truncated, then the last message in the array may itself be + // truncated, meaning its as() method will return nullptr or its asArray() method will + // return fewer elements than expected. Truncation can also mean that additional messages were + // available but discarded. + + virtual NetworkAddress& getSource() = 0; + // Get the datagram sender's address. + + struct Capacity { + size_t content = 8192; + // How much space to allocate for the datagram content. If a datagram is received that is + // larger than this, it will be truncated, with no way to recover the tail. + + size_t ancillary = 0; + // How much space to allocate for ancillary messages. As with content, if the ancillary data + // is larger than this, it will be truncated. + }; +}; + +class DatagramPort { +public: + virtual Promise send(const void* buffer, size_t size, NetworkAddress& destination) = 0; + virtual Promise send(ArrayPtr> pieces, + NetworkAddress& destination) = 0; + + virtual Own makeReceiver( + DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0; + // Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much + // space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`. + + virtual uint getPort() = 0; + // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't + // specify a port when constructing the NetworkAddress -- one will have been assigned + // automatically. + + virtual void getsockopt(int level, int option, void* value, uint* length); + virtual void setsockopt(int level, int option, const void* value, uint length); + // Same as the methods of AsyncIoStream. +}; + +// ======================================================================================= +// Networks + +class NetworkAddress { + // Represents a remote address to which the application can connect. + +public: + virtual Promise> connect() = 0; + // Make a new connection to this address. + // + // The address must not be a wildcard ("*"). If it is an IP address, it must have a port number. + + virtual Own listen() = 0; + // Listen for incoming connections on this address. + // + // The address must be local. + + virtual Own bindDatagramPort(); + // Open this address as a datagram (e.g. UDP) port. + // + // The address must be local. + + virtual Own clone() = 0; + // Returns an equivalent copy of this NetworkAddress. + + virtual String toString() = 0; + // Produce a human-readable string which hopefully can be passed to Network::parseAddress() + // to reproduce this address, although whether or not that works of course depends on the Network + // implementation. This should be called only to display the address to human users, who will + // hopefully know what they are able to do with it. +}; + +class Network { + // Factory for NetworkAddress instances, representing the network services offered by the + // operating system. + // + // This interface typically represents broad authority, and well-designed code should limit its + // use to high-level startup code and user interaction. Low-level APIs should accept + // NetworkAddress instances directly and work from there, if at all possible. + +public: + virtual Promise> parseAddress(StringPtr addr, uint portHint = 0) = 0; + // Construct a network address from a user-provided string. The format of the address + // strings is not specified at the API level, and application code should make no assumptions + // about them. These strings should always be provided by humans, and said humans will know + // what format to use in their particular context. + // + // `portHint`, if provided, specifies the "standard" IP port number for the application-level + // service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a + // port number, this port will be used. If `addr` lacks a port number *and* `portHint` is + // omitted, then the returned address will only support listen() and bindDatagramPort() + // (not connect()), and an unused port will be chosen each time one of those methods is called. + + virtual Own getSockaddr(const void* sockaddr, uint len) = 0; + // Construct a network address from a legacy struct sockaddr. +}; + +// ======================================================================================= +// I/O Provider + +class AsyncIoProvider { + // Class which constructs asynchronous wrappers around the operating system's I/O facilities. + // + // Generally, the implementation of this interface must integrate closely with a particular + // `EventLoop` implementation. Typically, the EventLoop implementation itself will provide + // an AsyncIoProvider. + +public: + virtual OneWayPipe newOneWayPipe() = 0; + // Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with + // the pipe(2) system call). + + virtual TwoWayPipe newTwoWayPipe() = 0; + // Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with + // socketpair(2) system call). Data written to one end can be read from the other. + + virtual Network& getNetwork() = 0; + // Creates a new `Network` instance representing the networks exposed by the operating system. + // + // DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If + // you call this from low-level code, then you are preventing higher-level code from injecting an + // alternative implementation. Instead, if your code needs to use network functionality, it + // should ask for a `Network` as a constructor or method parameter, so that higher-level code can + // chose what implementation to use. The system network is essentially a singleton. See: + // http://www.object-oriented-security.org/lets-argue/singletons + // + // Code that uses the system network should not make any assumptions about what kinds of + // addresses it will parse, as this could differ across platforms. String addresses should come + // strictly from the user, who will know how to write them correctly for their system. + // + // With that said, KJ currently supports the following string address formats: + // - IPv4: "1.2.3.4", "1.2.3.4:80" + // - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80" + // - Local IP wildcard (covers both v4 and v6): "*", "*:80" + // - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http" + // - Unix domain: "unix:/path/to/socket" + + struct PipeThread { + // A combination of a thread and a two-way pipe that communicates with that thread. + // + // The fields are intentionally ordered so that the pipe will be destroyed (and therefore + // disconnected) before the thread is destroyed (and therefore joined). Thus if the thread + // arranges to exit when it detects disconnect, destruction should be clean. + + Own thread; + Own pipe; + }; + + virtual PipeThread newPipeThread( + Function startFunc) = 0; + // Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate + // with it. One end of the pipe is passed to the thread's start function and the other end of + // the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will + // already have an active `EventLoop` when `startFunc` is called. + // + // TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too + // much at once but I'm not sure how to cleanly break it down. + + virtual Timer& getTimer() = 0; + // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- + // it only updates when the event loop polls for system events. This means that calling `now()` + // on this timer does not require a system call. + // + // This timer is not affected by changes to the system date. It is unspecified whether the timer + // continues to count while the system is suspended. +}; + +class LowLevelAsyncIoProvider { + // Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on + // different operating systems. You should prefer to use `AsyncIoProvider` over this interface + // whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection. + // + // On Unix, this interface can be used to import native file descriptors into the async framework. + // Different implementations of this interface might work on top of different event handling + // primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library. + // + // On Windows, this interface can be used to import native HANDLEs into the async framework. + // Different implementations of this interface might work on top of different event handling + // primitives, such as I/O completion ports vs. completion routines. + // + // TODO(port): Actually implement Windows support. + +public: + // --------------------------------------------------------------------------- + // Unix-specific stuff + + enum Flags { + // Flags controlling how to wrap a file descriptor. + + TAKE_OWNERSHIP = 1 << 0, + // The returned object should own the file descriptor, automatically closing it when destroyed. + // The close-on-exec flag will be set on the descriptor if it is not already. + // + // If this flag is not used, then the file descriptor is not automatically closed and the + // close-on-exec flag is not modified. + +#if !_WIN32 + ALREADY_CLOEXEC = 1 << 1, + // Indicates that the close-on-exec flag is known already to be set, so need not be set again. + // Only relevant when combined with TAKE_OWNERSHIP. + // + // On Linux, all system calls which yield new file descriptors have flags or variants which + // set the close-on-exec flag immediately. Unfortunately, other OS's do not. + + ALREADY_NONBLOCK = 1 << 2 + // Indicates that the file descriptor is known already to be in non-blocking mode, so the flag + // need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode + // automatically. + // + // On Linux, all system calls which yield new file descriptors have flags or variants which + // enable non-blocking mode immediately. Unfortunately, other OS's do not. +#endif + }; + +#if _WIN32 + typedef uintptr_t Fd; + // On Windows, the `fd` parameter to each of these methods must be a SOCKET, and must have the + // flag WSA_FLAG_OVERLAPPED (which socket() uses by default, but WSASocket() wants you to specify + // explicitly). +#else + typedef int Fd; + // On Unix, any arbitrary file descriptor is supported. +#endif + + virtual Own wrapInputFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncInputStream wrapping a file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapOutputFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncOutputStream wrapping a file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapSocketFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a socket file descriptor. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Promise> wrapConnectingSocketFd( + Fd fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a socket and initiate a connection to the given address. + // The returned promise does not resolve until connection has completed. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapListenSocketFd(Fd fd, uint flags = 0) = 0; + // Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already + // have had `bind()` and `listen()` called on it, so it's ready for `accept()`. + // + // `flags` is a bitwise-OR of the values of the `Flags` enum. + + virtual Own wrapDatagramSocketFd(Fd fd, uint flags = 0); + + virtual Timer& getTimer() = 0; + // Returns a `Timer` based on real time. Time does not pass while event handlers are running -- + // it only updates when the event loop polls for system events. This means that calling `now()` + // on this timer does not require a system call. + // + // This timer is not affected by changes to the system date. It is unspecified whether the timer + // continues to count while the system is suspended. +}; + +Own newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel); +// Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`. + +struct AsyncIoContext { + Own lowLevelProvider; + Own provider; + WaitScope& waitScope; + +#if _WIN32 + Win32EventPort& win32EventPort; +#else + UnixEventPort& unixEventPort; + // TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This + // field will go away at some point when we have a chance to improve these interfaces. +#endif +}; + +AsyncIoContext setupAsyncIo(); +// Convenience method which sets up the current thread with everything it needs to do async I/O. +// The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for +// doing I/O on the host system, so everything is ready for the thread to start making async calls +// and waiting on promises. +// +// You would typically call this in your main() loop or in the start function of a thread. +// Example: +// +// int main() { +// auto ioContext = kj::setupAsyncIo(); +// +// // Now we can call an async function. +// Promise textPromise = getHttp(*ioContext.provider, "http://example.com"); +// +// // And we can wait for the promise to complete. Note that you can only use `wait()` +// // from the top level, not from inside a promise callback. +// String text = textPromise.wait(ioContext.waitScope); +// print(text); +// return 0; +// } +// +// WARNING: An AsyncIoContext can only be used in the thread and process that created it. In +// particular, note that after a fork(), an AsyncIoContext created in the parent process will +// not work correctly in the child, even if the parent ceases to use its copy. In particular +// note that this means that server processes which daemonize themselves at startup must wait +// until after daemonization to create an AsyncIoContext. + +// ======================================================================================= +// inline implementation details + +inline AncillaryMessage::AncillaryMessage( + int level, int type, ArrayPtr data) + : level(level), type(type), data(data) {} + +inline int AncillaryMessage::getLevel() const { return level; } +inline int AncillaryMessage::getType() const { return type; } + +template +inline Maybe AncillaryMessage::as() { + if (data.size() >= sizeof(T)) { + return *reinterpret_cast(data.begin()); + } else { + return nullptr; + } +} + +template +inline ArrayPtr AncillaryMessage::asArray() { + return arrayPtr(reinterpret_cast(data.begin()), data.size() / sizeof(T)); +} + +} // namespace kj + +#endif // KJ_ASYNC_IO_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-prelude.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-prelude.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,218 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file contains a bunch of internal declarations that must appear before async.h can start. +// We don't define these directly in async.h because it makes the file hard to read. + +#ifndef KJ_ASYNC_PRELUDE_H_ +#define KJ_ASYNC_PRELUDE_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "exception.h" +#include "tuple.h" + +namespace kj { + +class EventLoop; +template +class Promise; +class WaitScope; + +template +Promise> joinPromises(Array>&& promises); +Promise joinPromises(Array>&& promises); + +namespace _ { // private + +template struct JoinPromises_ { typedef T Type; }; +template struct JoinPromises_> { typedef T Type; }; + +template +using JoinPromises = typename JoinPromises_::Type; +// If T is Promise, resolves to U, otherwise resolves to T. +// +// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely +// unrelated. + +class PropagateException { + // A functor which accepts a kj::Exception as a parameter and returns a broken promise of + // arbitrary type which simply propagates the exception. +public: + class Bottom { + public: + Bottom(Exception&& exception): exception(kj::mv(exception)) {} + + Exception asException() { return kj::mv(exception); } + + private: + Exception exception; + }; + + Bottom operator()(Exception&& e) { + return Bottom(kj::mv(e)); + } + Bottom operator()(const Exception& e) { + return Bottom(kj::cp(e)); + } +}; + +template +struct ReturnType_ { typedef decltype(instance()(instance())) Type; }; +template +struct ReturnType_ { typedef decltype(instance()()) Type; }; + +template +using ReturnType = typename ReturnType_::Type; +// The return type of functor Func given a parameter of type T, with the special exception that if +// T is void, this is the return type of Func called with no arguments. + +template struct SplitTuplePromise_ { typedef Promise Type; }; +template +struct SplitTuplePromise_> { + typedef kj::Tuple>...> Type; +}; + +template +using SplitTuplePromise = typename SplitTuplePromise_::Type; +// T -> Promise +// Tuple -> Tuple> + +struct Void {}; +// Application code should NOT refer to this! See `kj::READY_NOW` instead. + +template struct FixVoid_ { typedef T Type; }; +template <> struct FixVoid_ { typedef Void Type; }; +template using FixVoid = typename FixVoid_::Type; +// FixVoid is just T unless T is void in which case it is _::Void (an empty struct). + +template struct UnfixVoid_ { typedef T Type; }; +template <> struct UnfixVoid_ { typedef void Type; }; +template using UnfixVoid = typename UnfixVoid_::Type; +// UnfixVoid is the opposite of FixVoid. + +template +struct MaybeVoidCaller { + // Calls the function converting a Void input to an empty parameter list and a void return + // value to a Void output. + + template + static inline Out apply(Func& func, In&& in) { + return func(kj::mv(in)); + } +}; +template +struct MaybeVoidCaller { + template + static inline Out apply(Func& func, In& in) { + return func(in); + } +}; +template +struct MaybeVoidCaller { + template + static inline Out apply(Func& func, Void&& in) { + return func(); + } +}; +template +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, In&& in) { + func(kj::mv(in)); + return Void(); + } +}; +template +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, In& in) { + func(in); + return Void(); + } +}; +template <> +struct MaybeVoidCaller { + template + static inline Void apply(Func& func, Void&& in) { + func(); + return Void(); + } +}; + +template +inline T&& returnMaybeVoid(T&& t) { + return kj::fwd(t); +} +inline void returnMaybeVoid(Void&& v) {} + +class ExceptionOrValue; +class PromiseNode; +class ChainPromiseNode; +template +class ForkHub; + +class TaskSetImpl; + +class Event; + +class PromiseBase { +public: + kj::String trace(); + // Dump debug info about this promise. + +private: + Own node; + + PromiseBase() = default; + PromiseBase(Own&& node): node(kj::mv(node)) {} + + friend class kj::EventLoop; + friend class ChainPromiseNode; + template + friend class kj::Promise; + friend class TaskSetImpl; + template + friend Promise> kj::joinPromises(Array>&& promises); + friend Promise kj::joinPromises(Array>&& promises); +}; + +void detach(kj::Promise&& promise); +void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope); +Promise yield(); +Own neverDone(); + +class NeverDone { +public: + template + operator Promise() const { + return Promise(false, neverDone()); + } + + KJ_NORETURN(void wait(WaitScope& waitScope) const); +}; + +} // namespace _ (private) +} // namespace kj + +#endif // KJ_ASYNC_PRELUDE_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,752 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "async.h" +#include "debug.h" +#include + +namespace kj { +namespace { + +#if !_MSC_VER +// TODO(msvc): GetFunctorStartAddress is not supported on MSVC currently, so skip the test. +TEST(Async, GetFunctorStartAddress) { + EXPECT_TRUE(nullptr != _::GetFunctorStartAddress<>::apply([](){return 0;})); +} +#endif + +TEST(Async, EvalVoid) { + EventLoop loop; + WaitScope waitScope(loop); + + bool done = false; + + Promise promise = evalLater([&]() { done = true; }); + EXPECT_FALSE(done); + promise.wait(waitScope); + EXPECT_TRUE(done); +} + +TEST(Async, EvalInt) { + EventLoop loop; + WaitScope waitScope(loop); + + bool done = false; + + Promise promise = evalLater([&]() { done = true; return 123; }); + EXPECT_FALSE(done); + EXPECT_EQ(123, promise.wait(waitScope)); + EXPECT_TRUE(done); +} + +TEST(Async, There) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise a = 123; + bool done = false; + + Promise promise = a.then([&](int ai) { done = true; return ai + 321; }); + EXPECT_FALSE(done); + EXPECT_EQ(444, promise.wait(waitScope)); + EXPECT_TRUE(done); +} + +TEST(Async, ThereVoid) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise a = 123; + int value = 0; + + Promise promise = a.then([&](int ai) { value = ai; }); + EXPECT_EQ(0, value); + promise.wait(waitScope); + EXPECT_EQ(123, value); +} + +TEST(Async, Exception) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater( + [&]() -> int { KJ_FAIL_ASSERT("foo") { return 123; } }); + EXPECT_TRUE(kj::runCatchingExceptions([&]() { + // wait() only returns when compiling with -fno-exceptions. + EXPECT_EQ(123, promise.wait(waitScope)); + }) != nullptr); +} + +TEST(Async, HandleException) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater( + [&]() -> int { KJ_FAIL_ASSERT("foo") { return 123; } }); + int line = __LINE__ - 1; + + promise = promise.then( + [](int i) { return i + 1; }, + [&](Exception&& e) { EXPECT_EQ(line, e.getLine()); return 345; }); + + EXPECT_EQ(345, promise.wait(waitScope)); +} + +TEST(Async, PropagateException) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater( + [&]() -> int { KJ_FAIL_ASSERT("foo") { return 123; } }); + int line = __LINE__ - 1; + + promise = promise.then([](int i) { return i + 1; }); + + promise = promise.then( + [](int i) { return i + 2; }, + [&](Exception&& e) { EXPECT_EQ(line, e.getLine()); return 345; }); + + EXPECT_EQ(345, promise.wait(waitScope)); +} + +TEST(Async, PropagateExceptionTypeChange) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater( + [&]() -> int { KJ_FAIL_ASSERT("foo") { return 123; } }); + int line = __LINE__ - 1; + + Promise promise2 = promise.then([](int i) -> StringPtr { return "foo"; }); + + promise2 = promise2.then( + [](StringPtr s) -> StringPtr { return "bar"; }, + [&](Exception&& e) -> StringPtr { EXPECT_EQ(line, e.getLine()); return "baz"; }); + + EXPECT_EQ("baz", promise2.wait(waitScope)); +} + +TEST(Async, Then) { + EventLoop loop; + WaitScope waitScope(loop); + + bool done = false; + + Promise promise = Promise(123).then([&](int i) { + done = true; + return i + 321; + }); + + EXPECT_FALSE(done); + + EXPECT_EQ(444, promise.wait(waitScope)); + + EXPECT_TRUE(done); +} + +TEST(Async, Chain) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater([&]() -> int { return 123; }); + Promise promise2 = evalLater([&]() -> int { return 321; }); + + auto promise3 = promise.then([&](int i) { + return promise2.then([i](int j) { + return i + j; + }); + }); + + EXPECT_EQ(444, promise3.wait(waitScope)); +} + +TEST(Async, DeepChain) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = NEVER_DONE; + + // Create a ridiculous chain of promises. + for (uint i = 0; i < 1000; i++) { + promise = evalLater(mvCapture(promise, [](Promise promise) { + return kj::mv(promise); + })); + } + + loop.run(); + + auto trace = promise.trace(); + uint lines = 0; + for (char c: trace) { + lines += c == '\n'; + } + + // Chain nodes should have been collapsed such that instead of a chain of 1000 nodes, we have + // 2-ish nodes. We'll give a little room for implementation freedom. + EXPECT_LT(lines, 5); +} + +TEST(Async, DeepChain2) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = nullptr; + promise = evalLater([&]() { + auto trace = promise.trace(); + uint lines = 0; + for (char c: trace) { + lines += c == '\n'; + } + + // Chain nodes should have been collapsed such that instead of a chain of 1000 nodes, we have + // 2-ish nodes. We'll give a little room for implementation freedom. + EXPECT_LT(lines, 5); + }); + + // Create a ridiculous chain of promises. + for (uint i = 0; i < 1000; i++) { + promise = evalLater(mvCapture(promise, [](Promise promise) { + return kj::mv(promise); + })); + } + + promise.wait(waitScope); +} + +Promise makeChain(uint i) { + if (i > 0) { + return evalLater([i]() -> Promise { + return makeChain(i - 1); + }); + } else { + return NEVER_DONE; + } +} + +TEST(Async, DeepChain3) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = makeChain(1000); + + loop.run(); + + auto trace = promise.trace(); + uint lines = 0; + for (char c: trace) { + lines += c == '\n'; + } + + // Chain nodes should have been collapsed such that instead of a chain of 1000 nodes, we have + // 2-ish nodes. We'll give a little room for implementation freedom. + EXPECT_LT(lines, 5); +} + +Promise makeChain2(uint i, Promise promise) { + if (i > 0) { + return evalLater(mvCapture(promise, [i](Promise&& promise) -> Promise { + return makeChain2(i - 1, kj::mv(promise)); + })); + } else { + return kj::mv(promise); + } +} + +TEST(Async, DeepChain4) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = nullptr; + promise = evalLater([&]() { + auto trace = promise.trace(); + uint lines = 0; + for (char c: trace) { + lines += c == '\n'; + } + + // Chain nodes should have been collapsed such that instead of a chain of 1000 nodes, we have + // 2-ish nodes. We'll give a little room for implementation freedom. + EXPECT_LT(lines, 5); + }); + + promise = makeChain2(1000, kj::mv(promise)); + + promise.wait(waitScope); +} + +TEST(Async, IgnoreResult) { + EventLoop loop; + WaitScope waitScope(loop); + + bool done = false; + + Promise promise = Promise(123).then([&](int i) { + done = true; + return i + 321; + }).ignoreResult(); + + EXPECT_FALSE(done); + + promise.wait(waitScope); + + EXPECT_TRUE(done); +} + +TEST(Async, SeparateFulfiller) { + EventLoop loop; + WaitScope waitScope(loop); + + auto pair = newPromiseAndFulfiller(); + + EXPECT_TRUE(pair.fulfiller->isWaiting()); + pair.fulfiller->fulfill(123); + EXPECT_FALSE(pair.fulfiller->isWaiting()); + + EXPECT_EQ(123, pair.promise.wait(waitScope)); +} + +TEST(Async, SeparateFulfillerVoid) { + EventLoop loop; + WaitScope waitScope(loop); + + auto pair = newPromiseAndFulfiller(); + + EXPECT_TRUE(pair.fulfiller->isWaiting()); + pair.fulfiller->fulfill(); + EXPECT_FALSE(pair.fulfiller->isWaiting()); + + pair.promise.wait(waitScope); +} + +TEST(Async, SeparateFulfillerCanceled) { + auto pair = newPromiseAndFulfiller(); + + EXPECT_TRUE(pair.fulfiller->isWaiting()); + pair.promise = nullptr; + EXPECT_FALSE(pair.fulfiller->isWaiting()); +} + +TEST(Async, SeparateFulfillerChained) { + EventLoop loop; + WaitScope waitScope(loop); + + auto pair = newPromiseAndFulfiller>(); + auto inner = newPromiseAndFulfiller(); + + EXPECT_TRUE(pair.fulfiller->isWaiting()); + pair.fulfiller->fulfill(kj::mv(inner.promise)); + EXPECT_FALSE(pair.fulfiller->isWaiting()); + + inner.fulfiller->fulfill(123); + + EXPECT_EQ(123, pair.promise.wait(waitScope)); +} + +TEST(Async, SeparateFulfillerDiscarded) { + EventLoop loop; + WaitScope waitScope(loop); + + auto pair = newPromiseAndFulfiller(); + pair.fulfiller = nullptr; + + EXPECT_ANY_THROW(pair.promise.wait(waitScope)); +} + +TEST(Async, SeparateFulfillerMemoryLeak) { + auto paf = kj::newPromiseAndFulfiller(); + paf.fulfiller->fulfill(); +} + +TEST(Async, Ordering) { + EventLoop loop; + WaitScope waitScope(loop); + + int counter = 0; + Promise promises[6] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; + + promises[1] = evalLater([&]() { + EXPECT_EQ(0, counter++); + + { + // Use a promise and fulfiller so that we can fulfill the promise after waiting on it in + // order to induce depth-first scheduling. + auto paf = kj::newPromiseAndFulfiller(); + promises[2] = paf.promise.then([&]() { + EXPECT_EQ(1, counter++); + }).eagerlyEvaluate(nullptr); + paf.fulfiller->fulfill(); + } + + // .then() is scheduled breadth-first if the promise has already resolved, but depth-first + // if the promise resolves later. + promises[3] = Promise(READY_NOW).then([&]() { + EXPECT_EQ(4, counter++); + }).then([&]() { + EXPECT_EQ(5, counter++); + }).eagerlyEvaluate(nullptr); + + { + auto paf = kj::newPromiseAndFulfiller(); + promises[4] = paf.promise.then([&]() { + EXPECT_EQ(2, counter++); + }).eagerlyEvaluate(nullptr); + paf.fulfiller->fulfill(); + } + + // evalLater() is like READY_NOW.then(). + promises[5] = evalLater([&]() { + EXPECT_EQ(6, counter++); + }).eagerlyEvaluate(nullptr); + }).eagerlyEvaluate(nullptr); + + promises[0] = evalLater([&]() { + EXPECT_EQ(3, counter++); + + // Making this a chain should NOT cause it to preempt promises[1]. (This was a problem at one + // point.) + return Promise(READY_NOW); + }).eagerlyEvaluate(nullptr); + + for (auto i: indices(promises)) { + kj::mv(promises[i]).wait(waitScope); + } + + EXPECT_EQ(7, counter); +} + +TEST(Async, Fork) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater([&]() { return 123; }); + + auto fork = promise.fork(); + + auto branch1 = fork.addBranch().then([](int i) { + EXPECT_EQ(123, i); + return 456; + }); + auto branch2 = fork.addBranch().then([](int i) { + EXPECT_EQ(123, i); + return 789; + }); + + { + auto releaseFork = kj::mv(fork); + } + + EXPECT_EQ(456, branch1.wait(waitScope)); + EXPECT_EQ(789, branch2.wait(waitScope)); +} + +struct RefcountedInt: public Refcounted { + RefcountedInt(int i): i(i) {} + int i; + Own addRef() { return kj::addRef(*this); } +}; + +TEST(Async, ForkRef) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise> promise = evalLater([&]() { + return refcounted(123); + }); + + auto fork = promise.fork(); + + auto branch1 = fork.addBranch().then([](Own&& i) { + EXPECT_EQ(123, i->i); + return 456; + }); + auto branch2 = fork.addBranch().then([](Own&& i) { + EXPECT_EQ(123, i->i); + return 789; + }); + + { + auto releaseFork = kj::mv(fork); + } + + EXPECT_EQ(456, branch1.wait(waitScope)); + EXPECT_EQ(789, branch2.wait(waitScope)); +} + +TEST(Async, Split) { + EventLoop loop; + WaitScope waitScope(loop); + + Promise>> promise = evalLater([&]() { + return kj::tuple(123, str("foo"), Promise(321)); + }); + + Tuple, Promise, Promise> split = promise.split(); + + EXPECT_EQ(123, get<0>(split).wait(waitScope)); + EXPECT_EQ("foo", get<1>(split).wait(waitScope)); + EXPECT_EQ(321, get<2>(split).wait(waitScope)); +} + +TEST(Async, ExclusiveJoin) { + { + EventLoop loop; + WaitScope waitScope(loop); + + auto left = evalLater([&]() { return 123; }); + auto right = newPromiseAndFulfiller(); // never fulfilled + + EXPECT_EQ(123, left.exclusiveJoin(kj::mv(right.promise)).wait(waitScope)); + } + + { + EventLoop loop; + WaitScope waitScope(loop); + + auto left = newPromiseAndFulfiller(); // never fulfilled + auto right = evalLater([&]() { return 123; }); + + EXPECT_EQ(123, left.promise.exclusiveJoin(kj::mv(right)).wait(waitScope)); + } + + { + EventLoop loop; + WaitScope waitScope(loop); + + auto left = evalLater([&]() { return 123; }); + auto right = evalLater([&]() { return 456; }); + + EXPECT_EQ(123, left.exclusiveJoin(kj::mv(right)).wait(waitScope)); + } + + { + EventLoop loop; + WaitScope waitScope(loop); + + auto left = evalLater([&]() { return 123; }); + auto right = evalLater([&]() { return 456; }).eagerlyEvaluate(nullptr); + + EXPECT_EQ(456, left.exclusiveJoin(kj::mv(right)).wait(waitScope)); + } +} + +TEST(Async, ArrayJoin) { + EventLoop loop; + WaitScope waitScope(loop); + + auto builder = heapArrayBuilder>(3); + builder.add(123); + builder.add(456); + builder.add(789); + + Promise> promise = joinPromises(builder.finish()); + + auto result = promise.wait(waitScope); + + ASSERT_EQ(3u, result.size()); + EXPECT_EQ(123, result[0]); + EXPECT_EQ(456, result[1]); + EXPECT_EQ(789, result[2]); +} + +TEST(Async, ArrayJoinVoid) { + EventLoop loop; + WaitScope waitScope(loop); + + auto builder = heapArrayBuilder>(3); + builder.add(READY_NOW); + builder.add(READY_NOW); + builder.add(READY_NOW); + + Promise promise = joinPromises(builder.finish()); + + promise.wait(waitScope); +} + +class ErrorHandlerImpl: public TaskSet::ErrorHandler { +public: + uint exceptionCount = 0; + void taskFailed(kj::Exception&& exception) override { + EXPECT_TRUE(exception.getDescription().endsWith("example TaskSet failure")); + ++exceptionCount; + } +}; + +TEST(Async, TaskSet) { + EventLoop loop; + WaitScope waitScope(loop); + ErrorHandlerImpl errorHandler; + TaskSet tasks(errorHandler); + + int counter = 0; + + tasks.add(evalLater([&]() { + EXPECT_EQ(0, counter++); + })); + tasks.add(evalLater([&]() { + EXPECT_EQ(1, counter++); + KJ_FAIL_ASSERT("example TaskSet failure") { break; } + })); + tasks.add(evalLater([&]() { + EXPECT_EQ(2, counter++); + })); + + (void)evalLater([&]() { + KJ_FAIL_EXPECT("Promise without waiter shouldn't execute."); + }); + + evalLater([&]() { + EXPECT_EQ(3, counter++); + }).wait(waitScope); + + EXPECT_EQ(4, counter); + EXPECT_EQ(1u, errorHandler.exceptionCount); +} + +class DestructorDetector { +public: + DestructorDetector(bool& setTrue): setTrue(setTrue) {} + ~DestructorDetector() { setTrue = true; } + +private: + bool& setTrue; +}; + +TEST(Async, Attach) { + bool destroyed = false; + + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = evalLater([&]() { + EXPECT_FALSE(destroyed); + return 123; + }).attach(kj::heap(destroyed)); + + promise = promise.then([&](int i) { + EXPECT_TRUE(destroyed); + return i + 321; + }); + + EXPECT_FALSE(destroyed); + EXPECT_EQ(444, promise.wait(waitScope)); + EXPECT_TRUE(destroyed); +} + +TEST(Async, EagerlyEvaluate) { + bool called = false; + + EventLoop loop; + WaitScope waitScope(loop); + + Promise promise = Promise(READY_NOW).then([&]() { + called = true; + }); + evalLater([]() {}).wait(waitScope); + + EXPECT_FALSE(called); + + promise = promise.eagerlyEvaluate(nullptr); + + evalLater([]() {}).wait(waitScope); + + EXPECT_TRUE(called); +} + +TEST(Async, Detach) { + EventLoop loop; + WaitScope waitScope(loop); + + bool ran1 = false; + bool ran2 = false; + bool ran3 = false; + + (void)evalLater([&]() { ran1 = true; }); // let returned promise be destroyed (canceled) + evalLater([&]() { ran2 = true; }).detach([](kj::Exception&&) { ADD_FAILURE(); }); + evalLater([]() { KJ_FAIL_ASSERT("foo"){break;} }).detach([&](kj::Exception&& e) { ran3 = true; }); + + EXPECT_FALSE(ran1); + EXPECT_FALSE(ran2); + EXPECT_FALSE(ran3); + + evalLater([]() {}).wait(waitScope); + + EXPECT_FALSE(ran1); + EXPECT_TRUE(ran2); + EXPECT_TRUE(ran3); +} + +class DummyEventPort: public EventPort { +public: + bool runnable = false; + int callCount = 0; + + bool wait() override { KJ_FAIL_ASSERT("Nothing to wait for."); } + bool poll() override { return false; } + void setRunnable(bool runnable) override { + this->runnable = runnable; + ++callCount; + } +}; + +TEST(Async, SetRunnable) { + DummyEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + EXPECT_FALSE(port.runnable); + EXPECT_EQ(0, port.callCount); + + { + auto promise = evalLater([]() {}).eagerlyEvaluate(nullptr); + + EXPECT_TRUE(port.runnable); + loop.run(1); + EXPECT_FALSE(port.runnable); + EXPECT_EQ(2, port.callCount); + + promise.wait(waitScope); + EXPECT_FALSE(port.runnable); + EXPECT_EQ(4, port.callCount); + } + + { + auto paf = newPromiseAndFulfiller(); + auto promise = paf.promise.then([]() {}).eagerlyEvaluate(nullptr); + EXPECT_FALSE(port.runnable); + + auto promise2 = evalLater([]() {}).eagerlyEvaluate(nullptr); + paf.fulfiller->fulfill(); + + EXPECT_TRUE(port.runnable); + loop.run(1); + EXPECT_TRUE(port.runnable); + loop.run(10); + EXPECT_FALSE(port.runnable); + + promise.wait(waitScope); + EXPECT_FALSE(port.runnable); + + EXPECT_EQ(8, port.callCount); + } +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-unix-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-unix-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,608 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !_WIN32 + +#include "async-unix.h" +#include "thread.h" +#include "debug.h" +#include "io.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kj { +namespace { + +inline void delay() { usleep(10000); } + +// On OSX, si_code seems to be zero when SI_USER is expected. +#if __linux__ || __CYGWIN__ +#define EXPECT_SI_CODE EXPECT_EQ +#else +#define EXPECT_SI_CODE(a,b) +#endif + +void captureSignals() { + static bool captured = false; + if (!captured) { + captured = true; + + // We use SIGIO and SIGURG as our test signals because they're two signals that we can be + // reasonably confident won't otherwise be delivered to any KJ or Cap'n Proto test. We can't + // use SIGUSR1 because it is reserved by UnixEventPort and SIGUSR2 is used by Valgrind on OSX. + UnixEventPort::captureSignal(SIGURG); + UnixEventPort::captureSignal(SIGIO); + } +} + +TEST(AsyncUnixTest, Signals) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + kill(getpid(), SIGURG); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); +} + +#if defined(SIGRTMIN) && !__BIONIC__ && !(__linux__ && __mips__) +TEST(AsyncUnixTest, SignalWithValue) { + // This tests that if we use sigqueue() to attach a value to the signal, that value is received + // correctly. Note that this only works on platforms that support real-time signals -- even + // though the signal we're sending is SIGURG, the sigqueue() system call is introduced by RT + // signals. Hence this test won't run on e.g. Mac OSX. + // + // Also, Android's bionic does not appear to support sigqueue() even though the kernel does. + // + // Also, this test fails on Linux on mipsel. si_value comes back as zero. No one with a mips + // machine wants to debug the problem but they demand a patch fixing it, so we disable the test. + // Sad. https://github.com/sandstorm-io/capnproto/issues/204 + + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + union sigval value; + memset(&value, 0, sizeof(value)); + value.sival_int = 123; + sigqueue(getpid(), SIGURG, value); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_QUEUE, info.si_code); + EXPECT_EQ(123, info.si_value.sival_int); +} + +TEST(AsyncUnixTest, SignalWithPointerValue) { + // This tests that if we use sigqueue() to attach a value to the signal, that value is received + // correctly. Note that this only works on platforms that support real-time signals -- even + // though the signal we're sending is SIGURG, the sigqueue() system call is introduced by RT + // signals. Hence this test won't run on e.g. Mac OSX. + // + // Also, Android's bionic does not appear to support sigqueue() even though the kernel does. + // + // Also, this test fails on Linux on mipsel. si_value comes back as zero. No one with a mips + // machine wants to debug the problem but they demand a patch fixing it, so we disable the test. + // Sad. https://github.com/sandstorm-io/capnproto/issues/204 + + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + union sigval value; + memset(&value, 0, sizeof(value)); + value.sival_ptr = &port; + sigqueue(getpid(), SIGURG, value); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_QUEUE, info.si_code); + EXPECT_EQ(&port, info.si_value.sival_ptr); +} +#endif + +TEST(AsyncUnixTest, SignalsMultiListen) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + port.onSignal(SIGIO).then([](siginfo_t&&) { + KJ_FAIL_EXPECT("Received wrong signal."); + }).detach([](kj::Exception&& exception) { + KJ_FAIL_EXPECT(exception); + }); + + kill(getpid(), SIGURG); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); +} + +#if !__CYGWIN32__ +// Cygwin32 (but not Cygwin64) appears not to deliver SIGURG in the following test (but it does +// deliver SIGIO, if you reverse the order of the waits). Since this doesn't occur on any other +// platform I'm assuming it's a Cygwin bug. + +TEST(AsyncUnixTest, SignalsMultiReceive) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + kill(getpid(), SIGURG); + kill(getpid(), SIGIO); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); + + info = port.onSignal(SIGIO).wait(waitScope); + EXPECT_EQ(SIGIO, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); +} + +#endif // !__CYGWIN32__ + +TEST(AsyncUnixTest, SignalsAsync) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + // Arrange for a signal to be sent from another thread. + pthread_t mainThread = pthread_self(); + Thread thread([&]() { + delay(); + pthread_kill(mainThread, SIGURG); + }); + + siginfo_t info = port.onSignal(SIGURG).wait(waitScope); + EXPECT_EQ(SIGURG, info.si_signo); +#if __linux__ + EXPECT_SI_CODE(SI_TKILL, info.si_code); +#endif +} + +#if !__CYGWIN32__ +// Cygwin32 (but not Cygwin64) appears not to deliver SIGURG in the following test (but it does +// deliver SIGIO, if you reverse the order of the waits). Since this doesn't occur on any other +// platform I'm assuming it's a Cygwin bug. + +TEST(AsyncUnixTest, SignalsNoWait) { + // Verify that UnixEventPort::poll() correctly receives pending signals. + + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + bool receivedSigurg = false; + bool receivedSigio = false; + port.onSignal(SIGURG).then([&](siginfo_t&& info) { + receivedSigurg = true; + EXPECT_EQ(SIGURG, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); + }).detach([](Exception&& e) { KJ_FAIL_EXPECT(e); }); + port.onSignal(SIGIO).then([&](siginfo_t&& info) { + receivedSigio = true; + EXPECT_EQ(SIGIO, info.si_signo); + EXPECT_SI_CODE(SI_USER, info.si_code); + }).detach([](Exception&& e) { KJ_FAIL_EXPECT(e); }); + + kill(getpid(), SIGURG); + kill(getpid(), SIGIO); + + EXPECT_FALSE(receivedSigurg); + EXPECT_FALSE(receivedSigio); + + loop.run(); + + EXPECT_FALSE(receivedSigurg); + EXPECT_FALSE(receivedSigio); + + port.poll(); + + EXPECT_FALSE(receivedSigurg); + EXPECT_FALSE(receivedSigio); + + loop.run(); + + EXPECT_TRUE(receivedSigurg); + EXPECT_TRUE(receivedSigio); +} + +#endif // !__CYGWIN32__ + +TEST(AsyncUnixTest, ReadObserver) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + kj::AutoCloseFd infd(pipefds[0]), outfd(pipefds[1]); + + UnixEventPort::FdObserver observer(port, infd, UnixEventPort::FdObserver::OBSERVE_READ); + + KJ_SYSCALL(write(outfd, "foo", 3)); + + observer.whenBecomesReadable().wait(waitScope); + +#if __linux__ // platform known to support POLLRDHUP + EXPECT_FALSE(KJ_ASSERT_NONNULL(observer.atEndHint())); + + char buffer[4096]; + ssize_t n; + KJ_SYSCALL(n = read(infd, &buffer, sizeof(buffer))); + EXPECT_EQ(3, n); + + KJ_SYSCALL(write(outfd, "bar", 3)); + outfd = nullptr; + + observer.whenBecomesReadable().wait(waitScope); + + EXPECT_TRUE(KJ_ASSERT_NONNULL(observer.atEndHint())); +#endif +} + +TEST(AsyncUnixTest, ReadObserverMultiListen) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + int bogusPipefds[2]; + KJ_SYSCALL(pipe(bogusPipefds)); + KJ_DEFER({ close(bogusPipefds[1]); close(bogusPipefds[0]); }); + + UnixEventPort::FdObserver bogusObserver(port, bogusPipefds[0], + UnixEventPort::FdObserver::OBSERVE_READ); + + bogusObserver.whenBecomesReadable().then([]() { + ADD_FAILURE() << "Received wrong poll."; + }).detach([](kj::Exception&& exception) { + ADD_FAILURE() << kj::str(exception).cStr(); + }); + + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); }); + + UnixEventPort::FdObserver observer(port, pipefds[0], + UnixEventPort::FdObserver::OBSERVE_READ); + KJ_SYSCALL(write(pipefds[1], "foo", 3)); + + observer.whenBecomesReadable().wait(waitScope); +} + +TEST(AsyncUnixTest, ReadObserverMultiReceive) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); }); + + UnixEventPort::FdObserver observer(port, pipefds[0], + UnixEventPort::FdObserver::OBSERVE_READ); + KJ_SYSCALL(write(pipefds[1], "foo", 3)); + + int pipefds2[2]; + KJ_SYSCALL(pipe(pipefds2)); + KJ_DEFER({ close(pipefds2[1]); close(pipefds2[0]); }); + + UnixEventPort::FdObserver observer2(port, pipefds2[0], + UnixEventPort::FdObserver::OBSERVE_READ); + KJ_SYSCALL(write(pipefds2[1], "bar", 3)); + + auto promise1 = observer.whenBecomesReadable(); + auto promise2 = observer2.whenBecomesReadable(); + promise1.wait(waitScope); + promise2.wait(waitScope); +} + +TEST(AsyncUnixTest, ReadObserverAsync) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + // Make a pipe and wait on its read end while another thread writes to it. + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); }); + UnixEventPort::FdObserver observer(port, pipefds[0], + UnixEventPort::FdObserver::OBSERVE_READ); + + Thread thread([&]() { + delay(); + KJ_SYSCALL(write(pipefds[1], "foo", 3)); + }); + + // Wait for the event in this thread. + observer.whenBecomesReadable().wait(waitScope); +} + +TEST(AsyncUnixTest, ReadObserverNoWait) { + // Verify that UnixEventPort::poll() correctly receives pending FD events. + + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); }); + UnixEventPort::FdObserver observer(port, pipefds[0], + UnixEventPort::FdObserver::OBSERVE_READ); + + int pipefds2[2]; + KJ_SYSCALL(pipe(pipefds2)); + KJ_DEFER({ close(pipefds2[1]); close(pipefds2[0]); }); + UnixEventPort::FdObserver observer2(port, pipefds2[0], + UnixEventPort::FdObserver::OBSERVE_READ); + + int receivedCount = 0; + observer.whenBecomesReadable().then([&]() { + receivedCount++; + }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); }); + observer2.whenBecomesReadable().then([&]() { + receivedCount++; + }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); }); + + KJ_SYSCALL(write(pipefds[1], "foo", 3)); + KJ_SYSCALL(write(pipefds2[1], "bar", 3)); + + EXPECT_EQ(0, receivedCount); + + loop.run(); + + EXPECT_EQ(0, receivedCount); + + port.poll(); + + EXPECT_EQ(0, receivedCount); + + loop.run(); + + EXPECT_EQ(2, receivedCount); +} + +static void setNonblocking(int fd) { + int flags; + KJ_SYSCALL(flags = fcntl(fd, F_GETFL)); + if ((flags & O_NONBLOCK) == 0) { + KJ_SYSCALL(fcntl(fd, F_SETFL, flags | O_NONBLOCK)); + } +} + +TEST(AsyncUnixTest, WriteObserver) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + int pipefds[2]; + KJ_SYSCALL(pipe(pipefds)); + kj::AutoCloseFd infd(pipefds[0]), outfd(pipefds[1]); + setNonblocking(outfd); + setNonblocking(infd); + + UnixEventPort::FdObserver observer(port, outfd, UnixEventPort::FdObserver::OBSERVE_WRITE); + + // Fill buffer. + ssize_t n; + do { + KJ_NONBLOCKING_SYSCALL(n = write(outfd, "foo", 3)); + } while (n >= 0); + + bool writable = false; + auto promise = observer.whenBecomesWritable() + .then([&]() { writable = true; }).eagerlyEvaluate(nullptr); + + loop.run(); + port.poll(); + loop.run(); + + EXPECT_FALSE(writable); + + // Empty the read end so that the write end becomes writable. Note that Linux implements a + // high watermark / low watermark heuristic which means that only reading one byte is not + // sufficient. The amount we have to read is in fact architecture-dependent -- it appears to be + // 1 page. To be safe, we read everything. + char buffer[4096]; + do { + KJ_NONBLOCKING_SYSCALL(n = read(infd, &buffer, sizeof(buffer))); + } while (n > 0); + + loop.run(); + port.poll(); + loop.run(); + + EXPECT_TRUE(writable); +} + +#if !__APPLE__ +// Disabled on macOS due to https://github.com/sandstorm-io/capnproto/issues/374. +TEST(AsyncUnixTest, UrgentObserver) { + // Verify that FdObserver correctly detects availability of out-of-band data. + // Availability of out-of-band data is implementation-specific. + // Linux's and OS X's TCP/IP stack supports out-of-band messages for TCP sockets, which is used + // for this test. + + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + int tmpFd; + char c; + + // Spawn a TCP server + KJ_SYSCALL(tmpFd = socket(AF_INET, SOCK_STREAM, 0)); + kj::AutoCloseFd serverFd(tmpFd); + sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + KJ_SYSCALL(bind(serverFd, reinterpret_cast(&saddr), sizeof(saddr))); + socklen_t saddrLen = sizeof(saddr); + KJ_SYSCALL(getsockname(serverFd, reinterpret_cast(&saddr), &saddrLen)); + KJ_SYSCALL(listen(serverFd, 1)); + + // Accept one connection, send in-band and OOB byte, wait for a quit message + Thread thread([&]() { + int tmpFd; + char c; + + sockaddr_in caddr; + socklen_t caddrLen = sizeof(caddr); + KJ_SYSCALL(tmpFd = accept(serverFd, reinterpret_cast(&caddr), &caddrLen)); + kj::AutoCloseFd clientFd(tmpFd); + delay(); + + // Workaround: OS X won't signal POLLPRI without POLLIN. Also enqueue some in-band data. + c = 'i'; + KJ_SYSCALL(send(clientFd, &c, 1, 0)); + c = 'o'; + KJ_SYSCALL(send(clientFd, &c, 1, MSG_OOB)); + + KJ_SYSCALL(recv(clientFd, &c, 1, 0)); + EXPECT_EQ('q', c); + }); + KJ_DEFER({ shutdown(serverFd, SHUT_RDWR); serverFd = nullptr; }); + + KJ_SYSCALL(tmpFd = socket(AF_INET, SOCK_STREAM, 0)); + kj::AutoCloseFd clientFd(tmpFd); + KJ_SYSCALL(connect(clientFd, reinterpret_cast(&saddr), saddrLen)); + + UnixEventPort::FdObserver observer(port, clientFd, + UnixEventPort::FdObserver::OBSERVE_READ | UnixEventPort::FdObserver::OBSERVE_URGENT); + + observer.whenUrgentDataAvailable().wait(waitScope); + +#if __CYGWIN__ + // On Cygwin, reading the urgent byte first causes the subsequent regular read to block until + // such a time as the connection closes -- and then the byte is successfully returned. This + // seems to be a cygwin bug. + KJ_SYSCALL(recv(clientFd, &c, 1, 0)); + EXPECT_EQ('i', c); + KJ_SYSCALL(recv(clientFd, &c, 1, MSG_OOB)); + EXPECT_EQ('o', c); +#else + // Attempt to read the urgent byte prior to reading the in-band byte. + KJ_SYSCALL(recv(clientFd, &c, 1, MSG_OOB)); + EXPECT_EQ('o', c); + KJ_SYSCALL(recv(clientFd, &c, 1, 0)); + EXPECT_EQ('i', c); +#endif + + // Allow server thread to let its clientFd go out of scope. + c = 'q'; + KJ_SYSCALL(send(clientFd, &c, 1, 0)); + KJ_SYSCALL(shutdown(clientFd, SHUT_RDWR)); +} +#endif + +TEST(AsyncUnixTest, SteadyTimers) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + auto& timer = port.getTimer(); + + auto start = timer.now(); + kj::Vector expected; + kj::Vector actual; + + auto addTimer = [&](Duration delay) { + expected.add(max(start + delay, start)); + timer.atTime(start + delay).then([&]() { + actual.add(timer.now()); + }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); }); + }; + + addTimer(30 * MILLISECONDS); + addTimer(40 * MILLISECONDS); + addTimer(20350 * MICROSECONDS); + addTimer(30 * MILLISECONDS); + addTimer(-10 * MILLISECONDS); + + std::sort(expected.begin(), expected.end()); + timer.atTime(expected.back() + MILLISECONDS).wait(waitScope); + + ASSERT_EQ(expected.size(), actual.size()); + for (int i = 0; i < expected.size(); ++i) { + KJ_EXPECT(expected[i] <= actual[i], "Actual time for timer i is too early.", + i, ((expected[i] - actual[i]) / NANOSECONDS)); + } +} + +TEST(AsyncUnixTest, Wake) { + captureSignals(); + UnixEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + EXPECT_FALSE(port.poll()); + port.wake(); + EXPECT_TRUE(port.poll()); + EXPECT_FALSE(port.poll()); + + port.wake(); + EXPECT_TRUE(port.wait()); + + { + auto promise = port.getTimer().atTime(port.getTimer().now()); + EXPECT_FALSE(port.wait()); + } + + bool woken = false; + Thread thread([&]() { + delay(); + woken = true; + port.wake(); + }); + + EXPECT_TRUE(port.wait()); +} + +} // namespace +} // namespace kj + +#endif // !_WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-unix.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-unix.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,789 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !_WIN32 + +#include "async-unix.h" +#include "debug.h" +#include "threadlocal.h" +#include +#include +#include +#include +#include +#include + +#if KJ_USE_EPOLL +#include +#include +#include +#include +#else +#include +#endif + +namespace kj { + +// ======================================================================================= +// Timer code common to multiple implementations + +TimePoint UnixEventPort::readClock() { + return origin() + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count() * NANOSECONDS; +} + +// ======================================================================================= +// Signal code common to multiple implementations + +namespace { + +int reservedSignal = SIGUSR1; +bool tooLateToSetReserved = false; + +struct SignalCapture { + sigjmp_buf jumpTo; + siginfo_t siginfo; +}; + +#if !KJ_USE_EPOLL // on Linux we'll use signalfd +KJ_THREADLOCAL_PTR(SignalCapture) threadCapture = nullptr; + +void signalHandler(int, siginfo_t* siginfo, void*) { + SignalCapture* capture = threadCapture; + if (capture != nullptr) { + capture->siginfo = *siginfo; + siglongjmp(capture->jumpTo, 1); + } +} +#endif + +void registerSignalHandler(int signum) { + tooLateToSetReserved = true; + + sigset_t mask; + KJ_SYSCALL(sigemptyset(&mask)); + KJ_SYSCALL(sigaddset(&mask, signum)); + KJ_SYSCALL(sigprocmask(SIG_BLOCK, &mask, nullptr)); + +#if !KJ_USE_EPOLL // on Linux we'll use signalfd + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signalHandler; + KJ_SYSCALL(sigfillset(&action.sa_mask)); + action.sa_flags = SA_SIGINFO; + KJ_SYSCALL(sigaction(signum, &action, nullptr)); +#endif +} + +void registerReservedSignal() { + registerSignalHandler(reservedSignal); + + // We also disable SIGPIPE because users of UnixEventPort almost certainly don't want it. + while (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + int error = errno; + if (error != EINTR) { + KJ_FAIL_SYSCALL("signal(SIGPIPE, SIG_IGN)", error); + } + } +} + +pthread_once_t registerReservedSignalOnce = PTHREAD_ONCE_INIT; + +} // namespace + +class UnixEventPort::SignalPromiseAdapter { +public: + inline SignalPromiseAdapter(PromiseFulfiller& fulfiller, + UnixEventPort& loop, int signum) + : loop(loop), signum(signum), fulfiller(fulfiller) { + prev = loop.signalTail; + *loop.signalTail = this; + loop.signalTail = &next; + } + + ~SignalPromiseAdapter() noexcept(false) { + if (prev != nullptr) { + if (next == nullptr) { + loop.signalTail = prev; + } else { + next->prev = prev; + } + *prev = next; + } + } + + SignalPromiseAdapter* removeFromList() { + auto result = next; + if (next == nullptr) { + loop.signalTail = prev; + } else { + next->prev = prev; + } + *prev = next; + next = nullptr; + prev = nullptr; + return result; + } + + UnixEventPort& loop; + int signum; + PromiseFulfiller& fulfiller; + SignalPromiseAdapter* next = nullptr; + SignalPromiseAdapter** prev = nullptr; +}; + +Promise UnixEventPort::onSignal(int signum) { + return newAdaptedPromise(*this, signum); +} + +void UnixEventPort::captureSignal(int signum) { + if (reservedSignal == SIGUSR1) { + KJ_REQUIRE(signum != SIGUSR1, + "Sorry, SIGUSR1 is reserved by the UnixEventPort implementation. You may call " + "UnixEventPort::setReservedSignal() to reserve a different signal."); + } else { + KJ_REQUIRE(signum != reservedSignal, + "Can't capture signal reserved using setReservedSignal().", signum); + } + registerSignalHandler(signum); +} + +void UnixEventPort::setReservedSignal(int signum) { + KJ_REQUIRE(!tooLateToSetReserved, + "setReservedSignal() must be called before any calls to `captureSignal()` and " + "before any `UnixEventPort` is constructed."); + if (reservedSignal != SIGUSR1 && reservedSignal != signum) { + KJ_FAIL_REQUIRE("Detected multiple conflicting calls to setReservedSignal(). Please only " + "call this once, or always call it with the same signal number."); + } + reservedSignal = signum; +} + +void UnixEventPort::gotSignal(const siginfo_t& siginfo) { + // Fire any events waiting on this signal. + auto ptr = signalHead; + while (ptr != nullptr) { + if (ptr->signum == siginfo.si_signo) { + ptr->fulfiller.fulfill(kj::cp(siginfo)); + ptr = ptr->removeFromList(); + } else { + ptr = ptr->next; + } + } +} + +#if KJ_USE_EPOLL +// ======================================================================================= +// epoll FdObserver implementation + +UnixEventPort::UnixEventPort() + : timerImpl(readClock()), + epollFd(-1), + signalFd(-1), + eventFd(-1) { + pthread_once(®isterReservedSignalOnce, ®isterReservedSignal); + + int fd; + KJ_SYSCALL(fd = epoll_create1(EPOLL_CLOEXEC)); + epollFd = AutoCloseFd(fd); + + KJ_SYSCALL(sigemptyset(&signalFdSigset)); + KJ_SYSCALL(fd = signalfd(-1, &signalFdSigset, SFD_NONBLOCK | SFD_CLOEXEC)); + signalFd = AutoCloseFd(fd); + + KJ_SYSCALL(fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + eventFd = AutoCloseFd(fd); + + + struct epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = EPOLLIN; + event.data.u64 = 0; + KJ_SYSCALL(epoll_ctl(epollFd, EPOLL_CTL_ADD, signalFd, &event)); + event.data.u64 = 1; + KJ_SYSCALL(epoll_ctl(epollFd, EPOLL_CTL_ADD, eventFd, &event)); +} + +UnixEventPort::~UnixEventPort() noexcept(false) {} + +UnixEventPort::FdObserver::FdObserver(UnixEventPort& eventPort, int fd, uint flags) + : eventPort(eventPort), fd(fd), flags(flags) { + struct epoll_event event; + memset(&event, 0, sizeof(event)); + + if (flags & OBSERVE_READ) { + event.events |= EPOLLIN | EPOLLRDHUP; + } + if (flags & OBSERVE_WRITE) { + event.events |= EPOLLOUT; + } + if (flags & OBSERVE_URGENT) { + event.events |= EPOLLPRI; + } + event.events |= EPOLLET; // Set edge-triggered mode. + + event.data.ptr = this; + + KJ_SYSCALL(epoll_ctl(eventPort.epollFd, EPOLL_CTL_ADD, fd, &event)); +} + +UnixEventPort::FdObserver::~FdObserver() noexcept(false) { + KJ_SYSCALL(epoll_ctl(eventPort.epollFd, EPOLL_CTL_DEL, fd, nullptr)) { break; } +} + +void UnixEventPort::FdObserver::fire(short events) { + if (events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR)) { + if (events & (EPOLLHUP | EPOLLRDHUP)) { + atEnd = true; + } else { + // Since we didn't receive EPOLLRDHUP, we know that we're not at the end. + atEnd = false; + } + + KJ_IF_MAYBE(f, readFulfiller) { + f->get()->fulfill(); + readFulfiller = nullptr; + } + } + + if (events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) { + KJ_IF_MAYBE(f, writeFulfiller) { + f->get()->fulfill(); + writeFulfiller = nullptr; + } + } + + if (events & EPOLLPRI) { + KJ_IF_MAYBE(f, urgentFulfiller) { + f->get()->fulfill(); + urgentFulfiller = nullptr; + } + } +} + +Promise UnixEventPort::FdObserver::whenBecomesReadable() { + KJ_REQUIRE(flags & OBSERVE_READ, "FdObserver was not set to observe reads."); + + auto paf = newPromiseAndFulfiller(); + readFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +Promise UnixEventPort::FdObserver::whenBecomesWritable() { + KJ_REQUIRE(flags & OBSERVE_WRITE, "FdObserver was not set to observe writes."); + + auto paf = newPromiseAndFulfiller(); + writeFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +Promise UnixEventPort::FdObserver::whenUrgentDataAvailable() { + KJ_REQUIRE(flags & OBSERVE_URGENT, + "FdObserver was not set to observe availability of urgent data."); + + auto paf = newPromiseAndFulfiller(); + urgentFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +bool UnixEventPort::wait() { + return doEpollWait( + timerImpl.timeoutToNextEvent(readClock(), MILLISECONDS, int(maxValue)) + .map([](uint64_t t) -> int { return t; }) + .orDefault(-1)); +} + +bool UnixEventPort::poll() { + return doEpollWait(0); +} + +void UnixEventPort::wake() const { + uint64_t one = 1; + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = write(eventFd, &one, sizeof(one))); + KJ_ASSERT(n < 0 || n == sizeof(one)); +} + +static siginfo_t toRegularSiginfo(const struct signalfd_siginfo& siginfo) { + // Unfortunately, siginfo_t is mostly a big union and the correct set of fields to fill in + // depends on the type of signal. OTOH, signalfd_siginfo is a flat struct that expands all + // siginfo_t's union fields out to be non-overlapping. We can't just copy all the fields over + // because of the unions; we have to carefully figure out which fields are appropriate to fill + // in for this signal. Ick. + + siginfo_t result; + memset(&result, 0, sizeof(result)); + + result.si_signo = siginfo.ssi_signo; + result.si_errno = siginfo.ssi_errno; + result.si_code = siginfo.ssi_code; + + if (siginfo.ssi_code > 0) { + // Signal originated from the kernel. The structure of the siginfo depends primarily on the + // signal number. + + switch (siginfo.ssi_signo) { + case SIGCHLD: + result.si_pid = siginfo.ssi_pid; + result.si_uid = siginfo.ssi_uid; + result.si_status = siginfo.ssi_status; + result.si_utime = siginfo.ssi_utime; + result.si_stime = siginfo.ssi_stime; + break; + + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + result.si_addr = reinterpret_cast(static_cast(siginfo.ssi_addr)); +#ifdef si_trapno + result.si_trapno = siginfo.ssi_trapno; +#endif +#ifdef si_addr_lsb + // ssi_addr_lsb is defined as coming immediately after ssi_addr in the kernel headers but + // apparently the userspace headers were never updated. So we do a pointer hack. :( + result.si_addr_lsb = *reinterpret_cast(&siginfo.ssi_addr + 1); +#endif + break; + + case SIGIO: + static_assert(SIGIO == SIGPOLL, "SIGIO != SIGPOLL?"); + + // Note: Technically, code can arrange for SIGIO signals to be delivered with a signal number + // other than SIGIO. AFAICT there is no way for us to detect this in the siginfo. Luckily + // SIGIO is totally obsoleted by epoll so it shouldn't come up. + + result.si_band = siginfo.ssi_band; + result.si_fd = siginfo.ssi_fd; + break; + + case SIGSYS: + // Apparently SIGSYS's fields are not available in signalfd_siginfo? + break; + } + + } else { + // Signal originated from userspace. The sender could specify whatever signal number they + // wanted. The structure of the signal is determined by the API they used, which is identified + // by SI_CODE. + + switch (siginfo.ssi_code) { + case SI_USER: + case SI_TKILL: + // kill(), tkill(), or tgkill(). + result.si_pid = siginfo.ssi_pid; + result.si_uid = siginfo.ssi_uid; + break; + + case SI_QUEUE: + case SI_MESGQ: + case SI_ASYNCIO: + default: + result.si_pid = siginfo.ssi_pid; + result.si_uid = siginfo.ssi_uid; + + // This is awkward. In siginfo_t, si_ptr and si_int are in a union together. In + // signalfd_siginfo, they are not. We don't really know whether the app intended to send + // an int or a pointer. Presumably since the pointer is always larger than the int, if + // we write the pointer, we'll end up with the right value for the int? Presumably the + // two fields of signalfd_siginfo are actually extracted from one of these unions + // originally, so actually contain redundant data? Better write some tests... + // + // Making matters even stranger, siginfo.ssi_ptr is 64-bit even on 32-bit systems, and + // it appears that instead of doing the obvious thing by casting the pointer value to + // 64 bits, the kernel actually memcpy()s the 32-bit value into the 64-bit space. As + // a result, on big-endian 32-bit systems, the original pointer value ends up in the + // *upper* 32 bits of siginfo.ssi_ptr, which is totally weird. We play along and use + // a memcpy() on our end too, to get the right result on all platforms. + memcpy(&result.si_ptr, &siginfo.ssi_ptr, sizeof(result.si_ptr)); + break; + + case SI_TIMER: + result.si_timerid = siginfo.ssi_tid; + result.si_overrun = siginfo.ssi_overrun; + + // Again with this weirdness... + result.si_ptr = reinterpret_cast(static_cast(siginfo.ssi_ptr)); + break; + } + } + + return result; +} + +bool UnixEventPort::doEpollWait(int timeout) { + sigset_t newMask; + sigemptyset(&newMask); + + { + auto ptr = signalHead; + while (ptr != nullptr) { + sigaddset(&newMask, ptr->signum); + ptr = ptr->next; + } + } + + if (memcmp(&newMask, &signalFdSigset, sizeof(newMask)) != 0) { + // Apparently we're not waiting on the same signals as last time. Need to update the signal + // FD's mask. + signalFdSigset = newMask; + KJ_SYSCALL(signalfd(signalFd, &signalFdSigset, SFD_NONBLOCK | SFD_CLOEXEC)); + } + + struct epoll_event events[16]; + int n; + KJ_SYSCALL(n = epoll_wait(epollFd, events, kj::size(events), timeout)); + + bool woken = false; + + for (int i = 0; i < n; i++) { + if (events[i].data.u64 == 0) { + for (;;) { + struct signalfd_siginfo siginfo; + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = read(signalFd, &siginfo, sizeof(siginfo))); + if (n < 0) break; // no more signals + + KJ_ASSERT(n == sizeof(siginfo)); + + gotSignal(toRegularSiginfo(siginfo)); + } + } else if (events[i].data.u64 == 1) { + // Someone called wake() from another thread. Consume the event. + uint64_t value; + ssize_t n; + KJ_NONBLOCKING_SYSCALL(n = read(eventFd, &value, sizeof(value))); + KJ_ASSERT(n < 0 || n == sizeof(value)); + + // We were woken. Need to return true. + woken = true; + } else { + FdObserver* observer = reinterpret_cast(events[i].data.ptr); + observer->fire(events[i].events); + } + } + + timerImpl.advanceTo(readClock()); + + return woken; +} + +#else // KJ_USE_EPOLL +// ======================================================================================= +// Traditional poll() FdObserver implementation. + +#ifndef POLLRDHUP +#define POLLRDHUP 0 +#endif + +UnixEventPort::UnixEventPort() + : timerImpl(readClock()) { + static_assert(sizeof(threadId) >= sizeof(pthread_t), + "pthread_t is larger than a long long on your platform. Please port."); + *reinterpret_cast(&threadId) = pthread_self(); + + pthread_once(®isterReservedSignalOnce, ®isterReservedSignal); +} + +UnixEventPort::~UnixEventPort() noexcept(false) {} + +UnixEventPort::FdObserver::FdObserver(UnixEventPort& eventPort, int fd, uint flags) + : eventPort(eventPort), fd(fd), flags(flags), next(nullptr), prev(nullptr) {} + +UnixEventPort::FdObserver::~FdObserver() noexcept(false) { + if (prev != nullptr) { + if (next == nullptr) { + eventPort.observersTail = prev; + } else { + next->prev = prev; + } + *prev = next; + } +} + +void UnixEventPort::FdObserver::fire(short events) { + if (events & (POLLIN | POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) { + if (events & (POLLHUP | POLLRDHUP)) { + atEnd = true; +#if POLLRDHUP + } else { + // Since POLLRDHUP exists on this platform, and we didn't receive it, we know that we're not + // at the end. + atEnd = false; +#endif + } + + KJ_IF_MAYBE(f, readFulfiller) { + f->get()->fulfill(); + readFulfiller = nullptr; + } + } + + if (events & (POLLOUT | POLLHUP | POLLERR | POLLNVAL)) { + KJ_IF_MAYBE(f, writeFulfiller) { + f->get()->fulfill(); + writeFulfiller = nullptr; + } + } + + if (events & POLLPRI) { + KJ_IF_MAYBE(f, urgentFulfiller) { + f->get()->fulfill(); + urgentFulfiller = nullptr; + } + } + + if (readFulfiller == nullptr && writeFulfiller == nullptr && urgentFulfiller == nullptr) { + // Remove from list. + if (next == nullptr) { + eventPort.observersTail = prev; + } else { + next->prev = prev; + } + *prev = next; + next = nullptr; + prev = nullptr; + } +} + +short UnixEventPort::FdObserver::getEventMask() { + return (readFulfiller == nullptr ? 0 : (POLLIN | POLLRDHUP)) | + (writeFulfiller == nullptr ? 0 : POLLOUT) | + (urgentFulfiller == nullptr ? 0 : POLLPRI); +} + +Promise UnixEventPort::FdObserver::whenBecomesReadable() { + KJ_REQUIRE(flags & OBSERVE_READ, "FdObserver was not set to observe reads."); + + if (prev == nullptr) { + KJ_DASSERT(next == nullptr); + prev = eventPort.observersTail; + *prev = this; + eventPort.observersTail = &next; + } + + auto paf = newPromiseAndFulfiller(); + readFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +Promise UnixEventPort::FdObserver::whenBecomesWritable() { + KJ_REQUIRE(flags & OBSERVE_WRITE, "FdObserver was not set to observe writes."); + + if (prev == nullptr) { + KJ_DASSERT(next == nullptr); + prev = eventPort.observersTail; + *prev = this; + eventPort.observersTail = &next; + } + + auto paf = newPromiseAndFulfiller(); + writeFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +Promise UnixEventPort::FdObserver::whenUrgentDataAvailable() { + KJ_REQUIRE(flags & OBSERVE_URGENT, + "FdObserver was not set to observe availability of urgent data."); + + if (prev == nullptr) { + KJ_DASSERT(next == nullptr); + prev = eventPort.observersTail; + *prev = this; + eventPort.observersTail = &next; + } + + auto paf = newPromiseAndFulfiller(); + urgentFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); +} + +class UnixEventPort::PollContext { +public: + PollContext(FdObserver* ptr) { + while (ptr != nullptr) { + struct pollfd pollfd; + memset(&pollfd, 0, sizeof(pollfd)); + pollfd.fd = ptr->fd; + pollfd.events = ptr->getEventMask(); + pollfds.add(pollfd); + pollEvents.add(ptr); + ptr = ptr->next; + } + } + + void run(int timeout) { + do { + pollResult = ::poll(pollfds.begin(), pollfds.size(), timeout); + pollError = pollResult < 0 ? errno : 0; + + // EINTR should only happen if we received a signal *other than* the ones registered via + // the UnixEventPort, so we don't care about that case. + } while (pollError == EINTR); + } + + void processResults() { + if (pollResult < 0) { + KJ_FAIL_SYSCALL("poll()", pollError); + } + + for (auto i: indices(pollfds)) { + if (pollfds[i].revents != 0) { + pollEvents[i]->fire(pollfds[i].revents); + if (--pollResult <= 0) { + break; + } + } + } + } + +private: + kj::Vector pollfds; + kj::Vector pollEvents; + int pollResult = 0; + int pollError = 0; +}; + +bool UnixEventPort::wait() { + sigset_t newMask; + sigemptyset(&newMask); + sigaddset(&newMask, reservedSignal); + + { + auto ptr = signalHead; + while (ptr != nullptr) { + sigaddset(&newMask, ptr->signum); + ptr = ptr->next; + } + } + + PollContext pollContext(observersHead); + + // Capture signals. + SignalCapture capture; + + if (sigsetjmp(capture.jumpTo, true)) { + // We received a signal and longjmp'd back out of the signal handler. + threadCapture = nullptr; + + if (capture.siginfo.si_signo == reservedSignal) { + return true; + } else { + gotSignal(capture.siginfo); + return false; + } + } + + // Enable signals, run the poll, then mask them again. + sigset_t origMask; + threadCapture = &capture; + sigprocmask(SIG_UNBLOCK, &newMask, &origMask); + + pollContext.run( + timerImpl.timeoutToNextEvent(readClock(), MILLISECONDS, int(maxValue)) + .map([](uint64_t t) -> int { return t; }) + .orDefault(-1)); + + sigprocmask(SIG_SETMASK, &origMask, nullptr); + threadCapture = nullptr; + + // Queue events. + pollContext.processResults(); + timerImpl.advanceTo(readClock()); + + return false; +} + +bool UnixEventPort::poll() { + // volatile so that longjmp() doesn't clobber it. + volatile bool woken = false; + + sigset_t pending; + sigset_t waitMask; + sigemptyset(&pending); + sigfillset(&waitMask); + + // Count how many signals that we care about are pending. + KJ_SYSCALL(sigpending(&pending)); + uint signalCount = 0; + + if (sigismember(&pending, reservedSignal)) { + ++signalCount; + sigdelset(&pending, reservedSignal); + sigdelset(&waitMask, reservedSignal); + } + + { + auto ptr = signalHead; + while (ptr != nullptr) { + if (sigismember(&pending, ptr->signum)) { + ++signalCount; + sigdelset(&pending, ptr->signum); + sigdelset(&waitMask, ptr->signum); + } + ptr = ptr->next; + } + } + + // Wait for each pending signal. It would be nice to use sigtimedwait() here but it is not + // available on OSX. :( Instead, we call sigsuspend() once per expected signal. + while (signalCount-- > 0) { + SignalCapture capture; + threadCapture = &capture; + if (sigsetjmp(capture.jumpTo, true)) { + // We received a signal and longjmp'd back out of the signal handler. + sigdelset(&waitMask, capture.siginfo.si_signo); + if (capture.siginfo.si_signo == reservedSignal) { + woken = true; + } else { + gotSignal(capture.siginfo); + } + } else { + sigsuspend(&waitMask); + KJ_FAIL_ASSERT("sigsuspend() shouldn't return because the signal handler should " + "have siglongjmp()ed."); + } + threadCapture = nullptr; + } + + { + PollContext pollContext(observersHead); + pollContext.run(0); + pollContext.processResults(); + } + timerImpl.advanceTo(readClock()); + + return woken; +} + +void UnixEventPort::wake() const { + int error = pthread_kill(*reinterpret_cast(&threadId), reservedSignal); + if (error != 0) { + KJ_FAIL_SYSCALL("pthread_kill", error); + } +} + +#endif // KJ_USE_EPOLL, else + +} // namespace kj + +#endif // !_WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-unix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-unix.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,274 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_UNIX_H_ +#define KJ_ASYNC_UNIX_H_ + +#if _WIN32 +#error "This file is Unix-specific. On Windows, include async-win32.h instead." +#endif + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async.h" +#include "time.h" +#include "vector.h" +#include "io.h" +#include + +#if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL) +// Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h. +#define KJ_USE_EPOLL 1 +#endif + +namespace kj { + +class UnixEventPort: public EventPort { + // An EventPort implementation which can wait for events on file descriptors as well as signals. + // This API only makes sense on Unix. + // + // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue). + // To also wait on signals without race conditions, the implementation may block signals until + // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before + // the signal was unblocked, or it may use a nicer platform-specific API like signalfd. + // + // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you + // need to use SIGUSR1 for something else, you must offer a different signal by calling + // setReservedSignal() at startup. + // + // WARNING: A UnixEventPort can only be used in the thread and process that created it. In + // particular, note that after a fork(), a UnixEventPort created in the parent process will + // not work correctly in the child, even if the parent ceases to use its copy. In particular + // note that this means that server processes which daemonize themselves at startup must wait + // until after daemonization to create a UnixEventPort. + +public: + UnixEventPort(); + ~UnixEventPort() noexcept(false); + + class FdObserver; + // Class that watches an fd for readability or writability. See definition below. + + Promise onSignal(int signum); + // When the given signal is delivered to this thread, return the corresponding siginfo_t. + // The signal must have been captured using `captureSignal()`. + // + // If `onSignal()` has not been called, the signal will remain blocked in this thread. + // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the + // next call to 'onSignal()' will receive it. Also, you can control which thread receives a + // process-wide signal by only calling `onSignal()` on that thread's event loop. + // + // The result of waiting on the same signal twice at once is undefined. + + static void captureSignal(int signum); + // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may + // then pass it to `onSignal()`. This method is static because it registers a signal handler + // which applies process-wide. If any other threads exist in the process when `captureSignal()` + // is called, you *must* set the signal mask in those threads to block this signal, otherwise + // terrible things will happen if the signal happens to be delivered to those threads. If at + // all possible, call `captureSignal()` *before* creating threads, so that threads you create in + // the future will inherit the proper signal mask. + // + // To un-capture a signal, simply install a different signal handler and then un-block it from + // the signal mask. + + static void setReservedSignal(int signum); + // Sets the signal number which `UnixEventPort` reserves for internal use. If your application + // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before + // constructing an `UnixEventPort`) to offer a different signal. + + Timer& getTimer() { return timerImpl; } + + // implements EventPort ------------------------------------------------------ + bool wait() override; + bool poll() override; + void wake() const override; + +private: + struct TimerSet; // Defined in source file to avoid STL include. + class TimerPromiseAdapter; + class SignalPromiseAdapter; + + TimerImpl timerImpl; + + SignalPromiseAdapter* signalHead = nullptr; + SignalPromiseAdapter** signalTail = &signalHead; + + TimePoint readClock(); + void gotSignal(const siginfo_t& siginfo); + + friend class TimerPromiseAdapter; + +#if KJ_USE_EPOLL + AutoCloseFd epollFd; + AutoCloseFd signalFd; + AutoCloseFd eventFd; // Used for cross-thread wakeups. + + sigset_t signalFdSigset; + // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it + // needs updating. + + bool doEpollWait(int timeout); + +#else + class PollContext; + + FdObserver* observersHead = nullptr; + FdObserver** observersTail = &observersHead; + + unsigned long long threadId; // actually pthread_t +#endif +}; + +class UnixEventPort::FdObserver { + // Object which watches a file descriptor to determine when it is readable or writable. + // + // For listen sockets, "readable" means that there is a connection to accept(). For everything + // else, it means that read() (or recv()) will return data. + // + // The presence of out-of-band data should NOT fire this event. However, the event may + // occasionally fire spuriously (when there is actually no data to read), and one thing that can + // cause such spurious events is the arrival of OOB data on certain platforms whose event + // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX). + // + // WARNING: The exact behavior of this class differs across systems, since event interfaces + // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified + // behavior. If at all possible, use the higher-level AsyncInputStream interface instead. + +public: + enum Flags { + OBSERVE_READ = 1, + OBSERVE_WRITE = 2, + OBSERVE_URGENT = 4, + OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE + }; + + FdObserver(UnixEventPort& eventPort, int fd, uint flags); + // Begin watching the given file descriptor for readability. Only one ReadObserver may exist + // for a given file descriptor at a time. + + ~FdObserver() noexcept(false); + + KJ_DISALLOW_COPY(FdObserver); + + Promise whenBecomesReadable(); + // Resolves the next time the file descriptor transitions from having no data to read to having + // some data to read. + // + // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error + // to call this method when there is already data in the read buffer which has been there since + // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is + // unspecified whether the promise will ever resolve -- it depends on the underlying event + // mechanism being used. + // + // In order to avoid this problem, make sure that you only call `whenBecomesReadable()` + // only at times when you know the buffer is empty. You know this for sure when one of the + // following happens: + // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode + // enabled on the fd!) + // * The file descriptor is a regular byte-oriented object (like a socket or pipe), + // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()` + // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note, + // though, that for record-oriented file descriptors like Linux's inotify interface, this + // rule does not hold, because it could simply be that the next record did not fit into the + // space available.) + // + // It is an error to call `whenBecomesReadable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + + inline Maybe atEndHint() { return atEnd; } + // Returns true if the event system has indicated that EOF has been received. There may still + // be data in the read buffer, but once that is gone, there's nothing left. + // + // Returns false if the event system has indicated that EOF had NOT been received as of the + // last turn of the event loop. + // + // Returns nullptr if the event system does not know whether EOF has been reached. In this + // case, the only way to know for sure is to call read() or recv() and check if it returns + // zero. + // + // This hint may be useful as an optimization to avoid an unnecessary system call. + + Promise whenBecomesWritable(); + // Resolves the next time the file descriptor transitions from having no space available in the + // write buffer to having some space available. + // + // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error + // to call this method when there is already space in the write buffer which has been there + // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case, + // it is unspecified whether the promise will ever resolve -- it depends on the underlying + // event mechanism being used. + // + // In order to avoid this problem, make sure that you only call `whenBecomesWritable()` + // only at times when you know the buffer is full. You know this for sure when one of the + // following happens: + // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode + // enabled on the fd!) + // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can + // only happen if the buffer is full. + // + // It is an error to call `whenBecomesWritable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + + Promise whenUrgentDataAvailable(); + // Resolves the next time the file descriptor's read buffer contains "urgent" data. + // + // The conditions for availability of urgent data are specific to the file descriptor's + // underlying implementation. + // + // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously + // has not yet resolved. If you do this, the previous promise may throw an exception. + // + // WARNING: This has some known weird behavior on macOS. See + // https://github.com/sandstorm-io/capnproto/issues/374. + +private: + UnixEventPort& eventPort; + int fd; + uint flags; + + kj::Maybe>> readFulfiller; + kj::Maybe>> writeFulfiller; + kj::Maybe>> urgentFulfiller; + // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to + // null every time an event is fired. + + Maybe atEnd; + + void fire(short events); + +#if !KJ_USE_EPOLL + FdObserver* next; + FdObserver** prev; + // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller. + // If `prev` is null then the observer is not currently in the list. + + short getEventMask(); +#endif + + friend class UnixEventPort; +}; + +} // namespace kj + +#endif // KJ_ASYNC_UNIX_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-win32-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-win32-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,168 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if _WIN32 + +#include "async-win32.h" +#include "thread.h" +#include "test.h" + +namespace kj { +namespace { + +KJ_TEST("Win32IocpEventPort I/O operations") { + Win32IocpEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + auto pipeName = kj::str("\\\\.\\Pipe\\kj-async-win32-test.", GetCurrentProcessId()); + + HANDLE readEnd_, writeEnd_; + KJ_WIN32(readEnd_ = CreateNamedPipeA(pipeName.cStr(), + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT, + 1, 0, 0, 0, NULL)); + AutoCloseHandle readEnd(readEnd_); + + KJ_WIN32(writeEnd_ = CreateFileA(pipeName.cStr(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)); + AutoCloseHandle writeEnd(writeEnd_); + + auto observer = port.observeIo(readEnd); + auto op = observer->newOperation(0); + + byte buffer[256]; + + KJ_ASSERT(!ReadFile(readEnd, buffer, sizeof(buffer), NULL, op->getOverlapped())); + DWORD error = GetLastError(); + if (error != ERROR_IO_PENDING) { + KJ_FAIL_WIN32("ReadFile()", error); + } + + bool done = false; + auto promise = op->onComplete().then([&](Win32EventPort::IoResult result) { + done = true; + return result; + }).eagerlyEvaluate(nullptr); + + KJ_EXPECT(!done); + + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + + KJ_EXPECT(!done); + + DWORD bytesWritten; + KJ_WIN32(WriteFile(writeEnd, "foo", 3, &bytesWritten, NULL)); + KJ_EXPECT(bytesWritten == 3); + + auto result = promise.wait(waitScope); + KJ_EXPECT(result.errorCode == ERROR_SUCCESS); + KJ_EXPECT(result.bytesTransferred == 3); + + KJ_EXPECT(kj::str(kj::arrayPtr(buffer, 3).asChars()) == "foo"); +} + +KJ_TEST("Win32IocpEventPort::wake()") { + Win32IocpEventPort port; + + Thread thread([&]() { + Sleep(10); + port.wake(); + }); + + KJ_EXPECT(port.wait()); +} + +KJ_TEST("Win32IocpEventPort::wake() on poll()") { + Win32IocpEventPort port; + volatile bool woken = false; + + Thread thread([&]() { + Sleep(10); + port.wake(); + woken = true; + }); + + KJ_EXPECT(!port.poll()); + while (!woken) Sleep(10); + KJ_EXPECT(port.poll()); +} + +KJ_TEST("Win32IocpEventPort timer") { + Win32IocpEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + auto start = port.getTimer().now(); + + bool done = false; + auto promise = port.getTimer().afterDelay(10 * MILLISECONDS).then([&]() { + done = true; + }).eagerlyEvaluate(nullptr); + + KJ_EXPECT(!done); + + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + evalLater([]() {}).wait(waitScope); + + KJ_EXPECT(!done); + + promise.wait(waitScope); + KJ_EXPECT(done); + KJ_EXPECT(port.getTimer().now() - start >= 10 * MILLISECONDS); +} + +VOID CALLBACK testApcProc(ULONG_PTR dwParam) { + reinterpret_cast*>(dwParam)->fulfill(); +} + +KJ_TEST("Win32IocpEventPort APC") { + if (GetProcAddress(GetModuleHandle("ntdll.dll"), "wine_get_version") != nullptr) { + // TODO(cleanup): Periodically check if Wine supports this yet. + KJ_LOG(WARNING, "detected that we're running under wine and this test won't work; skipping"); + return; + } + + Win32IocpEventPort port; + EventLoop loop(port); + WaitScope waitScope(loop); + + port.allowApc(); + + auto paf = kj::newPromiseAndFulfiller(); + + KJ_WIN32(QueueUserAPC(&testApcProc, GetCurrentThread(), + reinterpret_cast(paf.fulfiller.get()))); + + paf.promise.wait(waitScope); +} + +} // namespace +} // namespace kj + +#endif // _WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-win32.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-win32.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,286 @@ +// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if _WIN32 + +// Request Vista-level APIs. +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 + +#include "async-win32.h" +#include "debug.h" +#include +#include +#include "refcount.h" +#include // NTSTATUS +#include // STATUS_SUCCESS + +#undef ERROR // dammit windows.h + +namespace kj { + +Win32IocpEventPort::Win32IocpEventPort() + : iocp(newIocpHandle()), thread(openCurrentThread()), timerImpl(readClock()) {} + +Win32IocpEventPort::~Win32IocpEventPort() noexcept(false) {} + +class Win32IocpEventPort::IoPromiseAdapter final: public OVERLAPPED { +public: + IoPromiseAdapter(PromiseFulfiller& fulfiller, Win32IocpEventPort& port, + uint64_t offset, IoPromiseAdapter** selfPtr) + : fulfiller(fulfiller), port(port) { + *selfPtr = this; + + memset(implicitCast(this), 0, sizeof(OVERLAPPED)); + this->Offset = offset & 0x00000000FFFFFFFFull; + this->OffsetHigh = offset >> 32; + } + + ~IoPromiseAdapter() { + if (handle != INVALID_HANDLE_VALUE) { + // Need to cancel the I/O. + // + // Note: Even if HasOverlappedIoCompleted(this) is true, CancelIoEx() still seems needed to + // force the completion event. + if (!CancelIoEx(handle, this)) { + DWORD error = GetLastError(); + + // ERROR_NOT_FOUND probably means the operation already completed and is enqueued on the + // IOCP. + // + // ERROR_INVALID_HANDLE probably means that, amid a mass of destructors, the HANDLE was + // closed before all of the I/O promises were destroyed. We tolerate this so long as the + // I/O promises are also destroyed before returning to the event loop, hence the I/O + // tasks won't actually continue on a dead handle. + // + // TODO(cleanup): ERROR_INVALID_HANDLE really shouldn't be allowed. Unfortunately, the + // refcounted nature of capabilities and the RPC system seems to mean that objects + // are unwound in the wrong order in several of Cap'n Proto's tests. So we live with this + // for now. Note that even if a new handle is opened with the same numeric value, it + // should be hardless to call CancelIoEx() on it because it couldn't possibly be using + // the same OVERLAPPED structure. + if (error != ERROR_NOT_FOUND && error != ERROR_INVALID_HANDLE) { + KJ_FAIL_WIN32("CancelIoEx()", error, handle); + } + } + + // We have to wait for the IOCP to poop out the event, so that we can safely destroy the + // OVERLAPPED. + while (handle != INVALID_HANDLE_VALUE) { + port.waitIocp(INFINITE); + } + } + } + + void start(HANDLE handle) { + KJ_ASSERT(this->handle == INVALID_HANDLE_VALUE); + this->handle = handle; + } + + void done(IoResult result) { + KJ_ASSERT(handle != INVALID_HANDLE_VALUE); + handle = INVALID_HANDLE_VALUE; + fulfiller.fulfill(kj::mv(result)); + } + +private: + PromiseFulfiller& fulfiller; + Win32IocpEventPort& port; + + HANDLE handle = INVALID_HANDLE_VALUE; + // If an I/O operation is currently enqueued, the handle on which it is enqueued. +}; + +class Win32IocpEventPort::IoOperationImpl final: public Win32EventPort::IoOperation { +public: + explicit IoOperationImpl(Win32IocpEventPort& port, HANDLE handle, uint64_t offset) + : handle(handle), + promise(newAdaptedPromise(port, offset, &promiseAdapter)) {} + + LPOVERLAPPED getOverlapped() override { + KJ_REQUIRE(promiseAdapter != nullptr, "already called onComplete()"); + return promiseAdapter; + } + + Promise onComplete() override { + KJ_REQUIRE(promiseAdapter != nullptr, "can only call onComplete() once"); + promiseAdapter->start(handle); + promiseAdapter = nullptr; + return kj::mv(promise); + } + +private: + HANDLE handle; + IoPromiseAdapter* promiseAdapter; + Promise promise; +}; + +class Win32IocpEventPort::IoObserverImpl final: public Win32EventPort::IoObserver { +public: + IoObserverImpl(Win32IocpEventPort& port, HANDLE handle) + : port(port), handle(handle) { + KJ_WIN32(CreateIoCompletionPort(handle, port.iocp, 0, 1), handle, port.iocp.get()); + } + + Own newOperation(uint64_t offset) { + return heap(port, handle, offset); + } + +private: + Win32IocpEventPort& port; + HANDLE handle; +}; + +Own Win32IocpEventPort::observeIo(HANDLE handle) { + return heap(*this, handle); +} + +Own Win32IocpEventPort::observeSignalState(HANDLE handle) { + return waitThreads.observeSignalState(handle); +} + +TimePoint Win32IocpEventPort::readClock() { + return origin() + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count() * NANOSECONDS; +} + +bool Win32IocpEventPort::wait() { + waitIocp(timerImpl.timeoutToNextEvent(readClock(), MILLISECONDS, INFINITE - 1) + .map([](uint64_t t) -> DWORD { return t; }) + .orDefault(INFINITE)); + + timerImpl.advanceTo(readClock()); + + return receivedWake(); +} + +bool Win32IocpEventPort::poll() { + waitIocp(0); + + return receivedWake(); +} + +void Win32IocpEventPort::wake() const { + if (!sentWake.load(std::memory_order_acquire)) { + sentWake.store(true, std::memory_order_release); + KJ_WIN32(PostQueuedCompletionStatus(iocp, 0, 0, nullptr)); + } +} + +void Win32IocpEventPort::waitIocp(DWORD timeoutMs) { + if (isAllowApc) { + ULONG countReceived = 0; + OVERLAPPED_ENTRY entry; + memset(&entry, 0, sizeof(entry)); + + if (GetQueuedCompletionStatusEx(iocp, &entry, 1, &countReceived, timeoutMs, TRUE)) { + KJ_ASSERT(countReceived == 1); + + if (entry.lpOverlapped == nullptr) { + // wake() called in another thread, or APC queued. + } else { + DWORD error = ERROR_SUCCESS; + if (entry.lpOverlapped->Internal != STATUS_SUCCESS) { + error = LsaNtStatusToWinError(entry.lpOverlapped->Internal); + } + static_cast(entry.lpOverlapped) + ->done(IoResult { error, entry.dwNumberOfBytesTransferred }); + } + } else { + // Call failed. + DWORD error = GetLastError(); + if (error == WAIT_TIMEOUT || error == WAIT_IO_COMPLETION) { + // WAIT_TIMEOUT = timed out (dunno why this isn't ERROR_TIMEOUT??) + // WAIT_IO_COMPLETION = APC queued + // Either way, nothing to do. + return; + } else { + KJ_FAIL_WIN32("GetQueuedCompletionStatusEx()", error, error, entry.lpOverlapped); + } + } + } else { + DWORD bytesTransferred; + ULONG_PTR completionKey; + LPOVERLAPPED overlapped = nullptr; + + BOOL success = GetQueuedCompletionStatus( + iocp, &bytesTransferred, &completionKey, &overlapped, timeoutMs); + + if (overlapped == nullptr) { + if (success) { + // wake() called in another thread. + } else { + DWORD error = GetLastError(); + if (error == WAIT_TIMEOUT) { + // Great, nothing to do. (Why this is WAIT_TIMEOUT and not ERROR_TIMEOUT I'm not sure.) + } else { + KJ_FAIL_WIN32("GetQueuedCompletionStatus()", error, error, overlapped); + } + } + } else { + DWORD error = success ? ERROR_SUCCESS : GetLastError(); + static_cast(overlapped)->done(IoResult { error, bytesTransferred }); + } + } +} + +bool Win32IocpEventPort::receivedWake() { + if (sentWake.load(std::memory_order_acquire)) { + sentWake.store(false, std::memory_order_release); + return true; + } else { + return false; + } +} + +AutoCloseHandle Win32IocpEventPort::newIocpHandle() { + HANDLE h; + KJ_WIN32(h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1)); + return AutoCloseHandle(h); +} + +AutoCloseHandle Win32IocpEventPort::openCurrentThread() { + HANDLE process = GetCurrentProcess(); + HANDLE result; + KJ_WIN32(DuplicateHandle(process, GetCurrentThread(), process, &result, + 0, FALSE, DUPLICATE_SAME_ACCESS)); + return AutoCloseHandle(result); +} + +// ======================================================================================= + +Win32WaitObjectThreadPool::Win32WaitObjectThreadPool(uint mainThreadCount) {} + +Own Win32WaitObjectThreadPool::observeSignalState(HANDLE handle) { + KJ_UNIMPLEMENTED("wait for win32 handles"); +} + +uint Win32WaitObjectThreadPool::prepareMainThreadWait(HANDLE* handles[]) { + KJ_UNIMPLEMENTED("wait for win32 handles"); +} + +bool Win32WaitObjectThreadPool::finishedMainThreadWait(DWORD returnCode) { + KJ_UNIMPLEMENTED("wait for win32 handles"); +} + +} // namespace kj + +#endif // _WIN32 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async-win32.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async-win32.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,234 @@ +// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_WIN32_H_ +#define KJ_ASYNC_WIN32_H_ + +#if !_WIN32 +#error "This file is Windows-specific. On Unix, include async-unix.h instead." +#endif + +#include "async.h" +#include "time.h" +#include "io.h" +#include +#include + +// Include windows.h as lean as possible. (If you need more of the Windows API for your app, +// #include windows.h yourself before including this header.) +#define WIN32_LEAN_AND_MEAN 1 +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#include +#include "windows-sanity.h" + +namespace kj { + +class Win32EventPort: public EventPort { + // Abstract base interface for EventPorts that can listen on Win32 event types. Due to the + // absurd complexity of the Win32 API, it's not possible to standardize on a single + // implementation of EventPort. In particular, there is no way for a single thread to use I/O + // completion ports (the most efficient way of handling I/O) while at the same time waiting for + // signalable handles or UI messages. + // + // Note that UI messages are not supported at all by this interface because the message queue + // is implemented by user32.dll and we want libkj to depend only on kernel32.dll. A separate + // compat library could provide a Win32EventPort implementation that works with the UI message + // queue. + +public: + // --------------------------------------------------------------------------- + // overlapped I/O + + struct IoResult { + DWORD errorCode; + DWORD bytesTransferred; + }; + + class IoOperation { + public: + virtual LPOVERLAPPED getOverlapped() = 0; + // Gets the OVERLAPPED structure to pass to the Win32 I/O call. Do NOT modify it; just pass it + // on. + + virtual Promise onComplete() = 0; + // After making the Win32 call, if the return value indicates that the operation was + // successfully queued (i.e. the completion event will definitely occur), call this to wait + // for completion. + // + // You MUST call this if the operation was successfully queued, and you MUST NOT call this + // otherwise. If the Win32 call failed (without queuing any operation or event) then you should + // simply drop the IoOperation object. + // + // Dropping the returned Promise cancels the operation via Win32's CancelIoEx(). The destructor + // will wait for the cancellation to complete, such that after dropping the proimse it is safe + // to free the buffer that the operation was reading from / writing to. + // + // You may safely drop the `IoOperation` while still waiting for this promise. You may not, + // however, drop the `IoObserver`. + }; + + class IoObserver { + public: + virtual Own newOperation(uint64_t offset) = 0; + // Begin an I/O operation. For file operations, `offset` is the offset within the file at + // which the operation will start. For stream operations, `offset` is ignored. + }; + + virtual Own observeIo(HANDLE handle) = 0; + // Given a handle which supports overlapped I/O, arrange to receive I/O completion events via + // this EventPort. + // + // Different Win32EventPort implementations may handle this in different ways, such as by using + // completion routines (APCs) or by using I/O completion ports. The caller should not assume + // any particular technique. + // + // WARNING: It is only safe to call observeIo() on a particular handle once during its lifetime. + // You cannot observe the same handle from multiple Win32EventPorts, even if not at the same + // time. This is because the Win32 API provides no way to disassociate a handle from an I/O + // completion port once it is associated. + + // --------------------------------------------------------------------------- + // signalable handles + // + // Warning: Due to limitations in the Win32 API, implementations of EventPort may be forced to + // spawn additional threads to wait for signaled objects. This is necessary if the EventPort + // implementation is based on I/O completion ports, or if you need to wait on more than 64 + // handles at once. + + class SignalObserver { + public: + virtual Promise onSignaled() = 0; + // Returns a promise that completes the next time the handle enters the signaled state. + // + // Depending on the type of handle, the handle may automatically be reset to a non-signaled + // state before the promise resolves. The underlying implementaiton uses WaitForSingleObject() + // or an equivalent wait call, so check the documentation for that to understand the semantics. + // + // If the handle is a mutex and it is abandoned without being unlocked, the promise breaks with + // an exception. + + virtual Promise onSignaledOrAbandoned() = 0; + // Like onSingaled(), but instead of throwing when a mutex is abandoned, resolves to `true`. + // Resolves to `false` for non-abandoned signals. + }; + + virtual Own observeSignalState(HANDLE handle) = 0; + // Given a handle that supports waiting for it to become "signaled" via WaitForSingleObject(), + // return an object that can wait for this state using the EventPort. + + // --------------------------------------------------------------------------- + // APCs + + virtual void allowApc() = 0; + // If this is ever called, the Win32EventPort will switch modes so that APCs can be scheduled + // on the thread, e.g. through the Win32 QueueUserAPC() call. In the future, this may be enabled + // by default. However, as of this writing, Wine does not support the necessary + // GetQueuedCompletionStatusEx() call, thus allowApc() breaks Wine support. (Tested on Wine + // 1.8.7.) + // + // If the event port implementation can't support APCs for some reason, this throws. + + // --------------------------------------------------------------------------- + // time + + virtual Timer& getTimer() = 0; +}; + +class Win32WaitObjectThreadPool { + // Helper class that implements Win32EventPort::observeSignalState() by spawning additional + // threads as needed to perform the actual waiting. + // + // This class is intended to be used to assist in building Win32EventPort implementations. + +public: + Win32WaitObjectThreadPool(uint mainThreadCount = 0); + // `mainThreadCount` indicates the number of objects the main thread is able to listen on + // directly. Typically this would be zero (e.g. if the main thread watches an I/O completion + // port) or MAXIMUM_WAIT_OBJECTS (e.g. if the main thread is a UI thread but can use + // MsgWaitForMultipleObjectsEx() to wait on some handles at the same time as messages). + + Own observeSignalState(HANDLE handle); + // Implemetns Win32EventPort::observeSignalState(). + + uint prepareMainThreadWait(HANDLE* handles[]); + // Call immediately before invoking WaitForMultipleObjects() or similar in the main thread. + // Fills in `handles` with the handle pointers to wait on, and returns the number of handles + // in this array. (The array should be allocated to be at least the size passed to the + // constructor). + // + // There's no need to call this if `mainThreadCount` as passed to the constructor was zero. + + bool finishedMainThreadWait(DWORD returnCode); + // Call immediately after invoking WaitForMultipleObjects() or similar in the main thread, + // passing the value returend by that call. Returns true if the event indicated by `returnCode` + // has been handled (i.e. it was WAIT_OBJECT_n or WAIT_ABANDONED_n where n is in-range for the + // last call to prepareMainThreadWait()). +}; + +class Win32IocpEventPort final: public Win32EventPort { + // An EventPort implementation which uses Windows I/O completion ports to listen for events. + // + // With this implementation, observeSignalState() requires spawning a separate thread. + +public: + Win32IocpEventPort(); + ~Win32IocpEventPort() noexcept(false); + + // implements EventPort ------------------------------------------------------ + bool wait() override; + bool poll() override; + void wake() const override; + + // implements Win32IocpEventPort --------------------------------------------- + Own observeIo(HANDLE handle) override; + Own observeSignalState(HANDLE handle) override; + Timer& getTimer() override { return timerImpl; } + void allowApc() override { isAllowApc = true; } + +private: + class IoPromiseAdapter; + class IoOperationImpl; + class IoObserverImpl; + + AutoCloseHandle iocp; + AutoCloseHandle thread; + Win32WaitObjectThreadPool waitThreads; + TimerImpl timerImpl; + mutable std::atomic sentWake {false}; + bool isAllowApc = false; + + static TimePoint readClock(); + + void waitIocp(DWORD timeoutMs); + // Wait on the I/O completion port for up to timeoutMs and pump events. Does not advance the + // timer; caller must do that. + + bool receivedWake(); + + static AutoCloseHandle newIocpHandle(); + static AutoCloseHandle openCurrentThread(); +}; + +} // namespace kj + +#endif // KJ_ASYNC_WIN32_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,958 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "async.h" +#include "debug.h" +#include "vector.h" +#include "threadlocal.h" +#include +#include + +#if KJ_USE_FUTEX +#include +#include +#include +#endif + +#if !KJ_NO_RTTI +#include +#if __GNUC__ +#include +#include +#endif +#endif + +namespace kj { + +namespace { + +KJ_THREADLOCAL_PTR(EventLoop) threadLocalEventLoop = nullptr; + +#define _kJ_ALREADY_READY reinterpret_cast< ::kj::_::Event*>(1) + +EventLoop& currentEventLoop() { + EventLoop* loop = threadLocalEventLoop; + KJ_REQUIRE(loop != nullptr, "No event loop is running on this thread."); + return *loop; +} + +class BoolEvent: public _::Event { +public: + bool fired = false; + + Maybe> fire() override { + fired = true; + return nullptr; + } +}; + +class YieldPromiseNode final: public _::PromiseNode { +public: + void onReady(_::Event& event) noexcept override { + event.armBreadthFirst(); + } + void get(_::ExceptionOrValue& output) noexcept override { + output.as<_::Void>() = _::Void(); + } +}; + +class NeverDonePromiseNode final: public _::PromiseNode { +public: + void onReady(_::Event& event) noexcept override { + // ignore + } + void get(_::ExceptionOrValue& output) noexcept override { + KJ_FAIL_REQUIRE("Not ready."); + } +}; + +} // namespace + +namespace _ { // private + +class TaskSetImpl { +public: + inline TaskSetImpl(TaskSet::ErrorHandler& errorHandler) + : errorHandler(errorHandler) {} + + ~TaskSetImpl() noexcept(false) { + // std::map doesn't like it when elements' destructors throw, so carefully disassemble it. + if (!tasks.empty()) { + Vector> deleteMe(tasks.size()); + for (auto& entry: tasks) { + deleteMe.add(kj::mv(entry.second)); + } + } + } + + class Task final: public Event { + public: + Task(TaskSetImpl& taskSet, Own<_::PromiseNode>&& nodeParam) + : taskSet(taskSet), node(kj::mv(nodeParam)) { + node->setSelfPointer(&node); + node->onReady(*this); + } + + protected: + Maybe> fire() override { + // Get the result. + _::ExceptionOr<_::Void> result; + node->get(result); + + // Delete the node, catching any exceptions. + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() { + node = nullptr; + })) { + result.addException(kj::mv(*exception)); + } + + // Call the error handler if there was an exception. + KJ_IF_MAYBE(e, result.exception) { + taskSet.errorHandler.taskFailed(kj::mv(*e)); + } + + // Remove from the task map. + auto iter = taskSet.tasks.find(this); + KJ_ASSERT(iter != taskSet.tasks.end()); + Own self = kj::mv(iter->second); + taskSet.tasks.erase(iter); + return mv(self); + } + + _::PromiseNode* getInnerForTrace() override { + return node; + } + + private: + TaskSetImpl& taskSet; + kj::Own<_::PromiseNode> node; + }; + + void add(Promise&& promise) { + auto task = heap(*this, kj::mv(promise.node)); + Task* ptr = task; + tasks.insert(std::make_pair(ptr, kj::mv(task))); + } + + kj::String trace() { + kj::Vector traces; + for (auto& entry: tasks) { + traces.add(entry.second->trace()); + } + return kj::strArray(traces, "\n============================================\n"); + } + +private: + TaskSet::ErrorHandler& errorHandler; + + // TODO(perf): Use a linked list instead. + std::map> tasks; +}; + +class LoggingErrorHandler: public TaskSet::ErrorHandler { +public: + static LoggingErrorHandler instance; + + void taskFailed(kj::Exception&& exception) override { + KJ_LOG(ERROR, "Uncaught exception in daemonized task.", exception); + } +}; + +LoggingErrorHandler LoggingErrorHandler::instance = LoggingErrorHandler(); + +class NullEventPort: public EventPort { +public: + bool wait() override { + KJ_FAIL_REQUIRE("Nothing to wait for; this thread would hang forever."); + } + + bool poll() override { return false; } + + void wake() const override { + // TODO(someday): Implement using condvar. + kj::throwRecoverableException(KJ_EXCEPTION(UNIMPLEMENTED, + "Cross-thread events are not yet implemented for EventLoops with no EventPort.")); + } + + static NullEventPort instance; +}; + +NullEventPort NullEventPort::instance = NullEventPort(); + +} // namespace _ (private) + +// ======================================================================================= + +void EventPort::setRunnable(bool runnable) {} + +void EventPort::wake() const { + kj::throwRecoverableException(KJ_EXCEPTION(UNIMPLEMENTED, + "cross-thread wake() not implemented by this EventPort implementation")); +} + +EventLoop::EventLoop() + : port(_::NullEventPort::instance), + daemons(kj::heap<_::TaskSetImpl>(_::LoggingErrorHandler::instance)) {} + +EventLoop::EventLoop(EventPort& port) + : port(port), + daemons(kj::heap<_::TaskSetImpl>(_::LoggingErrorHandler::instance)) {} + +EventLoop::~EventLoop() noexcept(false) { + // Destroy all "daemon" tasks, noting that their destructors might try to access the EventLoop + // some more. + daemons = nullptr; + + // The application _should_ destroy everything using the EventLoop before destroying the + // EventLoop itself, so if there are events on the loop, this indicates a memory leak. + KJ_REQUIRE(head == nullptr, "EventLoop destroyed with events still in the queue. Memory leak?", + head->trace()) { + // Unlink all the events and hope that no one ever fires them... + _::Event* event = head; + while (event != nullptr) { + _::Event* next = event->next; + event->next = nullptr; + event->prev = nullptr; + event = next; + } + break; + } + + KJ_REQUIRE(threadLocalEventLoop != this, + "EventLoop destroyed while still current for the thread.") { + threadLocalEventLoop = nullptr; + break; + } +} + +void EventLoop::run(uint maxTurnCount) { + running = true; + KJ_DEFER(running = false); + + for (uint i = 0; i < maxTurnCount; i++) { + if (!turn()) { + break; + } + } + + setRunnable(isRunnable()); +} + +bool EventLoop::turn() { + _::Event* event = head; + + if (event == nullptr) { + // No events in the queue. + return false; + } else { + head = event->next; + if (head != nullptr) { + head->prev = &head; + } + + depthFirstInsertPoint = &head; + if (tail == &event->next) { + tail = &head; + } + + event->next = nullptr; + event->prev = nullptr; + + Maybe> eventToDestroy; + { + event->firing = true; + KJ_DEFER(event->firing = false); + eventToDestroy = event->fire(); + } + + depthFirstInsertPoint = &head; + return true; + } +} + +bool EventLoop::isRunnable() { + return head != nullptr; +} + +void EventLoop::setRunnable(bool runnable) { + if (runnable != lastRunnableState) { + port.setRunnable(runnable); + lastRunnableState = runnable; + } +} + +void EventLoop::enterScope() { + KJ_REQUIRE(threadLocalEventLoop == nullptr, "This thread already has an EventLoop."); + threadLocalEventLoop = this; +} + +void EventLoop::leaveScope() { + KJ_REQUIRE(threadLocalEventLoop == this, + "WaitScope destroyed in a different thread than it was created in.") { + break; + } + threadLocalEventLoop = nullptr; +} + +namespace _ { // private + +void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope) { + EventLoop& loop = waitScope.loop; + KJ_REQUIRE(&loop == threadLocalEventLoop, "WaitScope not valid for this thread."); + KJ_REQUIRE(!loop.running, "wait() is not allowed from within event callbacks."); + + BoolEvent doneEvent; + node->setSelfPointer(&node); + node->onReady(doneEvent); + + loop.running = true; + KJ_DEFER(loop.running = false); + + while (!doneEvent.fired) { + if (!loop.turn()) { + // No events in the queue. Wait for callback. + loop.port.wait(); + } + } + + loop.setRunnable(loop.isRunnable()); + + node->get(result); + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + node = nullptr; + })) { + result.addException(kj::mv(*exception)); + } +} + +Promise yield() { + return Promise(false, kj::heap()); +} + +Own neverDone() { + return kj::heap(); +} + +void NeverDone::wait(WaitScope& waitScope) const { + ExceptionOr dummy; + waitImpl(neverDone(), dummy, waitScope); + KJ_UNREACHABLE; +} + +void detach(kj::Promise&& promise) { + EventLoop& loop = currentEventLoop(); + KJ_REQUIRE(loop.daemons.get() != nullptr, "EventLoop is shutting down.") { return; } + loop.daemons->add(kj::mv(promise)); +} + +Event::Event() + : loop(currentEventLoop()), next(nullptr), prev(nullptr) {} + +Event::~Event() noexcept(false) { + if (prev != nullptr) { + if (loop.tail == &next) { + loop.tail = prev; + } + if (loop.depthFirstInsertPoint == &next) { + loop.depthFirstInsertPoint = prev; + } + + *prev = next; + if (next != nullptr) { + next->prev = prev; + } + } + + KJ_REQUIRE(!firing, "Promise callback destroyed itself."); + KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr, + "Promise destroyed from a different thread than it was created in."); +} + +void Event::armDepthFirst() { + KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr, + "Event armed from different thread than it was created in. You must use " + "the thread-safe work queue to queue events cross-thread."); + + if (prev == nullptr) { + next = *loop.depthFirstInsertPoint; + prev = loop.depthFirstInsertPoint; + *prev = this; + if (next != nullptr) { + next->prev = &next; + } + + loop.depthFirstInsertPoint = &next; + + if (loop.tail == prev) { + loop.tail = &next; + } + + loop.setRunnable(true); + } +} + +void Event::armBreadthFirst() { + KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr, + "Event armed from different thread than it was created in. You must use " + "the thread-safe work queue to queue events cross-thread."); + + if (prev == nullptr) { + next = *loop.tail; + prev = loop.tail; + *prev = this; + if (next != nullptr) { + next->prev = &next; + } + + loop.tail = &next; + + loop.setRunnable(true); + } +} + +_::PromiseNode* Event::getInnerForTrace() { + return nullptr; +} + +#if !KJ_NO_RTTI +#if __GNUC__ +static kj::String demangleTypeName(const char* name) { + int status; + char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status); + kj::String result = kj::heapString(buf == nullptr ? name : buf); + free(buf); + return kj::mv(result); +} +#else +static kj::String demangleTypeName(const char* name) { + return kj::heapString(name); +} +#endif +#endif + +static kj::String traceImpl(Event* event, _::PromiseNode* node) { +#if KJ_NO_RTTI + return heapString("Trace not available because RTTI is disabled."); +#else + kj::Vector trace; + + if (event != nullptr) { + trace.add(demangleTypeName(typeid(*event).name())); + } + + while (node != nullptr) { + trace.add(demangleTypeName(typeid(*node).name())); + node = node->getInnerForTrace(); + } + + return strArray(trace, "\n"); +#endif +} + +kj::String Event::trace() { + return traceImpl(this, getInnerForTrace()); +} + +} // namespace _ (private) + +// ======================================================================================= + +TaskSet::TaskSet(ErrorHandler& errorHandler) + : impl(heap<_::TaskSetImpl>(errorHandler)) {} + +TaskSet::~TaskSet() noexcept(false) {} + +void TaskSet::add(Promise&& promise) { + impl->add(kj::mv(promise)); +} + +kj::String TaskSet::trace() { + return impl->trace(); +} + +namespace _ { // private + +kj::String PromiseBase::trace() { + return traceImpl(nullptr, node); +} + +void PromiseNode::setSelfPointer(Own* selfPtr) noexcept {} + +PromiseNode* PromiseNode::getInnerForTrace() { return nullptr; } + +void PromiseNode::OnReadyEvent::init(Event& newEvent) { + if (event == _kJ_ALREADY_READY) { + // A new continuation was added to a promise that was already ready. In this case, we schedule + // breadth-first, to make it difficult for applications to accidentally starve the event loop + // by repeatedly waiting on immediate promises. + newEvent.armBreadthFirst(); + } else { + event = &newEvent; + } +} + +void PromiseNode::OnReadyEvent::arm() { + if (event == nullptr) { + event = _kJ_ALREADY_READY; + } else { + // A promise resolved and an event is already waiting on it. In this case, arm in depth-first + // order so that the event runs immediately after the current one. This way, chained promises + // execute together for better cache locality and lower latency. + event->armDepthFirst(); + } +} + +// ------------------------------------------------------------------- + +ImmediatePromiseNodeBase::ImmediatePromiseNodeBase() {} +ImmediatePromiseNodeBase::~ImmediatePromiseNodeBase() noexcept(false) {} + +void ImmediatePromiseNodeBase::onReady(Event& event) noexcept { + event.armBreadthFirst(); +} + +ImmediateBrokenPromiseNode::ImmediateBrokenPromiseNode(Exception&& exception) + : exception(kj::mv(exception)) {} + +void ImmediateBrokenPromiseNode::get(ExceptionOrValue& output) noexcept { + output.exception = kj::mv(exception); +} + +// ------------------------------------------------------------------- + +AttachmentPromiseNodeBase::AttachmentPromiseNodeBase(Own&& dependencyParam) + : dependency(kj::mv(dependencyParam)) { + dependency->setSelfPointer(&dependency); +} + +void AttachmentPromiseNodeBase::onReady(Event& event) noexcept { + dependency->onReady(event); +} + +void AttachmentPromiseNodeBase::get(ExceptionOrValue& output) noexcept { + dependency->get(output); +} + +PromiseNode* AttachmentPromiseNodeBase::getInnerForTrace() { + return dependency; +} + +void AttachmentPromiseNodeBase::dropDependency() { + dependency = nullptr; +} + +// ------------------------------------------------------------------- + +TransformPromiseNodeBase::TransformPromiseNodeBase( + Own&& dependencyParam, void* continuationTracePtr) + : dependency(kj::mv(dependencyParam)), continuationTracePtr(continuationTracePtr) { + dependency->setSelfPointer(&dependency); +} + +void TransformPromiseNodeBase::onReady(Event& event) noexcept { + dependency->onReady(event); +} + +void TransformPromiseNodeBase::get(ExceptionOrValue& output) noexcept { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + getImpl(output); + dropDependency(); + })) { + output.addException(kj::mv(*exception)); + } +} + +PromiseNode* TransformPromiseNodeBase::getInnerForTrace() { + return dependency; +} + +void TransformPromiseNodeBase::dropDependency() { + dependency = nullptr; +} + +void TransformPromiseNodeBase::getDepResult(ExceptionOrValue& output) { + dependency->get(output); + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() { + dependency = nullptr; + })) { + output.addException(kj::mv(*exception)); + } + + KJ_IF_MAYBE(e, output.exception) { + e->addTrace(continuationTracePtr); + } +} + +// ------------------------------------------------------------------- + +ForkBranchBase::ForkBranchBase(Own&& hubParam): hub(kj::mv(hubParam)) { + if (hub->tailBranch == nullptr) { + onReadyEvent.arm(); + } else { + // Insert into hub's linked list of branches. + prevPtr = hub->tailBranch; + *prevPtr = this; + next = nullptr; + hub->tailBranch = &next; + } +} + +ForkBranchBase::~ForkBranchBase() noexcept(false) { + if (prevPtr != nullptr) { + // Remove from hub's linked list of branches. + *prevPtr = next; + (next == nullptr ? hub->tailBranch : next->prevPtr) = prevPtr; + } +} + +void ForkBranchBase::hubReady() noexcept { + onReadyEvent.arm(); +} + +void ForkBranchBase::releaseHub(ExceptionOrValue& output) { + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() { + hub = nullptr; + })) { + output.addException(kj::mv(*exception)); + } +} + +void ForkBranchBase::onReady(Event& event) noexcept { + onReadyEvent.init(event); +} + +PromiseNode* ForkBranchBase::getInnerForTrace() { + return hub->getInnerForTrace(); +} + +// ------------------------------------------------------------------- + +ForkHubBase::ForkHubBase(Own&& innerParam, ExceptionOrValue& resultRef) + : inner(kj::mv(innerParam)), resultRef(resultRef) { + inner->setSelfPointer(&inner); + inner->onReady(*this); +} + +Maybe> ForkHubBase::fire() { + // Dependency is ready. Fetch its result and then delete the node. + inner->get(resultRef); + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() { + inner = nullptr; + })) { + resultRef.addException(kj::mv(*exception)); + } + + for (auto branch = headBranch; branch != nullptr; branch = branch->next) { + branch->hubReady(); + *branch->prevPtr = nullptr; + branch->prevPtr = nullptr; + } + *tailBranch = nullptr; + + // Indicate that the list is no longer active. + tailBranch = nullptr; + + return nullptr; +} + +_::PromiseNode* ForkHubBase::getInnerForTrace() { + return inner; +} + +// ------------------------------------------------------------------- + +ChainPromiseNode::ChainPromiseNode(Own innerParam) + : state(STEP1), inner(kj::mv(innerParam)) { + inner->setSelfPointer(&inner); + inner->onReady(*this); +} + +ChainPromiseNode::~ChainPromiseNode() noexcept(false) {} + +void ChainPromiseNode::onReady(Event& event) noexcept { + switch (state) { + case STEP1: + KJ_REQUIRE(onReadyEvent == nullptr, "onReady() can only be called once."); + onReadyEvent = &event; + return; + case STEP2: + inner->onReady(event); + return; + } + KJ_UNREACHABLE; +} + +void ChainPromiseNode::setSelfPointer(Own* selfPtr) noexcept { + if (state == STEP2) { + *selfPtr = kj::mv(inner); // deletes this! + selfPtr->get()->setSelfPointer(selfPtr); + } else { + this->selfPtr = selfPtr; + } +} + +void ChainPromiseNode::get(ExceptionOrValue& output) noexcept { + KJ_REQUIRE(state == STEP2); + return inner->get(output); +} + +PromiseNode* ChainPromiseNode::getInnerForTrace() { + return inner; +} + +Maybe> ChainPromiseNode::fire() { + KJ_REQUIRE(state != STEP2); + + static_assert(sizeof(Promise) == sizeof(PromiseBase), + "This code assumes Promise does not add any new members to PromiseBase."); + + ExceptionOr intermediate; + inner->get(intermediate); + + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() { + inner = nullptr; + })) { + intermediate.addException(kj::mv(*exception)); + } + + KJ_IF_MAYBE(exception, intermediate.exception) { + // There is an exception. If there is also a value, delete it. + kj::runCatchingExceptions([&]() { intermediate.value = nullptr; }); + // Now set step2 to a rejected promise. + inner = heap(kj::mv(*exception)); + } else KJ_IF_MAYBE(value, intermediate.value) { + // There is a value and no exception. The value is itself a promise. Adopt it as our + // step2. + inner = kj::mv(value->node); + } else { + // We can only get here if inner->get() returned neither an exception nor a + // value, which never actually happens. + KJ_FAIL_ASSERT("Inner node returned empty value."); + } + state = STEP2; + + if (selfPtr != nullptr) { + // Hey, we can shorten the chain here. + auto chain = selfPtr->downcast(); + *selfPtr = kj::mv(inner); + selfPtr->get()->setSelfPointer(selfPtr); + if (onReadyEvent != nullptr) { + selfPtr->get()->onReady(*onReadyEvent); + } + + // Return our self-pointer so that the caller takes care of deleting it. + return Own(kj::mv(chain)); + } else { + inner->setSelfPointer(&inner); + if (onReadyEvent != nullptr) { + inner->onReady(*onReadyEvent); + } + + return nullptr; + } +} + +// ------------------------------------------------------------------- + +ExclusiveJoinPromiseNode::ExclusiveJoinPromiseNode(Own left, Own right) + : left(*this, kj::mv(left)), right(*this, kj::mv(right)) {} + +ExclusiveJoinPromiseNode::~ExclusiveJoinPromiseNode() noexcept(false) {} + +void ExclusiveJoinPromiseNode::onReady(Event& event) noexcept { + onReadyEvent.init(event); +} + +void ExclusiveJoinPromiseNode::get(ExceptionOrValue& output) noexcept { + KJ_REQUIRE(left.get(output) || right.get(output), "get() called before ready."); +} + +PromiseNode* ExclusiveJoinPromiseNode::getInnerForTrace() { + auto result = left.getInnerForTrace(); + if (result == nullptr) { + result = right.getInnerForTrace(); + } + return result; +} + +ExclusiveJoinPromiseNode::Branch::Branch( + ExclusiveJoinPromiseNode& joinNode, Own dependencyParam) + : joinNode(joinNode), dependency(kj::mv(dependencyParam)) { + dependency->setSelfPointer(&dependency); + dependency->onReady(*this); +} + +ExclusiveJoinPromiseNode::Branch::~Branch() noexcept(false) {} + +bool ExclusiveJoinPromiseNode::Branch::get(ExceptionOrValue& output) { + if (dependency) { + dependency->get(output); + return true; + } else { + return false; + } +} + +Maybe> ExclusiveJoinPromiseNode::Branch::fire() { + // Cancel the branch that didn't return first. Ignore exceptions caused by cancellation. + if (this == &joinNode.left) { + kj::runCatchingExceptions([&]() { joinNode.right.dependency = nullptr; }); + } else { + kj::runCatchingExceptions([&]() { joinNode.left.dependency = nullptr; }); + } + + joinNode.onReadyEvent.arm(); + return nullptr; +} + +PromiseNode* ExclusiveJoinPromiseNode::Branch::getInnerForTrace() { + return dependency; +} + +// ------------------------------------------------------------------- + +ArrayJoinPromiseNodeBase::ArrayJoinPromiseNodeBase( + Array> promises, ExceptionOrValue* resultParts, size_t partSize) + : countLeft(promises.size()) { + // Make the branches. + auto builder = heapArrayBuilder(promises.size()); + for (uint i: indices(promises)) { + ExceptionOrValue& output = *reinterpret_cast( + reinterpret_cast(resultParts) + i * partSize); + builder.add(*this, kj::mv(promises[i]), output); + } + branches = builder.finish(); + + if (branches.size() == 0) { + onReadyEvent.arm(); + } +} +ArrayJoinPromiseNodeBase::~ArrayJoinPromiseNodeBase() noexcept(false) {} + +void ArrayJoinPromiseNodeBase::onReady(Event& event) noexcept { + onReadyEvent.init(event); +} + +void ArrayJoinPromiseNodeBase::get(ExceptionOrValue& output) noexcept { + // If any of the elements threw exceptions, propagate them. + for (auto& branch: branches) { + KJ_IF_MAYBE(exception, branch.getPart()) { + output.addException(kj::mv(*exception)); + } + } + + if (output.exception == nullptr) { + // No errors. The template subclass will need to fill in the result. + getNoError(output); + } +} + +PromiseNode* ArrayJoinPromiseNodeBase::getInnerForTrace() { + return branches.size() == 0 ? nullptr : branches[0].getInnerForTrace(); +} + +ArrayJoinPromiseNodeBase::Branch::Branch( + ArrayJoinPromiseNodeBase& joinNode, Own dependencyParam, ExceptionOrValue& output) + : joinNode(joinNode), dependency(kj::mv(dependencyParam)), output(output) { + dependency->setSelfPointer(&dependency); + dependency->onReady(*this); +} + +ArrayJoinPromiseNodeBase::Branch::~Branch() noexcept(false) {} + +Maybe> ArrayJoinPromiseNodeBase::Branch::fire() { + if (--joinNode.countLeft == 0) { + joinNode.onReadyEvent.arm(); + } + return nullptr; +} + +_::PromiseNode* ArrayJoinPromiseNodeBase::Branch::getInnerForTrace() { + return dependency->getInnerForTrace(); +} + +Maybe ArrayJoinPromiseNodeBase::Branch::getPart() { + dependency->get(output); + return kj::mv(output.exception); +} + +ArrayJoinPromiseNode::ArrayJoinPromiseNode( + Array> promises, Array> resultParts) + : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr<_::Void>)), + resultParts(kj::mv(resultParts)) {} + +ArrayJoinPromiseNode::~ArrayJoinPromiseNode() {} + +void ArrayJoinPromiseNode::getNoError(ExceptionOrValue& output) noexcept { + output.as<_::Void>() = _::Void(); +} + +} // namespace _ (private) + +Promise joinPromises(Array>&& promises) { + return Promise(false, kj::heap<_::ArrayJoinPromiseNode>( + KJ_MAP(p, promises) { return kj::mv(p.node); }, + heapArray<_::ExceptionOr<_::Void>>(promises.size()))); +} + +namespace _ { // (private) + +// ------------------------------------------------------------------- + +EagerPromiseNodeBase::EagerPromiseNodeBase( + Own&& dependencyParam, ExceptionOrValue& resultRef) + : dependency(kj::mv(dependencyParam)), resultRef(resultRef) { + dependency->setSelfPointer(&dependency); + dependency->onReady(*this); +} + +void EagerPromiseNodeBase::onReady(Event& event) noexcept { + onReadyEvent.init(event); +} + +PromiseNode* EagerPromiseNodeBase::getInnerForTrace() { + return dependency; +} + +Maybe> EagerPromiseNodeBase::fire() { + dependency->get(resultRef); + KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() { + dependency = nullptr; + })) { + resultRef.addException(kj::mv(*exception)); + } + + onReadyEvent.arm(); + return nullptr; +} + +// ------------------------------------------------------------------- + +void AdapterPromiseNodeBase::onReady(Event& event) noexcept { + onReadyEvent.init(event); +} + +// ------------------------------------------------------------------- + +Promise IdentityFunc>::operator()() const { return READY_NOW; } + +} // namespace _ (private) +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/async.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/async.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,682 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_ASYNC_H_ +#define KJ_ASYNC_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "async-prelude.h" +#include "exception.h" +#include "refcount.h" + +namespace kj { + +class EventLoop; +class WaitScope; + +template +class Promise; +template +class ForkedPromise; +template +class PromiseFulfiller; +template +struct PromiseFulfillerPair; + +template +using PromiseForResult = Promise<_::JoinPromises<_::ReturnType>>; +// Evaluates to the type of Promise for the result of calling functor type Func with parameter type +// T. If T is void, then the promise is for the result of calling Func with no arguments. If +// Func itself returns a promise, the promises are joined, so you never get Promise>. + +// ======================================================================================= +// Promises + +template +class Promise: protected _::PromiseBase { + // The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed + // specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A. + // + // A Promise represents a promise to produce a value of type T some time in the future. Once + // that value has been produced, the promise is "fulfilled". Alternatively, a promise can be + // "broken", with an Exception describing what went wrong. You may implicitly convert a value of + // type T to an already-fulfilled Promise. You may implicitly convert the constant + // `kj::READY_NOW` to an already-fulfilled Promise. You may also implicitly convert a + // `kj::Exception` to an already-broken promise of any type. + // + // Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed + // or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations + // meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless + // otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they + // should be rvalue-qualified, but at the time this interface was created compilers didn't widely + // support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If + // you want to use one Promise in two different places, you must fork it with `fork()`. + // + // To use the result of a Promise, you must call `then()` and supply a callback function to + // call with the result. `then()` returns another promise, for the result of the callback. + // Any time that this would result in Promise>, the promises are collapsed into a + // simple Promise that first waits for the outer promise, then the inner. Example: + // + // // Open a remote file, read the content, and then count the + // // number of lines of text. + // // Note that none of the calls here block. `file`, `content` + // // and `lineCount` are all initialized immediately before any + // // asynchronous operations occur. The lambda callbacks are + // // called later. + // Promise> file = openFtp("ftp://host/foo/bar"); + // Promise content = file.then( + // [](Own file) -> Promise { + // return file.readAll(); + // }); + // Promise lineCount = content.then( + // [](String text) -> int { + // uint count = 0; + // for (char c: text) count += (c == '\n'); + // return count; + // }); + // + // For `then()` to work, the current thread must have an active `EventLoop`. Each callback + // is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current + // thread's event loop, you do not need to worry about two callbacks running at the same time. + // You will need to set up at least one `EventLoop` at the top level of your program before you + // can use promises. + // + // To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`. + // + // Systems using promises should consider supporting the concept of "pipelining". Pipelining + // means allowing a caller to start issuing method calls against a promised object before the + // promise has actually been fulfilled. This is particularly useful if the promise is for a + // remote object living across a network, as this can avoid round trips when chaining a series + // of calls. It is suggested that any class T which supports pipelining implement a subclass of + // Promise which adds "eventual send" methods -- methods which, when called, say "please + // invoke the corresponding method on the promised value once it is available". These methods + // should in turn return promises for the eventual results of said invocations. Cap'n Proto, + // for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see + // `capnp/capability.h`. + // + // KJ Promises are based on E promises: + // http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises + // + // KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript + // promises, which are themselves influenced by E promises: + // http://promisesaplus.com/ + // https://github.com/domenic/promises-unwrapping + +public: + Promise(_::FixVoid value); + // Construct an already-fulfilled Promise from a value of type T. For non-void promises, the + // parameter type is simply T. So, e.g., in a function that returns `Promise`, you can + // say `return 123;` to return a promise that is already fulfilled to 123. + // + // For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`. + + Promise(kj::Exception&& e); + // Construct an already-broken Promise. + + inline Promise(decltype(nullptr)) {} + + template + PromiseForResult then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException()) + KJ_WARN_UNUSED_RESULT; + // Register a continuation function to be executed when the promise completes. The continuation + // (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation + // may return a new value; `then()` itself returns a promise for the continuation's eventual + // result. If the continuation itself returns a `Promise`, then `then()` shall also return + // a `Promise` which first waits for the original promise, then executes the continuation, + // then waits for the inner promise (i.e. it automatically "unwraps" the promise). + // + // In all cases, `then()` returns immediately. The continuation is executed later. The + // continuation is always executed on the same EventLoop (and, therefore, the same thread) which + // called `then()`, therefore no synchronization is necessary on state shared by the continuation + // and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws + // an exception. + // + // You may also specify an error handler continuation as the second parameter. `errorHandler` + // must be a functor taking a parameter of type `kj::Exception&&`. It must return the same + // type as `func` returns (except when `func` returns `Promise`, in which case `errorHandler` + // may return either `Promise` or just `U`). The default error handler simply propagates the + // exception to the returned promise. + // + // Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise + // is broken. When compiled with -fno-exceptions, the framework will still detect when a + // recoverable exception was thrown inside of a continuation and will consider the promise + // broken even though a (presumably garbage) result was returned. + // + // If the returned promise is destroyed before the callback runs, the callback will be canceled + // (it will never run). + // + // Note that `then()` -- like all other Promise methods -- consumes the promise on which it is + // called, in the sense of move semantics. After returning, the original promise is no longer + // valid, but `then()` returns a new promise. + // + // *Advanced implementation tips:* Most users will never need to worry about the below, but + // it is good to be aware of. + // + // As an optimization, if the callback function `func` does _not_ return another promise, then + // execution of `func` itself may be delayed until its result is known to be needed. The + // expectation here is that `func` is just doing some transformation on the results, not + // scheduling any other actions, therefore the system doesn't need to be proactive about + // evaluating it. This way, a chain of trivial then() transformations can be executed all at + // once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()` + // method to suppress this behavior. + // + // On the other hand, if `func` _does_ return another promise, then the system evaluates `func` + // as soon as possible, because the promise it returns might be for a newly-scheduled + // long-running asynchronous task. + // + // As another optimization, when a callback function registered with `then()` is actually + // scheduled, it is scheduled to occur immediately, preempting other work in the event queue. + // This allows a long chain of `then`s to execute all at once, improving cache locality by + // clustering operations on the same data. However, this implies that starvation can occur + // if a chain of `then()`s takes a very long time to execute without ever stopping to wait for + // actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events + // in the queue will get a chance to run before your callback is executed. + + Promise ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); } + // Convenience method to convert the promise to a void promise by ignoring the return value. + // + // You must still wait on the returned promise if you want the task to execute. + + template + Promise catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; + // Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that + // just returns its input. + + T wait(WaitScope& waitScope); + // Run the event loop until the promise is fulfilled, then return its result. If the promise + // is rejected, throw an exception. + // + // wait() is primarily useful at the top level of a program -- typically, within the function + // that allocated the EventLoop. For example, a program that performs one or two RPCs and then + // exits would likely use wait() in its main() function to wait on each RPC. On the other hand, + // server-side code generally cannot use wait(), because it has to be able to accept multiple + // requests at once. + // + // If the promise is rejected, `wait()` throws an exception. If the program was compiled without + // exceptions (-fno-exceptions), this will usually abort. In this case you really should first + // use `then()` to set an appropriate handler for the exception case, so that the promise you + // actually wait on never throws. + // + // `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By + // convention, any function which might call wait(), or which might call another function which + // might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two + // reasons: + // * `wait()` is not allowed during an event callback, because event callbacks are themselves + // called during some other `wait()`, and such recursive `wait()`s would only be able to + // complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer + // than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during + // an event callback. + // * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()` + // returns. This means that anyone calling `wait()` must be reentrant -- state may change + // around them in arbitrary ways. Therefore, callers really need to know if a function they + // are calling might wait(), and the `WaitScope&` parameter makes this clear. + // + // TODO(someday): Implement fibers, and let them call wait() even when they are handling an + // event. + + ForkedPromise fork() KJ_WARN_UNUSED_RESULT; + // Forks the promise, so that multiple different clients can independently wait on the result. + // `T` must be copy-constructable for this to work. Or, in the special case where `T` is + // `Own`, `U` must have a method `Own addRef()` which returns a new reference to the same + // (or an equivalent) object (probably implemented via reference counting). + + _::SplitTuplePromise split(); + // Split a promise for a tuple into a tuple of promises. + // + // E.g. if you have `Promise>`, `split()` returns + // `kj::Tuple, Promise>`. + + Promise exclusiveJoin(Promise&& other) KJ_WARN_UNUSED_RESULT; + // Return a new promise that resolves when either the original promise resolves or `other` + // resolves (whichever comes first). The promise that didn't resolve first is canceled. + + // TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions + // and produces a tuple? + + template + Promise attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; + // "Attaches" one or more movable objects (often, Owns) to the promise, such that they will + // be destroyed when the promise resolves. This is useful when a promise's callback contains + // pointers into some object and you want to make sure the object still exists when the callback + // runs -- after calling then(), use attach() to add necessary objects to the result. + + template + Promise eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT; + Promise eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT; + // Force eager evaluation of this promise. Use this if you are going to hold on to the promise + // for awhile without consuming the result, but you want to make sure that the system actually + // processes it. + // + // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to + // `then()`, except that it must return void. We make you specify this because otherwise it's + // easy to forget to handle errors in a promise that you never use. You may specify nullptr for + // the error handler if you are sure that ignoring errors is fine, or if you know that you'll + // eventually wait on the promise somewhere. + + template + void detach(ErrorFunc&& errorHandler); + // Allows the promise to continue running in the background until it completes or the + // `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this + // promise, you need to make sure that the promise owns all the objects it touches or make sure + // those objects outlive the EventLoop. + // + // `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to + // `then()`, except that it must return void. + // + // This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be + // canceled unless the callee explicitly permits it. + + kj::String trace(); + // Returns a dump of debug info about this promise. Not for production use. Requires RTTI. + // This method does NOT consume the promise as other methods do. + +private: + Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {} + // Second parameter prevent ambiguity with immediate-value constructor. + + template + friend class Promise; + friend class EventLoop; + template + friend Promise newAdaptedPromise(Params&&... adapterConstructorParams); + template + friend PromiseFulfillerPair newPromiseAndFulfiller(); + template + friend class _::ForkHub; + friend class _::TaskSetImpl; + friend Promise _::yield(); + friend class _::NeverDone; + template + friend Promise> joinPromises(Array>&& promises); + friend Promise joinPromises(Array>&& promises); +}; + +template +class ForkedPromise { + // The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created. + // Like `Promise`, this is a pass-by-move type. + +public: + inline ForkedPromise(decltype(nullptr)) {} + + Promise addBranch(); + // Add a new branch to the fork. The branch is equivalent to the original promise. + +private: + Own<_::ForkHub<_::FixVoid>> hub; + + inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid>>&& hub): hub(kj::mv(hub)) {} + + friend class Promise; + friend class EventLoop; +}; + +constexpr _::Void READY_NOW = _::Void(); +// Use this when you need a Promise that is already fulfilled -- this value can be implicitly +// cast to `Promise`. + +constexpr _::NeverDone NEVER_DONE = _::NeverDone(); +// The opposite of `READY_NOW`, return this when the promise should never resolve. This can be +// implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait +// forever (useful for servers). + +template +PromiseForResult evalLater(Func&& func) KJ_WARN_UNUSED_RESULT; +// Schedule for the given zero-parameter function to be executed in the event loop at some +// point in the near future. Returns a Promise for its result -- or, if `func()` itself returns +// a promise, `evalLater()` returns a Promise for the result of resolving that promise. +// +// Example usage: +// Promise x = evalLater([]() { return 123; }); +// +// The above is exactly equivalent to: +// Promise x = Promise(READY_NOW).then([]() { return 123; }); +// +// If the returned promise is destroyed before the callback runs, the callback will be canceled +// (never called). +// +// If you schedule several evaluations with `evalLater` during the same callback, they are +// guaranteed to be executed in order. + +template +PromiseForResult evalNow(Func&& func) KJ_WARN_UNUSED_RESULT; +// Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns. +// If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the +// main reason why `evalNow()` is useful. + +template +Promise> joinPromises(Array>&& promises); +// Join an array of promises into a promise for an array. + +// ======================================================================================= +// Hack for creating a lambda that holds an owned pointer. + +template +class CaptureByMove { +public: + inline CaptureByMove(Func&& func, MovedParam&& param) + : func(kj::mv(func)), param(kj::mv(param)) {} + + template + inline auto operator()(Params&&... params) + -> decltype(kj::instance()(kj::instance(), kj::fwd(params)...)) { + return func(kj::mv(param), kj::fwd(params)...); + } + +private: + Func func; + MovedParam param; +}; + +template +inline CaptureByMove> mvCapture(MovedParam&& param, Func&& func) { + // Hack to create a "lambda" which captures a variable by moving it rather than copying or + // referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this + // is commonly needed for Promise continuations that own their state. Example usage: + // + // Own ptr = makeFoo(); + // Promise promise = callRpc(); + // promise.then(mvCapture(ptr, [](Own&& ptr, int result) { + // return ptr->finish(result); + // })); + + return CaptureByMove>(kj::fwd(func), kj::mv(param)); +} + +// ======================================================================================= +// Advanced promise construction + +template +class PromiseFulfiller { + // A callback which can be used to fulfill a promise. Only the first call to fulfill() or + // reject() matters; subsequent calls are ignored. + +public: + virtual void fulfill(T&& value) = 0; + // Fulfill the promise with the given value. + + virtual void reject(Exception&& exception) = 0; + // Reject the promise with an error. + + virtual bool isWaiting() = 0; + // Returns true if the promise is still unfulfilled and someone is potentially waiting for it. + // Returns false if fulfill()/reject() has already been called *or* if the promise to be + // fulfilled has been discarded and therefore the result will never be used anyway. + + template + bool rejectIfThrows(Func&& func); + // Call the function (with no arguments) and return true. If an exception is thrown, call + // `fulfiller.reject()` and then return false. When compiled with exceptions disabled, + // non-fatal exceptions are still detected and handled correctly. +}; + +template <> +class PromiseFulfiller { + // Specialization of PromiseFulfiller for void promises. See PromiseFulfiller. + +public: + virtual void fulfill(_::Void&& value = _::Void()) = 0; + // Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't + // have to specialize for . + + virtual void reject(Exception&& exception) = 0; + virtual bool isWaiting() = 0; + + template + bool rejectIfThrows(Func&& func); +}; + +template +Promise newAdaptedPromise(Params&&... adapterConstructorParams); +// Creates a new promise which owns an instance of `Adapter` which encapsulates the operation +// that will eventually fulfill the promise. This is primarily useful for adapting non-KJ +// asynchronous APIs to use promises. +// +// An instance of `Adapter` will be allocated and owned by the returned `Promise`. A +// `PromiseFulfiller&` will be passed as the first parameter to the adapter's constructor, +// and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter +// is expected to perform some asynchronous operation and call the `PromiseFulfiller` once +// it is finished. +// +// The adapter is destroyed when its owning Promise is destroyed. This may occur before the +// Promise has been fulfilled. In this case, the adapter's destructor should cancel the +// asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be +// called. +// +// An adapter implementation should be carefully written to ensure that it cannot accidentally +// be left unfulfilled permanently because of an exception. Consider making liberal use of +// `PromiseFulfiller::rejectIfThrows()`. + +template +struct PromiseFulfillerPair { + Promise<_::JoinPromises> promise; + Own> fulfiller; +}; + +template +PromiseFulfillerPair newPromiseAndFulfiller(); +// Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise. +// If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is +// implicitly rejected. +// +// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback +// that there is no way to handle cancellation (i.e. detect when the Promise is discarded). +// +// You can arrange to fulfill a promise with another promise by using a promise type for T. E.g. +// `newPromiseAndFulfiller>()` will produce a promise of type `Promise` but the +// fulfiller will be of type `PromiseFulfiller>`. Thus you pass a `Promise` to the +// `fulfill()` callback, and the promises are chained. + +// ======================================================================================= +// TaskSet + +class TaskSet { + // Holds a collection of Promises and ensures that each executes to completion. Memory + // associated with each promise is automatically freed when the promise completes. Destroying + // the TaskSet itself automatically cancels all unfinished promises. + // + // This is useful for "daemon" objects that perform background tasks which aren't intended to + // fulfill any particular external promise, but which may need to be canceled (and thus can't + // use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is + // working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well, + // and everything the daemon is doing is canceled. + +public: + class ErrorHandler { + public: + virtual void taskFailed(kj::Exception&& exception) = 0; + }; + + TaskSet(ErrorHandler& errorHandler); + // `loop` will be used to wait on promises. `errorHandler` will be executed any time a task + // throws an exception, and will execute within the given EventLoop. + + ~TaskSet() noexcept(false); + + void add(Promise&& promise); + + kj::String trace(); + // Return debug info about all promises currently in the TaskSet. + +private: + Own<_::TaskSetImpl> impl; +}; + +// ======================================================================================= +// The EventLoop class + +class EventPort { + // Interfaces between an `EventLoop` and events originating from outside of the loop's thread. + // All such events come in through the `EventPort` implementation. + // + // An `EventPort` implementation may interface with low-level operating system APIs and/or other + // threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop + // framework, allowing the two to coexist in a single thread. + +public: + virtual bool wait() = 0; + // Wait for an external event to arrive, sleeping if necessary. Once at least one event has + // arrived, queue it to the event loop (e.g. by fulfilling a promise) and return. + // + // This is called during `Promise::wait()` whenever the event queue becomes empty, in order to + // wait for new events to populate the queue. + // + // It is safe to return even if nothing has actually been queued, so long as calling `wait()` in + // a loop will eventually sleep. (That is to say, false positives are fine.) + // + // Returns true if wake() has been called from another thread. (Precisely, returns true if + // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last + // called.) + + virtual bool poll() = 0; + // Check if any external events have arrived, but do not sleep. If any events have arrived, + // add them to the event queue (e.g. by fulfilling promises) before returning. + // + // This may be called during `Promise::wait()` when the EventLoop has been executing for a while + // without a break but is still non-empty. + // + // Returns true if wake() has been called from another thread. (Precisely, returns true if + // no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last + // called.) + + virtual void setRunnable(bool runnable); + // Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it + // transitions from empty -> runnable or runnable -> empty. This is typically useful when + // integrating with an external event loop; if the loop is currently runnable then you should + // arrange to call run() on it soon. The default implementation does nothing. + + virtual void wake() const; + // Wake up the EventPort's thread from another thread. + // + // Unlike all other methods on this interface, `wake()` may be called from another thread, hence + // it is `const`. + // + // Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep + // again until `wait()` or `poll()` has returned true at least once. + // + // The default implementation throws an UNIMPLEMENTED exception. +}; + +class EventLoop { + // Represents a queue of events being executed in a loop. Most code won't interact with + // EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the + // documentation for `Promise`. + // + // Each thread can have at most one current EventLoop. To make an `EventLoop` current for + // the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop, + // or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly + // be passed a reference to the `WaitScope` to make the caller aware that they might block. + // + // Generally, you will want to construct an `EventLoop` at the top level of your program, e.g. + // in the main() function, or in the start function of a thread. You can then use it to + // construct some promises and wait on the result. Example: + // + // int main() { + // // `loop` becomes the official EventLoop for the thread. + // MyEventPort eventPort; + // EventLoop loop(eventPort); + // + // // Now we can call an async function. + // Promise textPromise = getHttp("http://example.com"); + // + // // And we can wait for the promise to complete. Note that you can only use `wait()` + // // from the top level, not from inside a promise callback. + // String text = textPromise.wait(); + // print(text); + // return 0; + // } + // + // Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather + // than allocate an `EventLoop` directly. + +public: + EventLoop(); + // Construct an `EventLoop` which does not receive external events at all. + + explicit EventLoop(EventPort& port); + // Construct an `EventLoop` which receives external events through the given `EventPort`. + + ~EventLoop() noexcept(false); + + void run(uint maxTurnCount = maxValue); + // Run the event loop for `maxTurnCount` turns or until there is nothing left to be done, + // whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will + // call the `EventPort`'s `setRunnable(false)` if the queue becomes empty. + + bool isRunnable(); + // Returns true if run() would currently do anything, or false if the queue is empty. + +private: + EventPort& port; + + bool running = false; + // True while looping -- wait() is then not allowed. + + bool lastRunnableState = false; + // What did we last pass to port.setRunnable()? + + _::Event* head = nullptr; + _::Event** tail = &head; + _::Event** depthFirstInsertPoint = &head; + + Own<_::TaskSetImpl> daemons; + + bool turn(); + void setRunnable(bool runnable); + void enterScope(); + void leaveScope(); + + friend void _::detach(kj::Promise&& promise); + friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, + WaitScope& waitScope); + friend class _::Event; + friend class WaitScope; +}; + +class WaitScope { + // Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually + // be allocated on the stack and serves two purposes: + // * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the + // thread. Most operations dealing with `Promise` (including all of its methods) do not work + // unless the thread has a current `EventLoop`. + // * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular + // promise to complete. See `Promise::wait()` for an extended discussion. + +public: + inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); } + inline ~WaitScope() { loop.leaveScope(); } + KJ_DISALLOW_COPY(WaitScope); + +private: + EventLoop& loop; + friend class EventLoop; + friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, + WaitScope& waitScope); +}; + +} // namespace kj + +#include "async-inl.h" + +#endif // KJ_ASYNC_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/common-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/common-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,482 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "common.h" +#include "test.h" +#include +#include + +namespace kj { +namespace { + +KJ_TEST("kj::size() on native arrays") { + int arr[] = {12, 34, 56, 78}; + + size_t expected = 0; + for (size_t i: indices(arr)) { + KJ_EXPECT(i == expected++); + } + KJ_EXPECT(expected == 4u); +} + +struct ImplicitToInt { + int i; + + operator int() const { + return i; + } +}; + +TEST(Common, Maybe) { + { + Maybe m = 123; + EXPECT_FALSE(m == nullptr); + EXPECT_TRUE(m != nullptr); + KJ_IF_MAYBE(v, m) { + EXPECT_EQ(123, *v); + } else { + ADD_FAILURE(); + } + KJ_IF_MAYBE(v, mv(m)) { + EXPECT_EQ(123, *v); + } else { + ADD_FAILURE(); + } + EXPECT_EQ(123, m.orDefault(456)); + } + + { + Maybe m = nullptr; + EXPECT_TRUE(m == nullptr); + EXPECT_FALSE(m != nullptr); + KJ_IF_MAYBE(v, m) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + KJ_IF_MAYBE(v, mv(m)) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + EXPECT_EQ(456, m.orDefault(456)); + } + + int i = 234; + { + Maybe m = i; + EXPECT_FALSE(m == nullptr); + EXPECT_TRUE(m != nullptr); + KJ_IF_MAYBE(v, m) { + EXPECT_EQ(&i, v); + } else { + ADD_FAILURE(); + } + KJ_IF_MAYBE(v, mv(m)) { + EXPECT_EQ(&i, v); + } else { + ADD_FAILURE(); + } + EXPECT_EQ(234, m.orDefault(456)); + } + + { + Maybe m = nullptr; + EXPECT_TRUE(m == nullptr); + EXPECT_FALSE(m != nullptr); + KJ_IF_MAYBE(v, m) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + KJ_IF_MAYBE(v, mv(m)) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + EXPECT_EQ(456, m.orDefault(456)); + } + + { + Maybe m = &i; + EXPECT_FALSE(m == nullptr); + EXPECT_TRUE(m != nullptr); + KJ_IF_MAYBE(v, m) { + EXPECT_EQ(&i, v); + } else { + ADD_FAILURE(); + } + KJ_IF_MAYBE(v, mv(m)) { + EXPECT_EQ(&i, v); + } else { + ADD_FAILURE(); + } + EXPECT_EQ(234, m.orDefault(456)); + } + + { + Maybe m = implicitCast(nullptr); + EXPECT_TRUE(m == nullptr); + EXPECT_FALSE(m != nullptr); + KJ_IF_MAYBE(v, m) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + KJ_IF_MAYBE(v, mv(m)) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + EXPECT_EQ(456, m.orDefault(456)); + } + + { + Maybe m = &i; + EXPECT_FALSE(m == nullptr); + EXPECT_TRUE(m != nullptr); + KJ_IF_MAYBE(v, m) { + EXPECT_NE(v, &i); + EXPECT_EQ(234, *v); + } else { + ADD_FAILURE(); + } + KJ_IF_MAYBE(v, mv(m)) { + EXPECT_NE(v, &i); + EXPECT_EQ(234, *v); + } else { + ADD_FAILURE(); + } + } + + { + Maybe m = implicitCast(nullptr); + EXPECT_TRUE(m == nullptr); + EXPECT_FALSE(m != nullptr); + KJ_IF_MAYBE(v, m) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + KJ_IF_MAYBE(v, mv(m)) { + ADD_FAILURE(); + EXPECT_EQ(0, *v); // avoid unused warning + } + } + + { + // Test a case where an implicit conversion didn't used to happen correctly. + Maybe m(ImplicitToInt { 123 }); + Maybe m2(m); + Maybe m3(kj::mv(m)); + KJ_IF_MAYBE(v, m2) { + EXPECT_EQ(123, *v); + } else { + ADD_FAILURE(); + } + KJ_IF_MAYBE(v, m3) { + EXPECT_EQ(123, *v); + } else { + ADD_FAILURE(); + } + } +} + +TEST(Common, MaybeConstness) { + int i; + + Maybe mi = i; + const Maybe cmi = mi; +// const Maybe cmi2 = cmi; // shouldn't compile! Transitive const violation. + + KJ_IF_MAYBE(i2, cmi) { + EXPECT_EQ(&i, i2); + } else { + ADD_FAILURE(); + } + + Maybe mci = mi; + const Maybe cmci = mci; + const Maybe cmci2 = cmci; + + KJ_IF_MAYBE(i2, cmci2) { + EXPECT_EQ(&i, i2); + } else { + ADD_FAILURE(); + } +} + +class Foo { +public: + KJ_DISALLOW_COPY(Foo); + virtual ~Foo() {} +protected: + Foo() = default; +}; + +class Bar: public Foo { +public: + Bar() = default; + KJ_DISALLOW_COPY(Bar); + virtual ~Bar() {} +}; + +class Baz: public Foo { +public: + Baz() = delete; + KJ_DISALLOW_COPY(Baz); + virtual ~Baz() {} +}; + +TEST(Common, Downcast) { + Bar bar; + Foo& foo = bar; + + EXPECT_EQ(&bar, &downcast(foo)); +#if defined(KJ_DEBUG) && !KJ_NO_RTTI + KJ_EXPECT_THROW_MESSAGE("Value cannot be downcast", downcast(foo)); +#endif + +#if KJ_NO_RTTI + EXPECT_TRUE(dynamicDowncastIfAvailable(foo) == nullptr); + EXPECT_TRUE(dynamicDowncastIfAvailable(foo) == nullptr); +#else + KJ_IF_MAYBE(m, dynamicDowncastIfAvailable(foo)) { + EXPECT_EQ(&bar, m); + } else { + KJ_FAIL_ASSERT("Dynamic downcast returned null."); + } + EXPECT_TRUE(dynamicDowncastIfAvailable(foo) == nullptr); +#endif +} + +TEST(Common, MinMax) { + EXPECT_EQ(5, kj::min(5, 9)); + EXPECT_EQ(5, kj::min(9, 5)); + EXPECT_EQ(5, kj::min(5, 5)); + EXPECT_EQ(9, kj::max(5, 9)); + EXPECT_EQ(9, kj::max(9, 5)); + EXPECT_EQ(5, kj::min(5, 5)); + + // Hey look, we can handle the types mismatching. Eat your heart out, std. + EXPECT_EQ(5, kj::min(5, 'a')); + EXPECT_EQ(5, kj::min('a', 5)); + EXPECT_EQ('a', kj::max(5, 'a')); + EXPECT_EQ('a', kj::max('a', 5)); + + EXPECT_EQ('a', kj::min(1234567890123456789ll, 'a')); + EXPECT_EQ('a', kj::min('a', 1234567890123456789ll)); + EXPECT_EQ(1234567890123456789ll, kj::max(1234567890123456789ll, 'a')); + EXPECT_EQ(1234567890123456789ll, kj::max('a', 1234567890123456789ll)); +} + +TEST(Common, MinMaxValue) { + EXPECT_EQ(0x7f, int8_t(maxValue)); + EXPECT_EQ(0xffu, uint8_t(maxValue)); + EXPECT_EQ(0x7fff, int16_t(maxValue)); + EXPECT_EQ(0xffffu, uint16_t(maxValue)); + EXPECT_EQ(0x7fffffff, int32_t(maxValue)); + EXPECT_EQ(0xffffffffu, uint32_t(maxValue)); + EXPECT_EQ(0x7fffffffffffffffll, int64_t(maxValue)); + EXPECT_EQ(0xffffffffffffffffull, uint64_t(maxValue)); + + EXPECT_EQ(-0x80, int8_t(minValue)); + EXPECT_EQ(0, uint8_t(minValue)); + EXPECT_EQ(-0x8000, int16_t(minValue)); + EXPECT_EQ(0, uint16_t(minValue)); + EXPECT_EQ(-0x80000000, int32_t(minValue)); + EXPECT_EQ(0, uint32_t(minValue)); + EXPECT_EQ(-0x8000000000000000ll, int64_t(minValue)); + EXPECT_EQ(0, uint64_t(minValue)); + + double f = inf(); + EXPECT_TRUE(f * 2 == f); + + f = nan(); + EXPECT_FALSE(f == f); + + // `char`'s signedness is platform-specific. + EXPECT_LE(char(minValue), '\0'); + EXPECT_GE(char(maxValue), '\x7f'); +} + +TEST(Common, Defer) { + uint i = 0; + uint j = 1; + bool k = false; + + { + KJ_DEFER(++i); + KJ_DEFER(j += 3; k = true); + EXPECT_EQ(0u, i); + EXPECT_EQ(1u, j); + EXPECT_FALSE(k); + } + + EXPECT_EQ(1u, i); + EXPECT_EQ(4u, j); + EXPECT_TRUE(k); +} + +TEST(Common, CanConvert) { + static_assert(canConvert(), "failure"); + static_assert(!canConvert(), "failure"); + + struct Super {}; + struct Sub: public Super {}; + + static_assert(canConvert(), "failure"); + static_assert(!canConvert(), "failure"); + static_assert(canConvert(), "failure"); + static_assert(!canConvert(), "failure"); + + static_assert(canConvert(), "failure"); + static_assert(!canConvert(), "failure"); +} + +TEST(Common, ArrayAsBytes) { + uint32_t raw[] = { 0x12345678u, 0x9abcdef0u }; + + ArrayPtr array = raw; + ASSERT_EQ(2, array.size()); + EXPECT_EQ(0x12345678u, array[0]); + EXPECT_EQ(0x9abcdef0u, array[1]); + + { + ArrayPtr bytes = array.asBytes(); + ASSERT_EQ(8, bytes.size()); + + if (bytes[0] == '\x12') { + // big-endian + EXPECT_EQ(0x12u, bytes[0]); + EXPECT_EQ(0x34u, bytes[1]); + EXPECT_EQ(0x56u, bytes[2]); + EXPECT_EQ(0x78u, bytes[3]); + EXPECT_EQ(0x9au, bytes[4]); + EXPECT_EQ(0xbcu, bytes[5]); + EXPECT_EQ(0xdeu, bytes[6]); + EXPECT_EQ(0xf0u, bytes[7]); + } else { + // little-endian + EXPECT_EQ(0x12u, bytes[3]); + EXPECT_EQ(0x34u, bytes[2]); + EXPECT_EQ(0x56u, bytes[1]); + EXPECT_EQ(0x78u, bytes[0]); + EXPECT_EQ(0x9au, bytes[7]); + EXPECT_EQ(0xbcu, bytes[6]); + EXPECT_EQ(0xdeu, bytes[5]); + EXPECT_EQ(0xf0u, bytes[4]); + } + } + + { + ArrayPtr chars = array.asChars(); + ASSERT_EQ(8, chars.size()); + + if (chars[0] == '\x12') { + // big-endian + EXPECT_EQ('\x12', chars[0]); + EXPECT_EQ('\x34', chars[1]); + EXPECT_EQ('\x56', chars[2]); + EXPECT_EQ('\x78', chars[3]); + EXPECT_EQ('\x9a', chars[4]); + EXPECT_EQ('\xbc', chars[5]); + EXPECT_EQ('\xde', chars[6]); + EXPECT_EQ('\xf0', chars[7]); + } else { + // little-endian + EXPECT_EQ('\x12', chars[3]); + EXPECT_EQ('\x34', chars[2]); + EXPECT_EQ('\x56', chars[1]); + EXPECT_EQ('\x78', chars[0]); + EXPECT_EQ('\x9a', chars[7]); + EXPECT_EQ('\xbc', chars[6]); + EXPECT_EQ('\xde', chars[5]); + EXPECT_EQ('\xf0', chars[4]); + } + } + + ArrayPtr constArray = array; + + { + ArrayPtr bytes = constArray.asBytes(); + ASSERT_EQ(8, bytes.size()); + + if (bytes[0] == '\x12') { + // big-endian + EXPECT_EQ(0x12u, bytes[0]); + EXPECT_EQ(0x34u, bytes[1]); + EXPECT_EQ(0x56u, bytes[2]); + EXPECT_EQ(0x78u, bytes[3]); + EXPECT_EQ(0x9au, bytes[4]); + EXPECT_EQ(0xbcu, bytes[5]); + EXPECT_EQ(0xdeu, bytes[6]); + EXPECT_EQ(0xf0u, bytes[7]); + } else { + // little-endian + EXPECT_EQ(0x12u, bytes[3]); + EXPECT_EQ(0x34u, bytes[2]); + EXPECT_EQ(0x56u, bytes[1]); + EXPECT_EQ(0x78u, bytes[0]); + EXPECT_EQ(0x9au, bytes[7]); + EXPECT_EQ(0xbcu, bytes[6]); + EXPECT_EQ(0xdeu, bytes[5]); + EXPECT_EQ(0xf0u, bytes[4]); + } + } + + { + ArrayPtr chars = constArray.asChars(); + ASSERT_EQ(8, chars.size()); + + if (chars[0] == '\x12') { + // big-endian + EXPECT_EQ('\x12', chars[0]); + EXPECT_EQ('\x34', chars[1]); + EXPECT_EQ('\x56', chars[2]); + EXPECT_EQ('\x78', chars[3]); + EXPECT_EQ('\x9a', chars[4]); + EXPECT_EQ('\xbc', chars[5]); + EXPECT_EQ('\xde', chars[6]); + EXPECT_EQ('\xf0', chars[7]); + } else { + // little-endian + EXPECT_EQ('\x12', chars[3]); + EXPECT_EQ('\x34', chars[2]); + EXPECT_EQ('\x56', chars[1]); + EXPECT_EQ('\x78', chars[0]); + EXPECT_EQ('\x9a', chars[7]); + EXPECT_EQ('\xbc', chars[6]); + EXPECT_EQ('\xde', chars[5]); + EXPECT_EQ('\xf0', chars[4]); + } + } +} + +KJ_TEST("kj::range()") { + uint expected = 5; + for (uint i: range(5, 10)) { + KJ_EXPECT(i == expected++); + } + KJ_EXPECT(expected == 10); + + expected = 0; + for (uint i: range(0, 8)) { + KJ_EXPECT(i == expected++); + } + KJ_EXPECT(expected == 8); +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/common.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/common.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,58 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "common.h" +#include "debug.h" +#include +#ifdef _MSC_VER +#include +#endif + +namespace kj { +namespace _ { // private + +void inlineRequireFailure(const char* file, int line, const char* expectation, + const char* macroArgs, const char* message) { + if (message == nullptr) { + Debug::Fault f(file, line, kj::Exception::Type::FAILED, expectation, macroArgs); + f.fatal(); + } else { + Debug::Fault f(file, line, kj::Exception::Type::FAILED, expectation, macroArgs, message); + f.fatal(); + } +} + +void unreachable() { + KJ_FAIL_ASSERT("Supposedly-unreachable branch executed."); + + // Really make sure we abort. + abort(); +} + +} // namespace _ (private) + +#if _MSC_VER + +float nan() { return std::numeric_limits::quiet_NaN(); } + +#endif + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/common.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1400 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Header that should be #included by everyone. +// +// This defines very simple utilities that are widely applicable. + +#ifndef KJ_COMMON_H_ +#define KJ_COMMON_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#ifndef KJ_NO_COMPILER_CHECK +#if __cplusplus < 201103L && !__CDT_PARSER__ && !_MSC_VER + #error "This code requires C++11. Either your compiler does not support it or it is not enabled." + #ifdef __GNUC__ + // Compiler claims compatibility with GCC, so presumably supports -std. + #error "Pass -std=c++11 on the compiler command line to enable C++11." + #endif +#endif + +#ifdef __GNUC__ + #if __clang__ + #if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2) + #warning "This library requires at least Clang 3.2." + #elif defined(__apple_build_version__) && __apple_build_version__ <= 4250028 + #warning "This library requires at least Clang 3.2. XCode 4.6's Clang, which claims to be "\ + "version 4.2 (wat?), is actually built from some random SVN revision between 3.1 "\ + "and 3.2. Unfortunately, it is insufficient for compiling this library. You can "\ + "download the real Clang 3.2 (or newer) from the Clang web site. Step-by-step "\ + "instructions can be found in Cap'n Proto's documentation: "\ + "http://kentonv.github.io/capnproto/install.html#clang_32_on_mac_osx" + #elif __cplusplus >= 201103L && !__has_include() + #warning "Your compiler supports C++11 but your C++ standard library does not. If your "\ + "system has libc++ installed (as should be the case on e.g. Mac OSX), try adding "\ + "-stdlib=libc++ to your CXXFLAGS." + #endif + #else + #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) + #warning "This library requires at least GCC 4.7." + #endif + #endif +#elif defined(_MSC_VER) + #if _MSC_VER < 1900 + #error "You need Visual Studio 2015 or better to compile this code." + #endif +#else + #warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\ + "known compilers with enough C++11 support for this library. "\ + "#define KJ_NO_COMPILER_CHECK to make this warning go away." +#endif +#endif + +#include +#include + +#if __linux__ && __cplusplus > 201200L +// Hack around stdlib bug with C++14 that exists on some Linux systems. +// Apparently in this mode the C library decides not to define gets() but the C++ library still +// tries to import it into the std namespace. This bug has been fixed at the source but is still +// widely present in the wild e.g. on Ubuntu 14.04. +#undef _GLIBCXX_HAVE_GETS +#endif + +#if defined(_MSC_VER) +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include // __popcnt +#endif + +// ======================================================================================= + +namespace kj { + +typedef unsigned int uint; +typedef unsigned char byte; + +// ======================================================================================= +// Common macros, especially for common yet compiler-specific features. + +// Detect whether RTTI and exceptions are enabled, assuming they are unless we have specific +// evidence to the contrary. Clients can always define KJ_NO_RTTI or KJ_NO_EXCEPTIONS explicitly +// to override these checks. +#ifdef __GNUC__ + #if !defined(KJ_NO_RTTI) && !__GXX_RTTI + #define KJ_NO_RTTI 1 + #endif + #if !defined(KJ_NO_EXCEPTIONS) && !__EXCEPTIONS + #define KJ_NO_EXCEPTIONS 1 + #endif +#elif defined(_MSC_VER) + #if !defined(KJ_NO_RTTI) && !defined(_CPPRTTI) + #define KJ_NO_RTTI 1 + #endif + #if !defined(KJ_NO_EXCEPTIONS) && !defined(_CPPUNWIND) + #define KJ_NO_EXCEPTIONS 1 + #endif +#endif + +#if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG) +// Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that. +// Otherwise, fall back to checking whether optimization is enabled. +#if defined(DEBUG) || defined(_DEBUG) +#define KJ_DEBUG +#elif defined(NDEBUG) +#define KJ_NDEBUG +#elif __OPTIMIZE__ +#define KJ_NDEBUG +#else +#define KJ_DEBUG +#endif +#endif + +#define KJ_DISALLOW_COPY(classname) \ + classname(const classname&) = delete; \ + classname& operator=(const classname&) = delete +// Deletes the implicit copy constructor and assignment operator. + +#ifdef __GNUC__ +#define KJ_LIKELY(condition) __builtin_expect(condition, true) +#define KJ_UNLIKELY(condition) __builtin_expect(condition, false) +// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we +// expect the condition to be true/false enough of the time that it's worth hard-coding branch +// prediction. +#else +#define KJ_LIKELY(condition) (condition) +#define KJ_UNLIKELY(condition) (condition) +#endif + +#if defined(KJ_DEBUG) || __NO_INLINE__ +#define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ +// Don't force inline in debug mode. +#else +#if defined(_MSC_VER) +#define KJ_ALWAYS_INLINE(...) __forceinline __VA_ARGS__ +#else +#define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ __attribute__((always_inline)) +#endif +// Force a function to always be inlined. Apply only to the prototype, not to the definition. +#endif + +#if defined(_MSC_VER) +#define KJ_NOINLINE __declspec(noinline) +#else +#define KJ_NOINLINE __attribute__((noinline)) +#endif + +#if defined(_MSC_VER) +#define KJ_NORETURN(prototype) __declspec(noreturn) prototype +#define KJ_UNUSED +#define KJ_WARN_UNUSED_RESULT +// TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so +// wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx +// Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix. +#else +#define KJ_NORETURN(prototype) prototype __attribute__((noreturn)) +#define KJ_UNUSED __attribute__((unused)) +#define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + +#if __clang__ +#define KJ_UNUSED_MEMBER __attribute__((unused)) +// Inhibits "unused" warning for member variables. Only Clang produces such a warning, while GCC +// complains if the attribute is set on members. +#else +#define KJ_UNUSED_MEMBER +#endif + +#if __clang__ +#define KJ_DEPRECATED(reason) \ + __attribute__((deprecated(reason))) +#define KJ_UNAVAILABLE(reason) \ + __attribute__((unavailable(reason))) +#elif __GNUC__ +#define KJ_DEPRECATED(reason) \ + __attribute__((deprecated)) +#define KJ_UNAVAILABLE(reason) +#else +#define KJ_DEPRECATED(reason) +#define KJ_UNAVAILABLE(reason) +// TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated). +#endif + +namespace _ { // private + +KJ_NORETURN(void inlineRequireFailure( + const char* file, int line, const char* expectation, const char* macroArgs, + const char* message = nullptr)); + +KJ_NORETURN(void unreachable()); + +} // namespace _ (private) + +#ifdef KJ_DEBUG +#if _MSC_VER +#define KJ_IREQUIRE(condition, ...) \ + if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ + __FILE__, __LINE__, #condition, "" #__VA_ARGS__, __VA_ARGS__) +// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to +// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that +// it will be enabled depending on whether the application is compiled in debug mode rather than +// whether libkj is. +#else +#define KJ_IREQUIRE(condition, ...) \ + if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ + __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) +// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to +// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that +// it will be enabled depending on whether the application is compiled in debug mode rather than +// whether libkj is. +#endif +#else +#define KJ_IREQUIRE(condition, ...) +#endif + +#define KJ_IASSERT KJ_IREQUIRE + +#define KJ_UNREACHABLE ::kj::_::unreachable(); +// Put this on code paths that cannot be reached to suppress compiler warnings about missing +// returns. + +#if __clang__ +#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT +#else +#define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT KJ_UNREACHABLE +#endif + +// #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) +// +// Allocate an array, preferably on the stack, unless it is too big. On GCC this will use +// variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack` +// is the stack array size to use if variable-width arrays are not supported. `maxStack` is the +// maximum stack array size if variable-width arrays *are* supported. +#if __GNUC__ && !__clang__ +#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ + size_t name##_size = (size); \ + bool name##_isOnStack = name##_size <= (maxStack); \ + type name##_stack[name##_isOnStack ? size : 0]; \ + ::kj::Array name##_heap = name##_isOnStack ? \ + nullptr : kj::heapArray(name##_size); \ + ::kj::ArrayPtr name = name##_isOnStack ? \ + kj::arrayPtr(name##_stack, name##_size) : name##_heap +#else +#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ + size_t name##_size = (size); \ + bool name##_isOnStack = name##_size <= (minStack); \ + type name##_stack[minStack]; \ + ::kj::Array name##_heap = name##_isOnStack ? \ + nullptr : kj::heapArray(name##_size); \ + ::kj::ArrayPtr name = name##_isOnStack ? \ + kj::arrayPtr(name##_stack, name##_size) : name##_heap +#endif + +#define KJ_CONCAT_(x, y) x##y +#define KJ_CONCAT(x, y) KJ_CONCAT_(x, y) +#define KJ_UNIQUE_NAME(prefix) KJ_CONCAT(prefix, __LINE__) +// Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that +// the name can be used multiple times in the same macro. + +#if _MSC_VER + +#define KJ_CONSTEXPR(...) __VA_ARGS__ +// Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be +// provided, or just leave blank to remove the keyword entirely. +// +// TODO(msvc): Remove this hack once MSVC fully supports constexpr. + +#ifndef __restrict__ +#define __restrict__ __restrict +// TODO(msvc): Would it be better to define a KJ_RESTRICT macro? +#endif + +#pragma warning(disable: 4521 4522) +// This warning complains when there are two copy constructors, one for a const reference and +// one for a non-const reference. It is often quite necessary to do this in wrapper templates, +// therefore this warning is dumb and we disable it. + +#pragma warning(disable: 4458) +// Warns when a parameter name shadows a class member. Unfortunately my code does this a lot, +// since I don't use a special name format for members. + +#else // _MSC_VER +#define KJ_CONSTEXPR(...) constexpr +#endif + +// ======================================================================================= +// Template metaprogramming helpers. + +template struct NoInfer_ { typedef T Type; }; +template using NoInfer = typename NoInfer_::Type; +// Use NoInfer::Type in place of T for a template function parameter to prevent inference of +// the type based on the parameter value. + +template struct RemoveConst_ { typedef T Type; }; +template struct RemoveConst_ { typedef T Type; }; +template using RemoveConst = typename RemoveConst_::Type; + +template struct IsLvalueReference_ { static constexpr bool value = false; }; +template struct IsLvalueReference_ { static constexpr bool value = true; }; +template +inline constexpr bool isLvalueReference() { return IsLvalueReference_::value; } + +template struct Decay_ { typedef T Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template struct Decay_ { typedef typename Decay_::Type Type; }; +template using Decay = typename Decay_::Type; + +template struct EnableIf_; +template <> struct EnableIf_ { typedef void Type; }; +template using EnableIf = typename EnableIf_::Type; +// Use like: +// +// template ()> +// void func(T&& t); + +template struct VoidSfinae_ { using Type = void; }; +template using VoidSfinae = typename VoidSfinae_::Type; +// Note: VoidSfinae is std::void_t from C++17. + +template +T instance() noexcept; +// Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify +// instance(). + +struct DisallowConstCopy { + // Inherit from this, or declare a member variable of this type, to prevent the class from being + // copyable from a const reference -- instead, it will only be copyable from non-const references. + // This is useful for enforcing transitive constness of contained pointers. + // + // For example, say you have a type T which contains a pointer. T has non-const methods which + // modify the value at that pointer, but T's const methods are designed to allow reading only. + // Unfortunately, if T has a regular copy constructor, someone can simply make a copy of T and + // then use it to modify the pointed-to value. However, if T inherits DisallowConstCopy, then + // callers will only be able to copy non-const instances of T. Ideally, there is some + // parallel type ImmutableT which is like a version of T that only has const methods, and can + // be copied from a const T. + // + // Note that due to C++ rules about implicit copy constructors and assignment operators, any + // type that contains or inherits from a type that disallows const copies will also automatically + // disallow const copies. Hey, cool, that's exactly what we want. + +#if CAPNP_DEBUG_TYPES + // Alas! Declaring a defaulted non-const copy constructor tickles a bug which causes GCC and + // Clang to disagree on ABI, using different calling conventions to pass this type, leading to + // immediate segfaults. See: + // https://bugs.llvm.org/show_bug.cgi?id=23764 + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58074 + // + // Because of this, we can't use this technique. We guard it by CAPNP_DEBUG_TYPES so that it + // still applies to the Cap'n Proto developers during internal testing. + + DisallowConstCopy() = default; + DisallowConstCopy(DisallowConstCopy&) = default; + DisallowConstCopy(DisallowConstCopy&&) = default; + DisallowConstCopy& operator=(DisallowConstCopy&) = default; + DisallowConstCopy& operator=(DisallowConstCopy&&) = default; +#endif +}; + +#if _MSC_VER + +#define KJ_CPCAP(obj) obj=::kj::cp(obj) +// TODO(msvc): MSVC refuses to invoke non-const versions of copy constructors in by-value lambda +// captures. Wrap your captured object in this macro to force the compiler to perform a copy. +// Example: +// +// struct Foo: DisallowConstCopy {}; +// Foo foo; +// auto lambda = [KJ_CPCAP(foo)] {}; + +#else + +#define KJ_CPCAP(obj) obj +// Clang and gcc both already perform copy capturing correctly with non-const copy constructors. + +#endif + +template +struct DisallowConstCopyIfNotConst: public DisallowConstCopy { + // Inherit from this when implementing a template that contains a pointer to T and which should + // enforce transitive constness. If T is a const type, this has no effect. Otherwise, it is + // an alias for DisallowConstCopy. +}; + +template +struct DisallowConstCopyIfNotConst {}; + +template struct IsConst_ { static constexpr bool value = false; }; +template struct IsConst_ { static constexpr bool value = true; }; +template constexpr bool isConst() { return IsConst_::value; } + +template struct EnableIfNotConst_ { typedef T Type; }; +template struct EnableIfNotConst_; +template using EnableIfNotConst = typename EnableIfNotConst_::Type; + +template struct EnableIfConst_; +template struct EnableIfConst_ { typedef T Type; }; +template using EnableIfConst = typename EnableIfConst_::Type; + +template struct RemoveConstOrDisable_ { struct Type; }; +template struct RemoveConstOrDisable_ { typedef T Type; }; +template using RemoveConstOrDisable = typename RemoveConstOrDisable_::Type; + +template struct IsReference_ { static constexpr bool value = false; }; +template struct IsReference_ { static constexpr bool value = true; }; +template constexpr bool isReference() { return IsReference_::value; } + +template +struct PropagateConst_ { typedef To Type; }; +template +struct PropagateConst_ { typedef const To Type; }; +template +using PropagateConst = typename PropagateConst_::Type; + +namespace _ { // private + +template +T refIfLvalue(T&&); + +} // namespace _ (private) + +#define KJ_DECLTYPE_REF(exp) decltype(::kj::_::refIfLvalue(exp)) +// Like decltype(exp), but if exp is an lvalue, produces a reference type. +// +// int i; +// decltype(i) i1(i); // i1 has type int. +// KJ_DECLTYPE_REF(i + 1) i2(i + 1); // i2 has type int. +// KJ_DECLTYPE_REF(i) i3(i); // i3 has type int&. +// KJ_DECLTYPE_REF(kj::mv(i)) i4(kj::mv(i)); // i4 has type int. + +template +struct CanConvert_ { + static int sfinae(T); + static bool sfinae(...); +}; + +template +constexpr bool canConvert() { + return sizeof(CanConvert_::sfinae(instance())) == sizeof(int); +} + +#if __GNUC__ && !__clang__ && __GNUC__ < 5 +template +constexpr bool canMemcpy() { + // Returns true if T can be copied using memcpy instead of using the copy constructor or + // assignment operator. + + // GCC 4 does not have __is_trivially_constructible and friends, and there doesn't seem to be + // any reliable alternative. __has_trivial_copy() and __has_trivial_assign() return the right + // thing at one point but later on they changed such that a deleted copy constructor was + // considered "trivial" (apparently technically correct, though useless). So, on GCC 4 we give up + // and assume we can't memcpy() at all, and must explicitly copy-construct everything. + return false; +} +#define KJ_ASSERT_CAN_MEMCPY(T) +#else +template +constexpr bool canMemcpy() { + // Returns true if T can be copied using memcpy instead of using the copy constructor or + // assignment operator. + + return __is_trivially_constructible(T, const T&) && __is_trivially_assignable(T, const T&); +} +#define KJ_ASSERT_CAN_MEMCPY(T) \ + static_assert(kj::canMemcpy(), "this code expects this type to be memcpy()-able"); +#endif + +// ======================================================================================= +// Equivalents to std::move() and std::forward(), since these are very commonly needed and the +// std header pulls in lots of other stuff. +// +// We use abbreviated names mv and fwd because these helpers (especially mv) are so commonly used +// that the cost of typing more letters outweighs the cost of being slightly harder to understand +// when first encountered. + +template constexpr T&& mv(T& t) noexcept { return static_cast(t); } +template constexpr T&& fwd(NoInfer& t) noexcept { return static_cast(t); } + +template constexpr T cp(T& t) noexcept { return t; } +template constexpr T cp(const T& t) noexcept { return t; } +// Useful to force a copy, particularly to pass into a function that expects T&&. + +template struct ChooseType_; +template struct ChooseType_ { typedef T Type; }; +template struct ChooseType_ { typedef T Type; }; +template struct ChooseType_ { typedef U Type; }; + +template +using WiderType = typename ChooseType_= sizeof(U)>::Type; + +template +inline constexpr auto min(T&& a, U&& b) -> WiderType, Decay> { + return a < b ? WiderType, Decay>(a) : WiderType, Decay>(b); +} + +template +inline constexpr auto max(T&& a, U&& b) -> WiderType, Decay> { + return a > b ? WiderType, Decay>(a) : WiderType, Decay>(b); +} + +template +inline constexpr size_t size(T (&arr)[s]) { return s; } +template +inline constexpr size_t size(T&& arr) { return arr.size(); } +// Returns the size of the parameter, whether the parameter is a regular C array or a container +// with a `.size()` method. + +class MaxValue_ { +private: + template + inline constexpr T maxSigned() const { + return (1ull << (sizeof(T) * 8 - 1)) - 1; + } + template + inline constexpr T maxUnsigned() const { + return ~static_cast(0u); + } + +public: +#define _kJ_HANDLE_TYPE(T) \ + inline constexpr operator signed T() const { return MaxValue_::maxSigned < signed T>(); } \ + inline constexpr operator unsigned T() const { return MaxValue_::maxUnsigned(); } + _kJ_HANDLE_TYPE(char) + _kJ_HANDLE_TYPE(short) + _kJ_HANDLE_TYPE(int) + _kJ_HANDLE_TYPE(long) + _kJ_HANDLE_TYPE(long long) +#undef _kJ_HANDLE_TYPE + + inline constexpr operator char() const { + // `char` is different from both `signed char` and `unsigned char`, and may be signed or + // unsigned on different platforms. Ugh. + return char(-1) < 0 ? MaxValue_::maxSigned() + : MaxValue_::maxUnsigned(); + } +}; + +class MinValue_ { +private: + template + inline constexpr T minSigned() const { + return 1ull << (sizeof(T) * 8 - 1); + } + template + inline constexpr T minUnsigned() const { + return 0u; + } + +public: +#define _kJ_HANDLE_TYPE(T) \ + inline constexpr operator signed T() const { return MinValue_::minSigned < signed T>(); } \ + inline constexpr operator unsigned T() const { return MinValue_::minUnsigned(); } + _kJ_HANDLE_TYPE(char) + _kJ_HANDLE_TYPE(short) + _kJ_HANDLE_TYPE(int) + _kJ_HANDLE_TYPE(long) + _kJ_HANDLE_TYPE(long long) +#undef _kJ_HANDLE_TYPE + + inline constexpr operator char() const { + // `char` is different from both `signed char` and `unsigned char`, and may be signed or + // unsigned on different platforms. Ugh. + return char(-1) < 0 ? MinValue_::minSigned() + : MinValue_::minUnsigned(); + } +}; + +static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_(); +// A special constant which, when cast to an integer type, takes on the maximum possible value of +// that type. This is useful to use as e.g. a parameter to a function because it will be robust +// in the face of changes to the parameter's type. +// +// `char` is not supported, but `signed char` and `unsigned char` are. + +static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_(); +// A special constant which, when cast to an integer type, takes on the minimum possible value +// of that type. This is useful to use as e.g. a parameter to a function because it will be robust +// in the face of changes to the parameter's type. +// +// `char` is not supported, but `signed char` and `unsigned char` are. + +template +inline bool operator==(T t, MaxValue_) { return t == Decay(maxValue); } +template +inline bool operator==(T t, MinValue_) { return t == Decay(minValue); } + +template +inline constexpr unsigned long long maxValueForBits() { + // Get the maximum integer representable in the given number of bits. + + // 1ull << 64 is unfortunately undefined. + return (bits == 64 ? 0 : (1ull << bits)) - 1; +} + +struct ThrowOverflow { + // Functor which throws an exception complaining about integer overflow. Usually this is used + // with the interfaces in units.h, but is defined here because Cap'n Proto wants to avoid + // including units.h when not using CAPNP_DEBUG_TYPES. + void operator()() const; +}; + +#if __GNUC__ +inline constexpr float inf() { return __builtin_huge_valf(); } +inline constexpr float nan() { return __builtin_nanf(""); } + +#elif _MSC_VER + +// Do what MSVC math.h does +#pragma warning(push) +#pragma warning(disable: 4756) // "overflow in constant arithmetic" +inline constexpr float inf() { return (float)(1e300 * 1e300); } +#pragma warning(pop) + +float nan(); +// Unfortunatley, inf() * 0.0f produces a NaN with the sign bit set, whereas our preferred +// canonical NaN should not have the sign bit set. std::numeric_limits::quiet_NaN() +// returns the correct NaN, but we don't want to #include that here. So, we give up and make +// this out-of-line on MSVC. +// +// TODO(msvc): Can we do better? + +#else +#error "Not sure how to support your compiler." +#endif + +inline constexpr bool isNaN(float f) { return f != f; } +inline constexpr bool isNaN(double f) { return f != f; } + +inline int popCount(unsigned int x) { +#if defined(_MSC_VER) + return __popcnt(x); + // Note: __popcnt returns unsigned int, but the value is clearly guaranteed to fit into an int +#else + return __builtin_popcount(x); +#endif +} + +// ======================================================================================= +// Useful fake containers + +template +class Range { +public: + inline constexpr Range(const T& begin, const T& end): begin_(begin), end_(end) {} + inline explicit constexpr Range(const T& end): begin_(0), end_(end) {} + + class Iterator { + public: + Iterator() = default; + inline Iterator(const T& value): value(value) {} + + inline const T& operator* () const { return value; } + inline const T& operator[](size_t index) const { return value + index; } + inline Iterator& operator++() { ++value; return *this; } + inline Iterator operator++(int) { return Iterator(value++); } + inline Iterator& operator--() { --value; return *this; } + inline Iterator operator--(int) { return Iterator(value--); } + inline Iterator& operator+=(ptrdiff_t amount) { value += amount; return *this; } + inline Iterator& operator-=(ptrdiff_t amount) { value -= amount; return *this; } + inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value + amount); } + inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value - amount); } + inline ptrdiff_t operator- (const Iterator& other) const { return value - other.value; } + + inline bool operator==(const Iterator& other) const { return value == other.value; } + inline bool operator!=(const Iterator& other) const { return value != other.value; } + inline bool operator<=(const Iterator& other) const { return value <= other.value; } + inline bool operator>=(const Iterator& other) const { return value >= other.value; } + inline bool operator< (const Iterator& other) const { return value < other.value; } + inline bool operator> (const Iterator& other) const { return value > other.value; } + + private: + T value; + }; + + inline Iterator begin() const { return Iterator(begin_); } + inline Iterator end() const { return Iterator(end_); } + + inline auto size() const -> decltype(instance() - instance()) { return end_ - begin_; } + +private: + T begin_; + T end_; +}; + +template +inline constexpr Range, Decay>> range(T begin, U end) { + return Range, Decay>>(begin, end); +} + +template +inline constexpr Range> range(T begin, T end) { return Range>(begin, end); } +// Returns a fake iterable container containing all values of T from `begin` (inclusive) to `end` +// (exclusive). Example: +// +// // Prints 1, 2, 3, 4, 5, 6, 7, 8, 9. +// for (int i: kj::range(1, 10)) { print(i); } + +template +inline constexpr Range> zeroTo(T end) { return Range>(end); } +// Returns a fake iterable container containing all values of T from zero (inclusive) to `end` +// (exclusive). Example: +// +// // Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. +// for (int i: kj::zeroTo(10)) { print(i); } + +template +inline constexpr Range indices(T&& container) { + // Shortcut for iterating over the indices of a container: + // + // for (size_t i: kj::indices(myArray)) { handle(myArray[i]); } + + return range(0, kj::size(container)); +} + +template +class Repeat { +public: + inline constexpr Repeat(const T& value, size_t count): value(value), count(count) {} + + class Iterator { + public: + Iterator() = default; + inline Iterator(const T& value, size_t index): value(value), index(index) {} + + inline const T& operator* () const { return value; } + inline const T& operator[](ptrdiff_t index) const { return value; } + inline Iterator& operator++() { ++index; return *this; } + inline Iterator operator++(int) { return Iterator(value, index++); } + inline Iterator& operator--() { --index; return *this; } + inline Iterator operator--(int) { return Iterator(value, index--); } + inline Iterator& operator+=(ptrdiff_t amount) { index += amount; return *this; } + inline Iterator& operator-=(ptrdiff_t amount) { index -= amount; return *this; } + inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value, index + amount); } + inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value, index - amount); } + inline ptrdiff_t operator- (const Iterator& other) const { return index - other.index; } + + inline bool operator==(const Iterator& other) const { return index == other.index; } + inline bool operator!=(const Iterator& other) const { return index != other.index; } + inline bool operator<=(const Iterator& other) const { return index <= other.index; } + inline bool operator>=(const Iterator& other) const { return index >= other.index; } + inline bool operator< (const Iterator& other) const { return index < other.index; } + inline bool operator> (const Iterator& other) const { return index > other.index; } + + private: + T value; + size_t index; + }; + + inline Iterator begin() const { return Iterator(value, 0); } + inline Iterator end() const { return Iterator(value, count); } + + inline size_t size() const { return count; } + inline const T& operator[](ptrdiff_t) const { return value; } + +private: + T value; + size_t count; +}; + +template +inline constexpr Repeat> repeat(T&& value, size_t count) { + // Returns a fake iterable which contains `count` repeats of `value`. Useful for e.g. creating + // a bunch of spaces: `kj::repeat(' ', indent * 2)` + + return Repeat>(value, count); +} + +// ======================================================================================= +// Manually invoking constructors and destructors +// +// ctor(x, ...) and dtor(x) invoke x's constructor or destructor, respectively. + +// We want placement new, but we don't want to #include . operator new cannot be defined in +// a namespace, and defining it globally conflicts with the definition in . So we have to +// define a dummy type and an operator new that uses it. + +namespace _ { // private +struct PlacementNew {}; +} // namespace _ (private) +} // namespace kj + +inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { + return __p; +} + +inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {} + +namespace kj { + +template +inline void ctor(T& location, Params&&... params) { + new (_::PlacementNew(), &location) T(kj::fwd(params)...); +} + +template +inline void dtor(T& location) { + location.~T(); +} + +// ======================================================================================= +// Maybe +// +// Use in cases where you want to indicate that a value may be null. Using Maybe instead of T* +// forces the caller to handle the null case in order to satisfy the compiler, thus reliably +// preventing null pointer dereferences at runtime. +// +// Maybe can be implicitly constructed from T and from nullptr. Additionally, it can be +// implicitly constructed from T*, in which case the pointer is checked for nullness at runtime. +// To read the value of a Maybe, do: +// +// KJ_IF_MAYBE(value, someFuncReturningMaybe()) { +// doSomething(*value); +// } else { +// maybeWasNull(); +// } +// +// KJ_IF_MAYBE's first parameter is a variable name which will be defined within the following +// block. The variable will behave like a (guaranteed non-null) pointer to the Maybe's value, +// though it may or may not actually be a pointer. +// +// Note that Maybe actually just wraps a pointer, whereas Maybe wraps a T and a boolean +// indicating nullness. + +template +class Maybe; + +namespace _ { // private + +template +class NullableValue { + // Class whose interface behaves much like T*, but actually contains an instance of T and a + // boolean flag indicating nullness. + +public: + inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) + : isSet(other.isSet) { + if (isSet) { + ctor(value, kj::mv(other.value)); + } + } + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + inline NullableValue(NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + inline ~NullableValue() +#if _MSC_VER + // TODO(msvc): MSVC has a hard time with noexcept specifier expressions that are more complex + // than `true` or `false`. We had a workaround for VS2015, but VS2017 regressed. + noexcept(false) +#else + noexcept(noexcept(instance().~T())) +#endif + { + if (isSet) { + dtor(value); + } + } + + inline T& operator*() & { return value; } + inline const T& operator*() const & { return value; } + inline T&& operator*() && { return kj::mv(value); } + inline const T&& operator*() const && { return kj::mv(value); } + inline T* operator->() { return &value; } + inline const T* operator->() const { return &value; } + inline operator T*() { return isSet ? &value : nullptr; } + inline operator const T*() const { return isSet ? &value : nullptr; } + + template + inline T& emplace(Params&&... params) { + if (isSet) { + isSet = false; + dtor(value); + } + ctor(value, kj::fwd(params)...); + isSet = true; + return value; + } + +private: // internal interface used by friends only + inline NullableValue() noexcept: isSet(false) {} + inline NullableValue(T&& t) noexcept(noexcept(T(instance()))) + : isSet(true) { + ctor(value, kj::mv(t)); + } + inline NullableValue(T& t) + : isSet(true) { + ctor(value, t); + } + inline NullableValue(const T& t) + : isSet(true) { + ctor(value, t); + } + inline NullableValue(const T* t) + : isSet(t != nullptr) { + if (isSet) ctor(value, *t); + } + template + inline NullableValue(NullableValue&& other) noexcept(noexcept(T(instance()))) + : isSet(other.isSet) { + if (isSet) { + ctor(value, kj::mv(other.value)); + } + } + template + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, other.value); + } + } + template + inline NullableValue(const NullableValue& other) + : isSet(other.isSet) { + if (isSet) { + ctor(value, *other.ptr); + } + } + inline NullableValue(decltype(nullptr)): isSet(false) {} + + inline NullableValue& operator=(NullableValue&& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, kj::mv(other.value)); + isSet = true; + } + } + return *this; + } + + inline NullableValue& operator=(NullableValue& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, other.value); + isSet = true; + } + } + return *this; + } + + inline NullableValue& operator=(const NullableValue& other) { + if (&other != this) { + // Careful about throwing destructors/constructors here. + if (isSet) { + isSet = false; + dtor(value); + } + if (other.isSet) { + ctor(value, other.value); + isSet = true; + } + } + return *this; + } + + inline bool operator==(decltype(nullptr)) const { return !isSet; } + inline bool operator!=(decltype(nullptr)) const { return isSet; } + +private: + bool isSet; + +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4624) +// Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning +// seems broken. +#endif + + union { + T value; + }; + +#if _MSC_VER +#pragma warning(pop) +#endif + + friend class kj::Maybe; + template + friend NullableValue&& readMaybe(Maybe&& maybe); +}; + +template +inline NullableValue&& readMaybe(Maybe&& maybe) { return kj::mv(maybe.ptr); } +template +inline T* readMaybe(Maybe& maybe) { return maybe.ptr; } +template +inline const T* readMaybe(const Maybe& maybe) { return maybe.ptr; } +template +inline T* readMaybe(Maybe&& maybe) { return maybe.ptr; } +template +inline T* readMaybe(const Maybe& maybe) { return maybe.ptr; } + +template +inline T* readMaybe(T* ptr) { return ptr; } +// Allow KJ_IF_MAYBE to work on regular pointers. + +} // namespace _ (private) + +#define KJ_IF_MAYBE(name, exp) if (auto name = ::kj::_::readMaybe(exp)) + +template +class Maybe { + // A T, or nullptr. + + // IF YOU CHANGE THIS CLASS: Note that there is a specialization of it in memory.h. + +public: + Maybe(): ptr(nullptr) {} + Maybe(T&& t) noexcept(noexcept(T(instance()))): ptr(kj::mv(t)) {} + Maybe(T& t): ptr(t) {} + Maybe(const T& t): ptr(t) {} + Maybe(const T* t) noexcept: ptr(t) {} + Maybe(Maybe&& other) noexcept(noexcept(T(instance()))): ptr(kj::mv(other.ptr)) {} + Maybe(const Maybe& other): ptr(other.ptr) {} + Maybe(Maybe& other): ptr(other.ptr) {} + + template + Maybe(Maybe&& other) noexcept(noexcept(T(instance()))) { + KJ_IF_MAYBE(val, kj::mv(other)) { + ptr.emplace(kj::mv(*val)); + } + } + template + Maybe(const Maybe& other) { + KJ_IF_MAYBE(val, other) { + ptr.emplace(*val); + } + } + + Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} + + template + inline T& emplace(Params&&... params) { + // Replace this Maybe's content with a new value constructed by passing the given parametrs to + // T's constructor. This can be used to initialize a Maybe without copying or even moving a T. + // Returns a reference to the newly-constructed value. + + return ptr.emplace(kj::fwd(params)...); + } + + inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } + inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; } + inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; } + + inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T& orDefault(T& defaultValue) { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + const T& orDefault(const T& defaultValue) const { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + + template + auto map(Func&& f) & -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + + template + auto map(Func&& f) const & -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + + template + auto map(Func&& f) && -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(*ptr)); + } + } + + template + auto map(Func&& f) const && -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(kj::mv(*ptr)); + } + } + +private: + _::NullableValue ptr; + + template + friend class Maybe; + template + friend _::NullableValue&& _::readMaybe(Maybe&& maybe); + template + friend U* _::readMaybe(Maybe& maybe); + template + friend const U* _::readMaybe(const Maybe& maybe); +}; + +template +class Maybe: public DisallowConstCopyIfNotConst { +public: + Maybe() noexcept: ptr(nullptr) {} + Maybe(T& t) noexcept: ptr(&t) {} + Maybe(T* t) noexcept: ptr(t) {} + + template + inline Maybe(Maybe& other) noexcept: ptr(other.ptr) {} + template + inline Maybe(const Maybe& other) noexcept: ptr(other.ptr) {} + inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} + + inline Maybe& operator=(T& other) noexcept { ptr = &other; return *this; } + inline Maybe& operator=(T* other) noexcept { ptr = other; return *this; } + template + inline Maybe& operator=(Maybe& other) noexcept { ptr = other.ptr; return *this; } + template + inline Maybe& operator=(const Maybe& other) noexcept { ptr = other.ptr; return *this; } + + inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } + inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } + + T& orDefault(T& defaultValue) { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + const T& orDefault(const T& defaultValue) const { + if (ptr == nullptr) { + return defaultValue; + } else { + return *ptr; + } + } + + template + auto map(Func&& f) -> Maybe()))> { + if (ptr == nullptr) { + return nullptr; + } else { + return f(*ptr); + } + } + +private: + T* ptr; + + template + friend class Maybe; + template + friend U* _::readMaybe(Maybe&& maybe); + template + friend U* _::readMaybe(const Maybe& maybe); +}; + +// ======================================================================================= +// ArrayPtr +// +// So common that we put it in common.h rather than array.h. + +template +class ArrayPtr: public DisallowConstCopyIfNotConst { + // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data, + // and passing by value only copies the pointer, not the target. + +public: + inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {} + inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {} + inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {} + inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {} + inline KJ_CONSTEXPR() ArrayPtr(::std::initializer_list> init) + : ptr(init.begin()), size_(init.size()) {} + + template + inline constexpr ArrayPtr(T (&native)[size]): ptr(native), size_(size) {} + // Construct an ArrayPtr from a native C-style array. + + inline operator ArrayPtr() const { + return ArrayPtr(ptr, size_); + } + inline ArrayPtr asConst() const { + return ArrayPtr(ptr, size_); + } + + inline size_t size() const { return size_; } + inline const T& operator[](size_t index) const { + KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); + return ptr[index]; + } + inline T& operator[](size_t index) { + KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); + return ptr[index]; + } + + inline T* begin() { return ptr; } + inline T* end() { return ptr + size_; } + inline T& front() { return *ptr; } + inline T& back() { return *(ptr + size_ - 1); } + inline const T* begin() const { return ptr; } + inline const T* end() const { return ptr + size_; } + inline const T& front() const { return *ptr; } + inline const T& back() const { return *(ptr + size_ - 1); } + + inline ArrayPtr slice(size_t start, size_t end) const { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); + return ArrayPtr(ptr + start, end - start); + } + inline ArrayPtr slice(size_t start, size_t end) { + KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); + return ArrayPtr(ptr + start, end - start); + } + + inline ArrayPtr> asBytes() const { + // Reinterpret the array as a byte array. This is explicitly legal under C++ aliasing + // rules. + return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; + } + inline ArrayPtr> asChars() const { + // Reinterpret the array as a char array. This is explicitly legal under C++ aliasing + // rules. + return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; + } + + inline bool operator==(decltype(nullptr)) const { return size_ == 0; } + inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } + + inline bool operator==(const ArrayPtr& other) const { + if (size_ != other.size_) return false; + for (size_t i = 0; i < size_; i++) { + if (ptr[i] != other[i]) return false; + } + return true; + } + inline bool operator!=(const ArrayPtr& other) const { return !(*this == other); } + +private: + T* ptr; + size_t size_; +}; + +template +inline constexpr ArrayPtr arrayPtr(T* ptr, size_t size) { + // Use this function to construct ArrayPtrs without writing out the type name. + return ArrayPtr(ptr, size); +} + +template +inline constexpr ArrayPtr arrayPtr(T* begin, T* end) { + // Use this function to construct ArrayPtrs without writing out the type name. + return ArrayPtr(begin, end); +} + +// ======================================================================================= +// Casts + +template +To implicitCast(From&& from) { + // `implicitCast(value)` casts `value` to type `T` only if the conversion is implicit. Useful + // for e.g. resolving ambiguous overloads without sacrificing type-safety. + return kj::fwd(from); +} + +template +Maybe dynamicDowncastIfAvailable(From& from) { + // If RTTI is disabled, always returns nullptr. Otherwise, works like dynamic_cast. Useful + // in situations where dynamic_cast could allow an optimization, but isn't strictly necessary + // for correctness. It is highly recommended that you try to arrange all your dynamic_casts + // this way, as a dynamic_cast that is necessary for correctness implies a flaw in the interface + // design. + + // Force a compile error if To is not a subtype of From. Cross-casting is rare; if it is needed + // we should have a separate cast function like dynamicCrosscastIfAvailable(). + if (false) { + kj::implicitCast(kj::implicitCast(nullptr)); + } + +#if KJ_NO_RTTI + return nullptr; +#else + return dynamic_cast(&from); +#endif +} + +template +To& downcast(From& from) { + // Down-cast a value to a sub-type, asserting that the cast is valid. In opt mode this is a + // static_cast, but in debug mode (when RTTI is enabled) a dynamic_cast will be used to verify + // that the value really has the requested type. + + // Force a compile error if To is not a subtype of From. + if (false) { + kj::implicitCast(kj::implicitCast(nullptr)); + } + +#if !KJ_NO_RTTI + KJ_IREQUIRE(dynamic_cast(&from) != nullptr, "Value cannot be downcast() to requested type."); +#endif + + return static_cast(from); +} + +// ======================================================================================= +// Defer + +namespace _ { // private + +template +class Deferred { +public: + inline Deferred(Func&& func): func(kj::fwd(func)), canceled(false) {} + inline ~Deferred() noexcept(false) { if (!canceled) func(); } + KJ_DISALLOW_COPY(Deferred); + + // This move constructor is usually optimized away by the compiler. + inline Deferred(Deferred&& other): func(kj::mv(other.func)), canceled(false) { + other.canceled = true; + } +private: + Func func; + bool canceled; +}; + +} // namespace _ (private) + +template +_::Deferred defer(Func&& func) { + // Returns an object which will invoke the given functor in its destructor. The object is not + // copyable but is movable with the semantics you'd expect. Since the return type is private, + // you need to assign to an `auto` variable. + // + // The KJ_DEFER macro provides slightly more convenient syntax for the common case where you + // want some code to run at current scope exit. + + return _::Deferred(kj::fwd(func)); +} + +#define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::defer([&](){code;}) +// Run the given code when the function exits, whether by return or exception. + +} // namespace kj + +#endif // KJ_COMMON_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/compat/gtest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/compat/gtest.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,122 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_COMPAT_GTEST_H_ +#define KJ_COMPAT_GTEST_H_ +// This file defines compatibility macros converting Google Test tests into KJ tests. +// +// This is only intended to cover the most common functionality. Many tests will likely need +// additional tweaks. For instance: +// - Using operator<< to print information on failure is not supported. Instead, switch to +// KJ_ASSERT/KJ_EXPECT and pass in stuff to print as additional parameters. +// - Test fixtures are not supported. Allocate your "test fixture" on the stack instead. Do setup +// in the constructor, teardown in the destructor. + +#include "../test.h" + +namespace kj { + +namespace _ { // private + +template +T abs(T value) { return value < 0 ? -value : value; } + +inline bool floatAlmostEqual(float a, float b) { + return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-5; +} + +inline bool doubleAlmostEqual(double a, double b) { + return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-12; +} + +} // namespace _ (private) + +#define EXPECT_FALSE(x) KJ_EXPECT(!(x)) +#define EXPECT_TRUE(x) KJ_EXPECT(x) +#define EXPECT_EQ(x, y) KJ_EXPECT((x) == (y), x, y) +#define EXPECT_NE(x, y) KJ_EXPECT((x) != (y), x, y) +#define EXPECT_LE(x, y) KJ_EXPECT((x) <= (y), x, y) +#define EXPECT_GE(x, y) KJ_EXPECT((x) >= (y), x, y) +#define EXPECT_LT(x, y) KJ_EXPECT((x) < (y), x, y) +#define EXPECT_GT(x, y) KJ_EXPECT((x) > (y), x, y) +#define EXPECT_STREQ(x, y) KJ_EXPECT(::strcmp(x, y) == 0, x, y) +#define EXPECT_FLOAT_EQ(x, y) KJ_EXPECT(::kj::_::floatAlmostEqual(y, x), y, x); +#define EXPECT_DOUBLE_EQ(x, y) KJ_EXPECT(::kj::_::doubleAlmostEqual(y, x), y, x); + +#define ASSERT_FALSE(x) KJ_ASSERT(!(x)) +#define ASSERT_TRUE(x) KJ_ASSERT(x) +#define ASSERT_EQ(x, y) KJ_ASSERT((x) == (y), x, y) +#define ASSERT_NE(x, y) KJ_ASSERT((x) != (y), x, y) +#define ASSERT_LE(x, y) KJ_ASSERT((x) <= (y), x, y) +#define ASSERT_GE(x, y) KJ_ASSERT((x) >= (y), x, y) +#define ASSERT_LT(x, y) KJ_ASSERT((x) < (y), x, y) +#define ASSERT_GT(x, y) KJ_ASSERT((x) > (y), x, y) +#define ASSERT_STREQ(x, y) KJ_ASSERT(::strcmp(x, y) == 0, x, y) +#define ASSERT_FLOAT_EQ(x, y) KJ_ASSERT(::kj::_::floatAlmostEqual(y, x), y, x); +#define ASSERT_DOUBLE_EQ(x, y) KJ_ASSERT(::kj::_::doubleAlmostEqual(y, x), y, x); + +class AddFailureAdapter { +public: + AddFailureAdapter(const char* file, int line): file(file), line(line) {} + + ~AddFailureAdapter() { + if (!handled) { + _::Debug::log(file, line, LogSeverity::ERROR, "expectation failed"); + } + } + + template + void operator<<(T&& info) { + handled = true; + _::Debug::log(file, line, LogSeverity::ERROR, "\"expectation failed\", info", + "expectation failed", kj::fwd(info)); + } + +private: + bool handled = false; + const char* file; + int line; +}; + +#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__) + +#if KJ_NO_EXCEPTIONS +#define EXPECT_ANY_THROW(code) \ + KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, nullptr, [&]() { code; })) +#else +#define EXPECT_ANY_THROW(code) \ + KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr) +#endif + +#define EXPECT_NONFATAL_FAILURE(code) \ + EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr); + +#ifdef KJ_DEBUG +#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW +#else +#define EXPECT_DEBUG_ANY_THROW(EXP) +#endif + +#define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y) + +} // namespace kj + +#endif // KJ_COMPAT_GTEST_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/compat/http-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/compat/http-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1370 @@ +// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "http.h" +#include +#include +#include + +namespace kj { +namespace { + +KJ_TEST("HttpMethod parse / stringify") { +#define TRY(name) \ + KJ_EXPECT(kj::str(HttpMethod::name) == #name); \ + KJ_IF_MAYBE(parsed, tryParseHttpMethod(#name)) { \ + KJ_EXPECT(*parsed == HttpMethod::name); \ + } else { \ + KJ_FAIL_EXPECT("couldn't parse \"" #name "\" as HttpMethod"); \ + } + + KJ_HTTP_FOR_EACH_METHOD(TRY) +#undef TRY + + KJ_EXPECT(tryParseHttpMethod("FOO") == nullptr); + KJ_EXPECT(tryParseHttpMethod("") == nullptr); + KJ_EXPECT(tryParseHttpMethod("G") == nullptr); + KJ_EXPECT(tryParseHttpMethod("GE") == nullptr); + KJ_EXPECT(tryParseHttpMethod("GET ") == nullptr); + KJ_EXPECT(tryParseHttpMethod("get") == nullptr); +} + +KJ_TEST("HttpHeaderTable") { + HttpHeaderTable::Builder builder; + + auto host = builder.add("Host"); + auto host2 = builder.add("hOsT"); + auto fooBar = builder.add("Foo-Bar"); + auto bazQux = builder.add("baz-qux"); + auto bazQux2 = builder.add("Baz-Qux"); + + auto table = builder.build(); + + uint builtinHeaderCount = 0; +#define INCREMENT(id, name) ++builtinHeaderCount; + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(INCREMENT) +#undef INCREMENT + + KJ_EXPECT(table->idCount() == builtinHeaderCount + 2); + + KJ_EXPECT(host == HttpHeaderId::HOST); + KJ_EXPECT(host != HttpHeaderId::DATE); + KJ_EXPECT(host2 == host); + + KJ_EXPECT(host != fooBar); + KJ_EXPECT(host != bazQux); + KJ_EXPECT(fooBar != bazQux); + KJ_EXPECT(bazQux == bazQux2); + + KJ_EXPECT(kj::str(host) == "Host"); + KJ_EXPECT(kj::str(host2) == "Host"); + KJ_EXPECT(kj::str(fooBar) == "Foo-Bar"); + KJ_EXPECT(kj::str(bazQux) == "baz-qux"); + KJ_EXPECT(kj::str(HttpHeaderId::HOST) == "Host"); + + KJ_EXPECT(table->idToString(HttpHeaderId::DATE) == "Date"); + KJ_EXPECT(table->idToString(fooBar) == "Foo-Bar"); + + KJ_EXPECT(KJ_ASSERT_NONNULL(table->stringToId("Date")) == HttpHeaderId::DATE); + KJ_EXPECT(KJ_ASSERT_NONNULL(table->stringToId("dATE")) == HttpHeaderId::DATE); + KJ_EXPECT(KJ_ASSERT_NONNULL(table->stringToId("Foo-Bar")) == fooBar); + KJ_EXPECT(KJ_ASSERT_NONNULL(table->stringToId("foo-BAR")) == fooBar); + KJ_EXPECT(table->stringToId("foobar") == nullptr); + KJ_EXPECT(table->stringToId("barfoo") == nullptr); +} + +KJ_TEST("HttpHeaders::parseRequest") { + HttpHeaderTable::Builder builder; + + auto fooBar = builder.add("Foo-Bar"); + auto bazQux = builder.add("baz-qux"); + + auto table = builder.build(); + + HttpHeaders headers(*table); + auto text = kj::heapString( + "POST /some/path \t HTTP/1.1\r\n" + "Foo-BaR: Baz\r\n" + "Host: example.com\r\n" + "Content-Length: 123\r\n" + "DATE: early\r\n" + "other-Header: yep\r\n" + "\r\n"); + auto result = KJ_ASSERT_NONNULL(headers.tryParseRequest(text.asArray())); + + KJ_EXPECT(result.method == HttpMethod::POST); + KJ_EXPECT(result.url == "/some/path"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(HttpHeaderId::HOST)) == "example.com"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(HttpHeaderId::DATE)) == "early"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(fooBar)) == "Baz"); + KJ_EXPECT(headers.get(bazQux) == nullptr); + KJ_EXPECT(headers.get(HttpHeaderId::CONTENT_TYPE) == nullptr); + KJ_EXPECT(result.connectionHeaders.contentLength == "123"); + KJ_EXPECT(result.connectionHeaders.transferEncoding == nullptr); + + std::map unpackedHeaders; + headers.forEach([&](kj::StringPtr name, kj::StringPtr value) { + KJ_EXPECT(unpackedHeaders.insert(std::make_pair(name, value)).second); + }); + KJ_EXPECT(unpackedHeaders.size() == 4); + KJ_EXPECT(unpackedHeaders["Host"] == "example.com"); + KJ_EXPECT(unpackedHeaders["Date"] == "early"); + KJ_EXPECT(unpackedHeaders["Foo-Bar"] == "Baz"); + KJ_EXPECT(unpackedHeaders["other-Header"] == "yep"); + + KJ_EXPECT(headers.serializeRequest(result.method, result.url, result.connectionHeaders) == + "POST /some/path HTTP/1.1\r\n" + "Content-Length: 123\r\n" + "Host: example.com\r\n" + "Date: early\r\n" + "Foo-Bar: Baz\r\n" + "other-Header: yep\r\n" + "\r\n"); +} + +KJ_TEST("HttpHeaders::parseResponse") { + HttpHeaderTable::Builder builder; + + auto fooBar = builder.add("Foo-Bar"); + auto bazQux = builder.add("baz-qux"); + + auto table = builder.build(); + + HttpHeaders headers(*table); + auto text = kj::heapString( + "HTTP/1.1\t\t 418\t I'm a teapot\r\n" + "Foo-BaR: Baz\r\n" + "Host: example.com\r\n" + "Content-Length: 123\r\n" + "DATE: early\r\n" + "other-Header: yep\r\n" + "\r\n"); + auto result = KJ_ASSERT_NONNULL(headers.tryParseResponse(text.asArray())); + + KJ_EXPECT(result.statusCode == 418); + KJ_EXPECT(result.statusText == "I'm a teapot"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(HttpHeaderId::HOST)) == "example.com"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(HttpHeaderId::DATE)) == "early"); + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(fooBar)) == "Baz"); + KJ_EXPECT(headers.get(bazQux) == nullptr); + KJ_EXPECT(headers.get(HttpHeaderId::CONTENT_TYPE) == nullptr); + KJ_EXPECT(result.connectionHeaders.contentLength == "123"); + KJ_EXPECT(result.connectionHeaders.transferEncoding == nullptr); + + std::map unpackedHeaders; + headers.forEach([&](kj::StringPtr name, kj::StringPtr value) { + KJ_EXPECT(unpackedHeaders.insert(std::make_pair(name, value)).second); + }); + KJ_EXPECT(unpackedHeaders.size() == 4); + KJ_EXPECT(unpackedHeaders["Host"] == "example.com"); + KJ_EXPECT(unpackedHeaders["Date"] == "early"); + KJ_EXPECT(unpackedHeaders["Foo-Bar"] == "Baz"); + KJ_EXPECT(unpackedHeaders["other-Header"] == "yep"); + + KJ_EXPECT(headers.serializeResponse( + result.statusCode, result.statusText, result.connectionHeaders) == + "HTTP/1.1 418 I'm a teapot\r\n" + "Content-Length: 123\r\n" + "Host: example.com\r\n" + "Date: early\r\n" + "Foo-Bar: Baz\r\n" + "other-Header: yep\r\n" + "\r\n"); +} + +KJ_TEST("HttpHeaders parse invalid") { + auto table = HttpHeaderTable::Builder().build(); + HttpHeaders headers(*table); + + // NUL byte in request. + KJ_EXPECT(headers.tryParseRequest(kj::heapString( + "POST \0 /some/path \t HTTP/1.1\r\n" + "Foo-BaR: Baz\r\n" + "Host: example.com\r\n" + "DATE: early\r\n" + "other-Header: yep\r\n" + "\r\n")) == nullptr); + + // Control character in header name. + KJ_EXPECT(headers.tryParseRequest(kj::heapString( + "POST /some/path \t HTTP/1.1\r\n" + "Foo-BaR: Baz\r\n" + "Cont\001ent-Length: 123\r\n" + "DATE: early\r\n" + "other-Header: yep\r\n" + "\r\n")) == nullptr); + + // Separator character in header name. + KJ_EXPECT(headers.tryParseRequest(kj::heapString( + "POST /some/path \t HTTP/1.1\r\n" + "Foo-BaR: Baz\r\n" + "Host: example.com\r\n" + "DATE/: early\r\n" + "other-Header: yep\r\n" + "\r\n")) == nullptr); + + // Response status code not numeric. + KJ_EXPECT(headers.tryParseResponse(kj::heapString( + "HTTP/1.1\t\t abc\t I'm a teapot\r\n" + "Foo-BaR: Baz\r\n" + "Host: example.com\r\n" + "DATE: early\r\n" + "other-Header: yep\r\n" + "\r\n")) == nullptr); +} + +// ======================================================================================= + +class ReadFragmenter final: public kj::AsyncIoStream { +public: + ReadFragmenter(AsyncIoStream& inner, size_t limit): inner(inner), limit(limit) {} + + Promise read(void* buffer, size_t minBytes, size_t maxBytes) override { + return inner.read(buffer, minBytes, kj::max(minBytes, kj::min(limit, maxBytes))); + } + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + return inner.tryRead(buffer, minBytes, kj::max(minBytes, kj::min(limit, maxBytes))); + } + + Maybe tryGetLength() override { return inner.tryGetLength(); } + + Promise pumpTo(AsyncOutputStream& output, uint64_t amount) override { + return inner.pumpTo(output, amount); + } + + Promise write(const void* buffer, size_t size) override { + return inner.write(buffer, size); + } + Promise write(ArrayPtr> pieces) override { + return inner.write(pieces); + } + + Maybe> tryPumpFrom(AsyncInputStream& input, uint64_t amount) override { + return inner.tryPumpFrom(input, amount); + } + + void shutdownWrite() override { + return inner.shutdownWrite(); + } + + void abortRead() override { return inner.abortRead(); } + + void getsockopt(int level, int option, void* value, uint* length) override { + return inner.getsockopt(level, option, value, length); + } + void setsockopt(int level, int option, const void* value, uint length) override { + return inner.setsockopt(level, option, value, length); + } + + void getsockname(struct sockaddr* addr, uint* length) override { + return inner.getsockname(addr, length); + } + void getpeername(struct sockaddr* addr, uint* length) override { + return inner.getsockname(addr, length); + } + +private: + kj::AsyncIoStream& inner; + size_t limit; +}; + +template +class InitializeableArray: public Array { +public: + InitializeableArray(std::initializer_list init) + : Array(kj::heapArray(init)) {} +}; + +enum Side { BOTH, CLIENT_ONLY, SERVER_ONLY }; + +struct HeaderTestCase { + HttpHeaderId id; + kj::StringPtr value; +}; + +struct HttpRequestTestCase { + kj::StringPtr raw; + + HttpMethod method; + kj::StringPtr path; + InitializeableArray requestHeaders; + kj::Maybe requestBodySize; + InitializeableArray requestBodyParts; + + Side side = BOTH; + + // TODO(cleanup): Delete this constructor if/when we move to C++14. + HttpRequestTestCase(kj::StringPtr raw, HttpMethod method, kj::StringPtr path, + InitializeableArray requestHeaders, + kj::Maybe requestBodySize, + InitializeableArray requestBodyParts, + Side side = BOTH) + : raw(raw), method(method), path(path), requestHeaders(kj::mv(requestHeaders)), + requestBodySize(requestBodySize), requestBodyParts(kj::mv(requestBodyParts)), + side(side) {} +}; + +struct HttpResponseTestCase { + kj::StringPtr raw; + + uint64_t statusCode; + kj::StringPtr statusText; + InitializeableArray responseHeaders; + kj::Maybe responseBodySize; + InitializeableArray responseBodyParts; + + HttpMethod method = HttpMethod::GET; + + Side side = BOTH; + + // TODO(cleanup): Delete this constructor if/when we move to C++14. + HttpResponseTestCase(kj::StringPtr raw, uint64_t statusCode, kj::StringPtr statusText, + InitializeableArray responseHeaders, + kj::Maybe responseBodySize, + InitializeableArray responseBodyParts, + HttpMethod method = HttpMethod::GET, + Side side = BOTH) + : raw(raw), statusCode(statusCode), statusText(statusText), + responseHeaders(kj::mv(responseHeaders)), responseBodySize(responseBodySize), + responseBodyParts(kj::mv(responseBodyParts)), method(method), side(side) {} +}; + +struct HttpTestCase { + HttpRequestTestCase request; + HttpResponseTestCase response; +}; + +kj::Promise writeEach(kj::AsyncOutputStream& out, kj::ArrayPtr parts) { + if (parts.size() == 0) return kj::READY_NOW; + + return out.write(parts[0].begin(), parts[0].size()) + .then([&out,parts]() { + return writeEach(out, parts.slice(1, parts.size())); + }); +} + +kj::Promise expectRead(kj::AsyncInputStream& in, kj::StringPtr expected) { + if (expected.size() == 0) return kj::READY_NOW; + + auto buffer = kj::heapArray(expected.size()); + + auto promise = in.tryRead(buffer.begin(), 1, buffer.size()); + return promise.then(kj::mvCapture(buffer, [&in,expected](kj::Array buffer, size_t amount) { + if (amount == 0) { + KJ_FAIL_ASSERT("expected data never sent", expected); + } + + auto actual = buffer.slice(0, amount); + if (memcmp(actual.begin(), expected.begin(), actual.size()) != 0) { + KJ_FAIL_ASSERT("data from stream doesn't match expected", expected, actual); + } + + return expectRead(in, expected.slice(amount)); + })); +} + +void testHttpClientRequest(kj::AsyncIoContext& io, const HttpRequestTestCase& testCase) { + auto pipe = io.provider->newTwoWayPipe(); + + auto serverTask = expectRead(*pipe.ends[1], testCase.raw).then([&]() { + static const char SIMPLE_RESPONSE[] = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "\r\n"; + return pipe.ends[1]->write(SIMPLE_RESPONSE, strlen(SIMPLE_RESPONSE)); + }).then([&]() -> kj::Promise { + return kj::NEVER_DONE; + }); + + HttpHeaderTable table; + auto client = newHttpClient(table, *pipe.ends[0]); + + HttpHeaders headers(table); + for (auto& header: testCase.requestHeaders) { + headers.set(header.id, header.value); + } + + auto request = client->request(testCase.method, testCase.path, headers, testCase.requestBodySize); + if (testCase.requestBodyParts.size() > 0) { + writeEach(*request.body, testCase.requestBodyParts).wait(io.waitScope); + } + request.body = nullptr; + auto clientTask = request.response + .then([&](HttpClient::Response&& response) { + auto promise = response.body->readAllText(); + return promise.attach(kj::mv(response.body)); + }).ignoreResult(); + + serverTask.exclusiveJoin(kj::mv(clientTask)).wait(io.waitScope); + + // Verify no more data written by client. + client = nullptr; + pipe.ends[0]->shutdownWrite(); + KJ_EXPECT(pipe.ends[1]->readAllText().wait(io.waitScope) == ""); +} + +void testHttpClientResponse(kj::AsyncIoContext& io, const HttpResponseTestCase& testCase, + size_t readFragmentSize) { + auto pipe = io.provider->newTwoWayPipe(); + ReadFragmenter fragmenter(*pipe.ends[0], readFragmentSize); + + auto expectedReqText = testCase.method == HttpMethod::GET || testCase.method == HttpMethod::HEAD + ? kj::str(testCase.method, " / HTTP/1.1\r\n\r\n") + : kj::str(testCase.method, " / HTTP/1.1\r\nContent-Length: 0\r\n"); + + auto serverTask = expectRead(*pipe.ends[1], expectedReqText).then([&]() { + return pipe.ends[1]->write(testCase.raw.begin(), testCase.raw.size()); + }).then([&]() -> kj::Promise { + pipe.ends[1]->shutdownWrite(); + return kj::NEVER_DONE; + }); + + HttpHeaderTable table; + auto client = newHttpClient(table, fragmenter); + + HttpHeaders headers(table); + auto request = client->request(testCase.method, "/", headers, uint64_t(0)); + request.body = nullptr; + auto clientTask = request.response + .then([&](HttpClient::Response&& response) { + KJ_EXPECT(response.statusCode == testCase.statusCode); + KJ_EXPECT(response.statusText == testCase.statusText); + + for (auto& header: testCase.responseHeaders) { + KJ_EXPECT(KJ_ASSERT_NONNULL(response.headers->get(header.id)) == header.value); + } + auto promise = response.body->readAllText(); + return promise.attach(kj::mv(response.body)); + }).then([&](kj::String body) { + KJ_EXPECT(body == kj::strArray(testCase.responseBodyParts, ""), body); + }); + + serverTask.exclusiveJoin(kj::mv(clientTask)).wait(io.waitScope); + + // Verify no more data written by client. + client = nullptr; + pipe.ends[0]->shutdownWrite(); + KJ_EXPECT(pipe.ends[1]->readAllText().wait(io.waitScope) == ""); +} + +class TestHttpService final: public HttpService { +public: + TestHttpService(const HttpRequestTestCase& expectedRequest, + const HttpResponseTestCase& response, + HttpHeaderTable& table) + : singleExpectedRequest(&expectedRequest), + singleResponse(&response), + responseHeaders(table) {} + TestHttpService(kj::ArrayPtr testCases, + HttpHeaderTable& table) + : singleExpectedRequest(nullptr), + singleResponse(nullptr), + testCases(testCases), + responseHeaders(table) {} + + uint getRequestCount() { return requestCount; } + + kj::Promise request( + HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::AsyncInputStream& requestBody, Response& responseSender) override { + auto& expectedRequest = testCases == nullptr ? *singleExpectedRequest : + testCases[requestCount % testCases.size()].request; + auto& response = testCases == nullptr ? *singleResponse : + testCases[requestCount % testCases.size()].response; + + ++requestCount; + + KJ_EXPECT(method == expectedRequest.method, method); + KJ_EXPECT(url == expectedRequest.path, url); + + for (auto& header: expectedRequest.requestHeaders) { + KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(header.id)) == header.value); + } + + auto size = requestBody.tryGetLength(); + KJ_IF_MAYBE(expectedSize, expectedRequest.requestBodySize) { + KJ_IF_MAYBE(s, size) { + KJ_EXPECT(*s == *expectedSize, *s); + } else { + KJ_FAIL_EXPECT("tryGetLength() returned nullptr; expected known size"); + } + } else { + KJ_EXPECT(size == nullptr); + } + + return requestBody.readAllText() + .then([this,&expectedRequest,&response,&responseSender](kj::String text) { + KJ_EXPECT(text == kj::strArray(expectedRequest.requestBodyParts, ""), text); + + responseHeaders.clear(); + for (auto& header: response.responseHeaders) { + responseHeaders.set(header.id, header.value); + } + + auto stream = responseSender.send(response.statusCode, response.statusText, + responseHeaders, response.responseBodySize); + auto promise = writeEach(*stream, response.responseBodyParts); + return promise.attach(kj::mv(stream)); + }); + } + +private: + const HttpRequestTestCase* singleExpectedRequest; + const HttpResponseTestCase* singleResponse; + kj::ArrayPtr testCases; + HttpHeaders responseHeaders; + uint requestCount = 0; +}; + +void testHttpServerRequest(kj::AsyncIoContext& io, + const HttpRequestTestCase& requestCase, + const HttpResponseTestCase& responseCase) { + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + TestHttpService service(requestCase, responseCase, table); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + pipe.ends[1]->write(requestCase.raw.begin(), requestCase.raw.size()).wait(io.waitScope); + pipe.ends[1]->shutdownWrite(); + + expectRead(*pipe.ends[1], responseCase.raw).wait(io.waitScope); + + listenTask.wait(io.waitScope); + + KJ_EXPECT(service.getRequestCount() == 1); +} + +kj::ArrayPtr requestTestCases() { + static const auto HUGE_STRING = kj::strArray(kj::repeat("abcdefgh", 4096), ""); + static const auto HUGE_REQUEST = kj::str( + "GET / HTTP/1.1\r\n" + "Host: ", HUGE_STRING, "\r\n" + "\r\n"); + + static const HttpRequestTestCase REQUEST_TEST_CASES[] { + { + "GET /foo/bar HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + + HttpMethod::GET, + "/foo/bar", + {{HttpHeaderId::HOST, "example.com"}}, + nullptr, {}, + }, + + { + "HEAD /foo/bar HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + + HttpMethod::HEAD, + "/foo/bar", + {{HttpHeaderId::HOST, "example.com"}}, + nullptr, {}, + }, + + { + "POST / HTTP/1.1\r\n" + "Content-Length: 9\r\n" + "Host: example.com\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "foobarbaz", + + HttpMethod::POST, + "/", + { + {HttpHeaderId::HOST, "example.com"}, + {HttpHeaderId::CONTENT_TYPE, "text/plain"}, + }, + 9, { "foo", "bar", "baz" }, + }, + + { + "POST / HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "Host: example.com\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "3\r\n" + "foo\r\n" + "6\r\n" + "barbaz\r\n" + "0\r\n" + "\r\n", + + HttpMethod::POST, + "/", + { + {HttpHeaderId::HOST, "example.com"}, + {HttpHeaderId::CONTENT_TYPE, "text/plain"}, + }, + nullptr, { "foo", "barbaz" }, + }, + + { + "POST / HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "Host: example.com\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "1d\r\n" + "0123456789abcdef0123456789abc\r\n" + "0\r\n" + "\r\n", + + HttpMethod::POST, + "/", + { + {HttpHeaderId::HOST, "example.com"}, + {HttpHeaderId::CONTENT_TYPE, "text/plain"}, + }, + nullptr, { "0123456789abcdef0123456789abc" }, + }, + + { + HUGE_REQUEST, + + HttpMethod::GET, + "/", + {{HttpHeaderId::HOST, HUGE_STRING}}, + nullptr, {} + }, + }; + + // TODO(cleanup): A bug in GCC 4.8, fixed in 4.9, prevents REQUEST_TEST_CASES from implicitly + // casting to our return type. + return kj::arrayPtr(REQUEST_TEST_CASES, kj::size(REQUEST_TEST_CASES)); +} + +kj::ArrayPtr responseTestCases() { + static const HttpResponseTestCase RESPONSE_TEST_CASES[] { + { + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n" + "\r\n" + "baz qux", + + 200, "OK", + {{HttpHeaderId::CONTENT_TYPE, "text/plain"}}, + nullptr, {"baz qux"}, + + HttpMethod::GET, + CLIENT_ONLY, // Server never sends connection: close + }, + + { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 123\r\n" + "Content-Type: text/plain\r\n" + "\r\n", + + 200, "OK", + {{HttpHeaderId::CONTENT_TYPE, "text/plain"}}, + 123, {}, + + HttpMethod::HEAD, + }, + + { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 8\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "quxcorge", + + 200, "OK", + {{HttpHeaderId::CONTENT_TYPE, "text/plain"}}, + 8, { "qux", "corge" } + }, + + { + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "3\r\n" + "qux\r\n" + "5\r\n" + "corge\r\n" + "0\r\n" + "\r\n", + + 200, "OK", + {{HttpHeaderId::CONTENT_TYPE, "text/plain"}}, + nullptr, { "qux", "corge" } + }, + }; + + // TODO(cleanup): A bug in GCC 4.8, fixed in 4.9, prevents RESPONSE_TEST_CASES from implicitly + // casting to our return type. + return kj::arrayPtr(RESPONSE_TEST_CASES, kj::size(RESPONSE_TEST_CASES)); +} + +KJ_TEST("HttpClient requests") { + auto io = kj::setupAsyncIo(); + + for (auto& testCase: requestTestCases()) { + if (testCase.side == SERVER_ONLY) continue; + KJ_CONTEXT(testCase.raw); + testHttpClientRequest(io, testCase); + } +} + +KJ_TEST("HttpClient responses") { + auto io = kj::setupAsyncIo(); + size_t FRAGMENT_SIZES[] = { 1, 2, 3, 4, 5, 6, 7, 8, 16, 31, kj::maxValue }; + + for (auto& testCase: responseTestCases()) { + if (testCase.side == SERVER_ONLY) continue; + for (size_t fragmentSize: FRAGMENT_SIZES) { + KJ_CONTEXT(testCase.raw, fragmentSize); + testHttpClientResponse(io, testCase, fragmentSize); + } + } +} + +KJ_TEST("HttpServer requests") { + HttpResponseTestCase RESPONSE = { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 3\r\n" + "\r\n" + "foo", + + 200, "OK", + {}, + 3, {"foo"} + }; + + HttpResponseTestCase HEAD_RESPONSE = { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 3\r\n" + "\r\n", + + 200, "OK", + {}, + 3, {"foo"} + }; + + auto io = kj::setupAsyncIo(); + + for (auto& testCase: requestTestCases()) { + if (testCase.side == CLIENT_ONLY) continue; + KJ_CONTEXT(testCase.raw); + testHttpServerRequest(io, testCase, + testCase.method == HttpMethod::HEAD ? HEAD_RESPONSE : RESPONSE); + } +} + +KJ_TEST("HttpServer responses") { + HttpRequestTestCase REQUEST = { + "GET / HTTP/1.1\r\n" + "\r\n", + + HttpMethod::GET, + "/", + {}, + nullptr, {}, + }; + + HttpRequestTestCase HEAD_REQUEST = { + "HEAD / HTTP/1.1\r\n" + "\r\n", + + HttpMethod::HEAD, + "/", + {}, + nullptr, {}, + }; + + auto io = kj::setupAsyncIo(); + + for (auto& testCase: responseTestCases()) { + if (testCase.side == CLIENT_ONLY) continue; + KJ_CONTEXT(testCase.raw); + testHttpServerRequest(io, + testCase.method == HttpMethod::HEAD ? HEAD_REQUEST : REQUEST, testCase); + } +} + +// ----------------------------------------------------------------------------- + +kj::ArrayPtr pipelineTestCases() { + static const HttpTestCase PIPELINE_TESTS[] = { + { + { + "GET / HTTP/1.1\r\n" + "\r\n", + + HttpMethod::GET, "/", {}, nullptr, {}, + }, + { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 7\r\n" + "\r\n" + "foo bar", + + 200, "OK", {}, 7, { "foo bar" } + }, + }, + + { + { + "POST /foo HTTP/1.1\r\n" + "Content-Length: 6\r\n" + "\r\n" + "grault", + + HttpMethod::POST, "/foo", {}, 6, { "grault" }, + }, + { + "HTTP/1.1 404 Not Found\r\n" + "Content-Length: 13\r\n" + "\r\n" + "baz qux corge", + + 404, "Not Found", {}, 13, { "baz qux corge" } + }, + }, + + { + { + "POST /bar HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "6\r\n" + "garply\r\n" + "5\r\n" + "waldo\r\n" + "0\r\n" + "\r\n", + + HttpMethod::POST, "/bar", {}, nullptr, { "garply", "waldo" }, + }, + { + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "4\r\n" + "fred\r\n" + "5\r\n" + "plugh\r\n" + "0\r\n" + "\r\n", + + 200, "OK", {}, nullptr, { "fred", "plugh" } + }, + }, + + { + { + "HEAD / HTTP/1.1\r\n" + "\r\n", + + HttpMethod::HEAD, "/", {}, nullptr, {}, + }, + { + "HTTP/1.1 200 OK\r\n" + "Content-Length: 7\r\n" + "\r\n", + + 200, "OK", {}, 7, { "foo bar" } + }, + }, + }; + + // TODO(cleanup): A bug in GCC 4.8, fixed in 4.9, prevents RESPONSE_TEST_CASES from implicitly + // casting to our return type. + return kj::arrayPtr(PIPELINE_TESTS, kj::size(PIPELINE_TESTS)); +} + +KJ_TEST("HttpClient pipeline") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + kj::Promise writeResponsesPromise = kj::READY_NOW; + for (auto& testCase: PIPELINE_TESTS) { + writeResponsesPromise = writeResponsesPromise + .then([&]() { + return expectRead(*pipe.ends[1], testCase.request.raw); + }).then([&]() { + return pipe.ends[1]->write(testCase.response.raw.begin(), testCase.response.raw.size()); + }); + } + + HttpHeaderTable table; + auto client = newHttpClient(table, *pipe.ends[0]); + + for (auto& testCase: PIPELINE_TESTS) { + KJ_CONTEXT(testCase.request.raw, testCase.response.raw); + + HttpHeaders headers(table); + for (auto& header: testCase.request.requestHeaders) { + headers.set(header.id, header.value); + } + + auto request = client->request( + testCase.request.method, testCase.request.path, headers, testCase.request.requestBodySize); + for (auto& part: testCase.request.requestBodyParts) { + request.body->write(part.begin(), part.size()).wait(io.waitScope); + } + request.body = nullptr; + + auto response = request.response.wait(io.waitScope); + + KJ_EXPECT(response.statusCode == testCase.response.statusCode); + auto body = response.body->readAllText().wait(io.waitScope); + if (testCase.request.method == HttpMethod::HEAD) { + KJ_EXPECT(body == ""); + } else { + KJ_EXPECT(body == kj::strArray(testCase.response.responseBodyParts, ""), body); + } + } + + client = nullptr; + pipe.ends[0]->shutdownWrite(); + + writeResponsesPromise.wait(io.waitScope); +} + +KJ_TEST("HttpClient parallel pipeline") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + kj::Promise writeResponsesPromise = kj::READY_NOW; + for (auto& testCase: PIPELINE_TESTS) { + writeResponsesPromise = writeResponsesPromise + .then([&]() { + return expectRead(*pipe.ends[1], testCase.request.raw); + }).then([&]() { + return pipe.ends[1]->write(testCase.response.raw.begin(), testCase.response.raw.size()); + }); + } + + HttpHeaderTable table; + auto client = newHttpClient(table, *pipe.ends[0]); + + auto responsePromises = KJ_MAP(testCase, PIPELINE_TESTS) { + KJ_CONTEXT(testCase.request.raw, testCase.response.raw); + + HttpHeaders headers(table); + for (auto& header: testCase.request.requestHeaders) { + headers.set(header.id, header.value); + } + + auto request = client->request( + testCase.request.method, testCase.request.path, headers, testCase.request.requestBodySize); + for (auto& part: testCase.request.requestBodyParts) { + request.body->write(part.begin(), part.size()).wait(io.waitScope); + } + + return kj::mv(request.response); + }; + + for (auto i: kj::indices(PIPELINE_TESTS)) { + auto& testCase = PIPELINE_TESTS[i]; + auto response = responsePromises[i].wait(io.waitScope); + + KJ_EXPECT(response.statusCode == testCase.response.statusCode); + auto body = response.body->readAllText().wait(io.waitScope); + if (testCase.request.method == HttpMethod::HEAD) { + KJ_EXPECT(body == ""); + } else { + KJ_EXPECT(body == kj::strArray(testCase.response.responseBodyParts, ""), body); + } + } + + client = nullptr; + pipe.ends[0]->shutdownWrite(); + + writeResponsesPromise.wait(io.waitScope); +} + +KJ_TEST("HttpServer pipeline") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + TestHttpService service(PIPELINE_TESTS, table); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + for (auto& testCase: PIPELINE_TESTS) { + KJ_CONTEXT(testCase.request.raw, testCase.response.raw); + + pipe.ends[1]->write(testCase.request.raw.begin(), testCase.request.raw.size()) + .wait(io.waitScope); + + expectRead(*pipe.ends[1], testCase.response.raw).wait(io.waitScope); + } + + pipe.ends[1]->shutdownWrite(); + listenTask.wait(io.waitScope); + + KJ_EXPECT(service.getRequestCount() == kj::size(PIPELINE_TESTS)); +} + +KJ_TEST("HttpServer parallel pipeline") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + auto allRequestText = + kj::strArray(KJ_MAP(testCase, PIPELINE_TESTS) { return testCase.request.raw; }, ""); + auto allResponseText = + kj::strArray(KJ_MAP(testCase, PIPELINE_TESTS) { return testCase.response.raw; }, ""); + + HttpHeaderTable table; + TestHttpService service(PIPELINE_TESTS, table); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + pipe.ends[1]->write(allRequestText.begin(), allRequestText.size()).wait(io.waitScope); + pipe.ends[1]->shutdownWrite(); + + auto rawResponse = pipe.ends[1]->readAllText().wait(io.waitScope); + KJ_EXPECT(rawResponse == allResponseText, rawResponse); + + listenTask.wait(io.waitScope); + + KJ_EXPECT(service.getRequestCount() == kj::size(PIPELINE_TESTS)); +} + +KJ_TEST("HttpClient <-> HttpServer") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + TestHttpService service(PIPELINE_TESTS, table); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[1])); + auto client = newHttpClient(table, *pipe.ends[0]); + + for (auto& testCase: PIPELINE_TESTS) { + KJ_CONTEXT(testCase.request.raw, testCase.response.raw); + + HttpHeaders headers(table); + for (auto& header: testCase.request.requestHeaders) { + headers.set(header.id, header.value); + } + + auto request = client->request( + testCase.request.method, testCase.request.path, headers, testCase.request.requestBodySize); + for (auto& part: testCase.request.requestBodyParts) { + request.body->write(part.begin(), part.size()).wait(io.waitScope); + } + request.body = nullptr; + + auto response = request.response.wait(io.waitScope); + + KJ_EXPECT(response.statusCode == testCase.response.statusCode); + auto body = response.body->readAllText().wait(io.waitScope); + if (testCase.request.method == HttpMethod::HEAD) { + KJ_EXPECT(body == ""); + } else { + KJ_EXPECT(body == kj::strArray(testCase.response.responseBodyParts, ""), body); + } + } + + client = nullptr; + pipe.ends[0]->shutdownWrite(); + listenTask.wait(io.waitScope); + KJ_EXPECT(service.getRequestCount() == kj::size(PIPELINE_TESTS)); +} + +// ----------------------------------------------------------------------------- + +KJ_TEST("HttpServer request timeout") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + TestHttpService service(PIPELINE_TESTS, table); + HttpServerSettings settings; + settings.headerTimeout = 1 * kj::MILLISECONDS; + HttpServer server(io.provider->getTimer(), table, service, settings); + + // Shouldn't hang! Should time out. + server.listenHttp(kj::mv(pipe.ends[0])).wait(io.waitScope); + + // Sends back 408 Request Timeout. + KJ_EXPECT(pipe.ends[1]->readAllText().wait(io.waitScope) + .startsWith("HTTP/1.1 408 Request Timeout")); +} + +KJ_TEST("HttpServer pipeline timeout") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + TestHttpService service(PIPELINE_TESTS, table); + HttpServerSettings settings; + settings.pipelineTimeout = 1 * kj::MILLISECONDS; + HttpServer server(io.provider->getTimer(), table, service, settings); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + expectRead(*pipe.ends[1], PIPELINE_TESTS[0].response.raw).wait(io.waitScope); + + // Listen task should time out even though we didn't shutdown the socket. + listenTask.wait(io.waitScope); + + // In this case, no data is sent back. + KJ_EXPECT(pipe.ends[1]->readAllText().wait(io.waitScope) == ""); +} + +class BrokenHttpService final: public HttpService { + // HttpService that doesn't send a response. +public: + BrokenHttpService() = default; + explicit BrokenHttpService(kj::Exception&& exception): exception(kj::mv(exception)) {} + + kj::Promise request( + HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::AsyncInputStream& requestBody, Response& responseSender) override { + return requestBody.readAllBytes().then([this](kj::Array&&) -> kj::Promise { + KJ_IF_MAYBE(e, exception) { + return kj::cp(*e); + } else { + return kj::READY_NOW; + } + }); + } + +private: + kj::Maybe exception; +}; + +KJ_TEST("HttpServer no response") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + BrokenHttpService service; + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text == + "HTTP/1.1 500 Internal Server Error\r\n" + "Connection: close\r\n" + "Content-Length: 51\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "ERROR: The HttpService did not generate a response.", text); +} + +KJ_TEST("HttpServer disconnected") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + BrokenHttpService service(KJ_EXCEPTION(DISCONNECTED, "disconnected")); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text == "", text); +} + +KJ_TEST("HttpServer overloaded") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + BrokenHttpService service(KJ_EXCEPTION(OVERLOADED, "overloaded")); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text.startsWith("HTTP/1.1 503 Service Unavailable"), text); +} + +KJ_TEST("HttpServer unimplemented") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + BrokenHttpService service(KJ_EXCEPTION(UNIMPLEMENTED, "unimplemented")); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text.startsWith("HTTP/1.1 501 Not Implemented"), text); +} + +KJ_TEST("HttpServer threw exception") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + BrokenHttpService service(KJ_EXCEPTION(FAILED, "failed")); + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text.startsWith("HTTP/1.1 500 Internal Server Error"), text); +} + +class PartialResponseService final: public HttpService { + // HttpService that sends a partial response then throws. +public: + kj::Promise request( + HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::AsyncInputStream& requestBody, Response& response) override { + return requestBody.readAllBytes() + .then([this,&response](kj::Array&&) -> kj::Promise { + HttpHeaders headers(table); + auto body = response.send(200, "OK", headers, 32); + auto promise = body->write("foo", 3); + return promise.attach(kj::mv(body)).then([]() -> kj::Promise { + return KJ_EXCEPTION(FAILED, "failed"); + }); + }); + } + +private: + kj::Maybe exception; + HttpHeaderTable table; +}; + +KJ_TEST("HttpServer threw exception after starting response") { + auto PIPELINE_TESTS = pipelineTestCases(); + + auto io = kj::setupAsyncIo(); + auto pipe = io.provider->newTwoWayPipe(); + + HttpHeaderTable table; + PartialResponseService service; + HttpServer server(io.provider->getTimer(), table, service); + + auto listenTask = server.listenHttp(kj::mv(pipe.ends[0])); + + KJ_EXPECT_LOG(ERROR, "HttpService threw exception after generating a partial response"); + + // Do one request. + pipe.ends[1]->write(PIPELINE_TESTS[0].request.raw.begin(), PIPELINE_TESTS[0].request.raw.size()) + .wait(io.waitScope); + auto text = pipe.ends[1]->readAllText().wait(io.waitScope); + + KJ_EXPECT(text == + "HTTP/1.1 200 OK\r\n" + "Content-Length: 32\r\n" + "\r\n" + "foo", text); +} + +// ----------------------------------------------------------------------------- + +KJ_TEST("HttpClient to capnproto.org") { + auto io = kj::setupAsyncIo(); + + auto maybeConn = io.provider->getNetwork().parseAddress("capnproto.org", 80) + .then([](kj::Own addr) { + auto promise = addr->connect(); + return promise.attach(kj::mv(addr)); + }).then([](kj::Own&& connection) -> kj::Maybe> { + return kj::mv(connection); + }, [](kj::Exception&& e) -> kj::Maybe> { + KJ_LOG(WARNING, "skipping test because couldn't connect to capnproto.org"); + return nullptr; + }).wait(io.waitScope); + + KJ_IF_MAYBE(conn, maybeConn) { + // Successfully connected to capnproto.org. Try doing GET /. We expect to get a redirect to + // HTTPS, because what kind of horrible web site would serve in plaintext, really? + + HttpHeaderTable table; + auto client = newHttpClient(table, **conn); + + HttpHeaders headers(table); + headers.set(HttpHeaderId::HOST, "capnproto.org"); + + auto response = client->request(HttpMethod::GET, "/", headers).response.wait(io.waitScope); + KJ_EXPECT(response.statusCode / 100 == 3); + auto location = KJ_ASSERT_NONNULL(response.headers->get(HttpHeaderId::LOCATION)); + KJ_EXPECT(location == "https://capnproto.org/"); + + auto body = response.body->readAllText().wait(io.waitScope); + } +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/compat/http.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/compat/http.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,1826 @@ +// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "http.h" +#include +#include +#include +#include + +namespace kj { + +static const char* METHOD_NAMES[] = { +#define METHOD_NAME(id) #id, +KJ_HTTP_FOR_EACH_METHOD(METHOD_NAME) +#undef METHOD_NAME +}; + +kj::StringPtr KJ_STRINGIFY(HttpMethod method) { + return METHOD_NAMES[static_cast(method)]; +} + +static kj::Maybe consumeHttpMethod(char*& ptr) { + char* p = ptr; + +#define EXPECT_REST(prefix, suffix) \ + if (strncmp(p, #suffix, sizeof(#suffix)-1) == 0) { \ + ptr = p + (sizeof(#suffix)-1); \ + return HttpMethod::prefix##suffix; \ + } else { \ + return nullptr; \ + } + + switch (*p++) { + case 'C': + switch (*p++) { + case 'H': EXPECT_REST(CH,ECKOUT) + case 'O': EXPECT_REST(CO,PY) + default: return nullptr; + } + case 'D': EXPECT_REST(D,ELETE) + case 'G': EXPECT_REST(G,ET) + case 'H': EXPECT_REST(H,EAD) + case 'L': EXPECT_REST(L,OCK) + case 'M': + switch (*p++) { + case 'E': EXPECT_REST(ME,RGE) + case 'K': + switch (*p++) { + case 'A': EXPECT_REST(MKA,CTIVITY) + case 'C': EXPECT_REST(MKC,OL) + default: return nullptr; + } + case 'O': EXPECT_REST(MO,VE) + case 'S': EXPECT_REST(MS,EARCH) + default: return nullptr; + } + case 'N': EXPECT_REST(N,OTIFY) + case 'O': EXPECT_REST(O,PTIONS) + case 'P': + switch (*p++) { + case 'A': EXPECT_REST(PA,TCH) + case 'O': EXPECT_REST(PO,ST) + case 'R': + if (*p++ != 'O' || *p++ != 'P') return nullptr; + switch (*p++) { + case 'F': EXPECT_REST(PROPF,IND) + case 'P': EXPECT_REST(PROPP,ATCH) + default: return nullptr; + } + case 'U': + switch (*p++) { + case 'R': EXPECT_REST(PUR,GE) + case 'T': EXPECT_REST(PUT,) + default: return nullptr; + } + default: return nullptr; + } + case 'R': EXPECT_REST(R,EPORT) + case 'S': + switch (*p++) { + case 'E': EXPECT_REST(SE,ARCH) + case 'U': EXPECT_REST(SU,BSCRIBE) + default: return nullptr; + } + case 'T': EXPECT_REST(T,RACE) + case 'U': + if (*p++ != 'N') return nullptr; + switch (*p++) { + case 'L': EXPECT_REST(UNL,OCK) + case 'S': EXPECT_REST(UNS,UBSCRIBE) + default: return nullptr; + } + default: return nullptr; + } +#undef EXPECT_REST +} + +kj::Maybe tryParseHttpMethod(kj::StringPtr name) { + // const_cast OK because we don't actually access it. consumeHttpMethod() is also called by some + // code later than explicitly needs to use a non-const pointer. + char* ptr = const_cast(name.begin()); + auto result = consumeHttpMethod(ptr); + if (*ptr == '\0') { + return result; + } else { + return nullptr; + } +} + +// ======================================================================================= + +namespace { + +constexpr auto HTTP_SEPARATOR_CHARS = kj::parse::anyOfChars("()<>@,;:\\\"/[]?={} \t"); +// RFC2616 section 2.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 + +constexpr auto HTTP_TOKEN_CHARS = + kj::parse::controlChar.orChar('\x7f') + .orGroup(kj::parse::whitespaceChar) + .orGroup(HTTP_SEPARATOR_CHARS) + .invert(); +// RFC2616 section 2.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 + +constexpr auto HTTP_HEADER_NAME_CHARS = HTTP_TOKEN_CHARS; +// RFC2616 section 4.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + +static void requireValidHeaderName(kj::StringPtr name) { + for (char c: name) { + KJ_REQUIRE(HTTP_HEADER_NAME_CHARS.contains(c), "invalid header name", name); + } +} + +static void requireValidHeaderValue(kj::StringPtr value) { + for (char c: value) { + KJ_REQUIRE(c >= 0x20, "invalid header value", value); + } +} + +static const char* BUILTIN_HEADER_NAMES[] = { + // Indexed by header ID, which includes connection headers, so we include those names too. +#define HEADER_NAME(id, name) name, + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_NAME) +#undef HEADER_NAME +}; + +enum class BuiltinHeaderIndices { +#define HEADER_ID(id, name) id, + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(HEADER_ID) +#undef HEADER_ID +}; + +static constexpr size_t CONNECTION_HEADER_COUNT KJ_UNUSED = 0 +#define COUNT_HEADER(id, name) + 1 + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(COUNT_HEADER) +#undef COUNT_HEADER + ; + +enum class ConnectionHeaderIndices { +#define HEADER_ID(id, name) id, + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(HEADER_ID) +#undef HEADER_ID +}; + +static constexpr uint CONNECTION_HEADER_XOR = kj::maxValue; +static constexpr uint CONNECTION_HEADER_THRESHOLD = CONNECTION_HEADER_XOR >> 1; + +} // namespace + +#define DEFINE_HEADER(id, name) \ +const HttpHeaderId HttpHeaderId::id(nullptr, static_cast(BuiltinHeaderIndices::id)); +KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DEFINE_HEADER) +#undef DEFINE_HEADER + +kj::StringPtr HttpHeaderId::toString() const { + if (table == nullptr) { + KJ_ASSERT(id < kj::size(BUILTIN_HEADER_NAMES)); + return BUILTIN_HEADER_NAMES[id]; + } else { + return table->idToString(*this); + } +} + +namespace { + +struct HeaderNameHash { + size_t operator()(kj::StringPtr s) const { + size_t result = 5381; + for (byte b: s.asBytes()) { + // Masking bit 0x20 makes our hash case-insensitive while conveniently avoiding any + // collisions that would matter for header names. + result = ((result << 5) + result) ^ (b & ~0x20); + } + return result; + } + + bool operator()(kj::StringPtr a, kj::StringPtr b) const { + // TODO(perf): I wonder if we can beat strcasecmp() by masking bit 0x20 from each byte. We'd + // need to prohibit one of the technically-legal characters '^' or '~' from header names + // since they'd otherwise be ambiguous, but otherwise there is no ambiguity. +#if _MSC_VER + return _stricmp(a.cStr(), b.cStr()) == 0; +#else + return strcasecmp(a.cStr(), b.cStr()) == 0; +#endif + } +}; + +} // namespace + +struct HttpHeaderTable::IdsByNameMap { + // TODO(perf): If we were cool we could maybe use a perfect hash here, since our hashtable is + // static once built. + + std::unordered_map map; +}; + +HttpHeaderTable::Builder::Builder() + : table(kj::heap()) {} + +HttpHeaderId HttpHeaderTable::Builder::add(kj::StringPtr name) { + requireValidHeaderName(name); + + auto insertResult = table->idsByName->map.insert(std::make_pair(name, table->namesById.size())); + if (insertResult.second) { + table->namesById.add(name); + } + return HttpHeaderId(table, insertResult.first->second); +} + +HttpHeaderTable::HttpHeaderTable() + : idsByName(kj::heap()) { +#define ADD_HEADER(id, name) \ + idsByName->map.insert(std::make_pair(name, \ + static_cast(ConnectionHeaderIndices::id) ^ CONNECTION_HEADER_XOR)); + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(ADD_HEADER); +#undef ADD_HEADER + +#define ADD_HEADER(id, name) \ + namesById.add(name); \ + idsByName->map.insert(std::make_pair(name, static_cast(BuiltinHeaderIndices::id))); + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(ADD_HEADER); +#undef ADD_HEADER +} +HttpHeaderTable::~HttpHeaderTable() noexcept(false) {} + +kj::Maybe HttpHeaderTable::stringToId(kj::StringPtr name) { + auto iter = idsByName->map.find(name); + if (iter == idsByName->map.end()) { + return nullptr; + } else { + return HttpHeaderId(this, iter->second); + } +} + +// ======================================================================================= + +HttpHeaders::HttpHeaders(HttpHeaderTable& table) + : table(&table), + indexedHeaders(kj::heapArray(table.idCount())) {} + +void HttpHeaders::clear() { + for (auto& header: indexedHeaders) { + header = nullptr; + } + + unindexedHeaders.clear(); +} + +HttpHeaders HttpHeaders::clone() const { + HttpHeaders result(*table); + + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + result.indexedHeaders[i] = result.cloneToOwn(indexedHeaders[i]); + } + } + + result.unindexedHeaders.resize(unindexedHeaders.size()); + for (auto i: kj::indices(unindexedHeaders)) { + result.unindexedHeaders[i].name = result.cloneToOwn(unindexedHeaders[i].name); + result.unindexedHeaders[i].value = result.cloneToOwn(unindexedHeaders[i].value); + } + + return result; +} + +HttpHeaders HttpHeaders::cloneShallow() const { + HttpHeaders result(*table); + + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + result.indexedHeaders[i] = indexedHeaders[i]; + } + } + + result.unindexedHeaders.resize(unindexedHeaders.size()); + for (auto i: kj::indices(unindexedHeaders)) { + result.unindexedHeaders[i] = unindexedHeaders[i]; + } + + return result; +} + +kj::StringPtr HttpHeaders::cloneToOwn(kj::StringPtr str) { + auto copy = kj::heapString(str); + kj::StringPtr result = copy; + ownedStrings.add(copy.releaseArray()); + return result; +} + +void HttpHeaders::set(HttpHeaderId id, kj::StringPtr value) { + id.requireFrom(*table); + requireValidHeaderValue(value); + + indexedHeaders[id.id] = value; +} + +void HttpHeaders::set(HttpHeaderId id, kj::String&& value) { + set(id, kj::StringPtr(value)); + takeOwnership(kj::mv(value)); +} + +void HttpHeaders::add(kj::StringPtr name, kj::StringPtr value) { + requireValidHeaderName(name); + requireValidHeaderValue(value); + + KJ_REQUIRE(addNoCheck(name, value) == nullptr, + "can't set connection-level headers on HttpHeaders", name, value) { break; } +} + +void HttpHeaders::add(kj::StringPtr name, kj::String&& value) { + add(name, kj::StringPtr(value)); + takeOwnership(kj::mv(value)); +} + +void HttpHeaders::add(kj::String&& name, kj::String&& value) { + add(kj::StringPtr(name), kj::StringPtr(value)); + takeOwnership(kj::mv(name)); + takeOwnership(kj::mv(value)); +} + +kj::Maybe HttpHeaders::addNoCheck(kj::StringPtr name, kj::StringPtr value) { + KJ_IF_MAYBE(id, table->stringToId(name)) { + if (id->id > CONNECTION_HEADER_THRESHOLD) { + return id->id ^ CONNECTION_HEADER_XOR; + } + + if (indexedHeaders[id->id] == nullptr) { + indexedHeaders[id->id] = value; + } else { + // Duplicate HTTP headers are equivalent to the values being separated by a comma. + auto concat = kj::str(indexedHeaders[id->id], ", ", value); + indexedHeaders[id->id] = concat; + ownedStrings.add(concat.releaseArray()); + } + } else { + unindexedHeaders.add(Header {name, value}); + } + + return nullptr; +} + +void HttpHeaders::takeOwnership(kj::String&& string) { + ownedStrings.add(string.releaseArray()); +} +void HttpHeaders::takeOwnership(kj::Array&& chars) { + ownedStrings.add(kj::mv(chars)); +} +void HttpHeaders::takeOwnership(HttpHeaders&& otherHeaders) { + for (auto& str: otherHeaders.ownedStrings) { + ownedStrings.add(kj::mv(str)); + } + otherHeaders.ownedStrings.clear(); +} + +// ----------------------------------------------------------------------------- + +static inline char* skipSpace(char* p) { + for (;;) { + switch (*p) { + case '\t': + case ' ': + ++p; + break; + default: + return p; + } + } +} + +static kj::Maybe consumeWord(char*& ptr) { + char* start = skipSpace(ptr); + char* p = start; + + for (;;) { + switch (*p) { + case '\0': + ptr = p; + return kj::StringPtr(start, p); + + case '\t': + case ' ': { + char* end = p++; + ptr = p; + *end = '\0'; + return kj::StringPtr(start, end); + } + + case '\n': + case '\r': + // Not expecting EOL! + return nullptr; + + default: + ++p; + break; + } + } +} + +static kj::Maybe consumeNumber(char*& ptr) { + char* start = skipSpace(ptr); + char* p = start; + + uint result = 0; + + for (;;) { + char c = *p; + if ('0' <= c && c <= '9') { + result = result * 10 + (c - '0'); + ++p; + } else { + if (p == start) return nullptr; + ptr = p; + return result; + } + } +} + +static kj::StringPtr consumeLine(char*& ptr) { + char* start = skipSpace(ptr); + char* p = start; + + for (;;) { + switch (*p) { + case '\0': + ptr = p; + return kj::StringPtr(start, p); + + case '\r': { + char* end = p++; + if (*p == '\n') ++p; + + if (*p == ' ' || *p == '\t') { + // Whoa, continuation line. These are deprecated, but historically a line starting with + // a space was treated as a continuation of the previous line. The behavior should be + // the same as if the \r\n were replaced with spaces, so let's do that here to prevent + // confusion later. + *end = ' '; + p[-1] = ' '; + break; + } + + ptr = p; + *end = '\0'; + return kj::StringPtr(start, end); + } + + case '\n': { + char* end = p++; + + if (*p == ' ' || *p == '\t') { + // Whoa, continuation line. These are deprecated, but historically a line starting with + // a space was treated as a continuation of the previous line. The behavior should be + // the same as if the \n were replaced with spaces, so let's do that here to prevent + // confusion later. + *end = ' '; + break; + } + + ptr = p; + *end = '\0'; + return kj::StringPtr(start, end); + } + + default: + ++p; + break; + } + } +} + +static kj::Maybe consumeHeaderName(char*& ptr) { + // Do NOT skip spaces before the header name. Leading spaces indicate a continuation line; they + // should have been handled in consumeLine(). + char* p = ptr; + + char* start = p; + while (HTTP_HEADER_NAME_CHARS.contains(*p)) ++p; + char* end = p; + + p = skipSpace(p); + + if (end == start || *p != ':') return nullptr; + ++p; + + p = skipSpace(p); + + *end = '\0'; + ptr = p; + return kj::StringPtr(start, end); +} + +static char* trimHeaderEnding(kj::ArrayPtr content) { + // Trim off the trailing \r\n from a header blob. + + if (content.size() < 2) return nullptr; + + // Remove trailing \r\n\r\n and replace with \0 sentinel char. + char* end = content.end(); + + if (end[-1] != '\n') return nullptr; + --end; + if (end[-1] == '\r') --end; + *end = '\0'; + + return end; +} + +kj::Maybe HttpHeaders::tryParseRequest(kj::ArrayPtr content) { + char* end = trimHeaderEnding(content); + if (end == nullptr) return nullptr; + + char* ptr = content.begin(); + + HttpHeaders::Request request; + + KJ_IF_MAYBE(method, consumeHttpMethod(ptr)) { + request.method = *method; + if (*ptr != ' ' && *ptr != '\t') { + return nullptr; + } + ++ptr; + } else { + return nullptr; + } + + KJ_IF_MAYBE(path, consumeWord(ptr)) { + request.url = *path; + } else { + return nullptr; + } + + // Ignore rest of line. Don't care about "HTTP/1.1" or whatever. + consumeLine(ptr); + + if (!parseHeaders(ptr, end, request.connectionHeaders)) return nullptr; + + return request; +} + +kj::Maybe HttpHeaders::tryParseResponse(kj::ArrayPtr content) { + char* end = trimHeaderEnding(content); + if (end == nullptr) return nullptr; + + char* ptr = content.begin(); + + HttpHeaders::Response response; + + KJ_IF_MAYBE(version, consumeWord(ptr)) { + if (!version->startsWith("HTTP/")) return nullptr; + } else { + return nullptr; + } + + KJ_IF_MAYBE(code, consumeNumber(ptr)) { + response.statusCode = *code; + } else { + return nullptr; + } + + response.statusText = consumeLine(ptr); + + if (!parseHeaders(ptr, end, response.connectionHeaders)) return nullptr; + + return response; +} + +bool HttpHeaders::parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders) { + while (*ptr != '\0') { + KJ_IF_MAYBE(name, consumeHeaderName(ptr)) { + kj::StringPtr line = consumeLine(ptr); + KJ_IF_MAYBE(connectionHeaderId, addNoCheck(*name, line)) { + // Parsed a connection header. + switch (*connectionHeaderId) { +#define HANDLE_HEADER(id, name) \ + case static_cast(ConnectionHeaderIndices::id): \ + connectionHeaders.id = line; \ + break; + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(HANDLE_HEADER) +#undef HANDLE_HEADER + default: + KJ_UNREACHABLE; + } + } + } else { + return false; + } + } + + return ptr == end; +} + +// ----------------------------------------------------------------------------- + +kj::String HttpHeaders::serializeRequest(HttpMethod method, kj::StringPtr url, + const ConnectionHeaders& connectionHeaders) const { + return serialize(kj::toCharSequence(method), url, kj::StringPtr("HTTP/1.1"), connectionHeaders); +} + +kj::String HttpHeaders::serializeResponse(uint statusCode, kj::StringPtr statusText, + const ConnectionHeaders& connectionHeaders) const { + auto statusCodeStr = kj::toCharSequence(statusCode); + + return serialize(kj::StringPtr("HTTP/1.1"), statusCodeStr, statusText, connectionHeaders); +} + +kj::String HttpHeaders::serialize(kj::ArrayPtr word1, + kj::ArrayPtr word2, + kj::ArrayPtr word3, + const ConnectionHeaders& connectionHeaders) const { + const kj::StringPtr space = " "; + const kj::StringPtr newline = "\r\n"; + const kj::StringPtr colon = ": "; + + size_t size = 2; // final \r\n + if (word1 != nullptr) { + size += word1.size() + word2.size() + word3.size() + 4; + } +#define HANDLE_HEADER(id, name) \ + if (connectionHeaders.id != nullptr) { \ + size += connectionHeaders.id.size() + (sizeof(name) + 3); \ + } + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(HANDLE_HEADER) +#undef HANDLE_HEADER + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + size += table->idToString(HttpHeaderId(table, i)).size() + indexedHeaders[i].size() + 4; + } + } + for (auto& header: unindexedHeaders) { + size += header.name.size() + header.value.size() + 4; + } + + String result = heapString(size); + char* ptr = result.begin(); + + if (word1 != nullptr) { + ptr = kj::_::fill(ptr, word1, space, word2, space, word3, newline); + } +#define HANDLE_HEADER(id, name) \ + if (connectionHeaders.id != nullptr) { \ + ptr = kj::_::fill(ptr, kj::StringPtr(name), colon, connectionHeaders.id, newline); \ + } + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(HANDLE_HEADER) +#undef HANDLE_HEADER + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + ptr = kj::_::fill(ptr, table->idToString(HttpHeaderId(table, i)), colon, + indexedHeaders[i], newline); + } + } + for (auto& header: unindexedHeaders) { + ptr = kj::_::fill(ptr, header.name, colon, header.value, newline); + } + ptr = kj::_::fill(ptr, newline); + + KJ_ASSERT(ptr == result.end()); + return result; +} + +kj::String HttpHeaders::toString() const { + return serialize(nullptr, nullptr, nullptr, ConnectionHeaders()); +} + +// ======================================================================================= + +namespace { + +static constexpr size_t MIN_BUFFER = 4096; +static constexpr size_t MAX_BUFFER = 65536; +static constexpr size_t MAX_CHUNK_HEADER_SIZE = 32; + +class HttpInputStream { +public: + explicit HttpInputStream(AsyncIoStream& inner, HttpHeaderTable& table) + : inner(inner), headerBuffer(kj::heapArray(MIN_BUFFER)), headers(table) { + } + + // --------------------------------------------------------------------------- + // Stream locking: While an entity-body is being read, the body stream "locks" the underlying + // HTTP stream. Once the entity-body is complete, we can read the next pipelined message. + + void finishRead() { + // Called when entire request has been read. + + KJ_REQUIRE_NONNULL(onMessageDone)->fulfill(); + onMessageDone = nullptr; + } + + void abortRead() { + // Called when a body input stream was destroyed without reading to the end. + + KJ_REQUIRE_NONNULL(onMessageDone)->reject(KJ_EXCEPTION(FAILED, + "client did not finish reading previous HTTP response body", + "can't read next pipelined response")); + onMessageDone = nullptr; + } + + // --------------------------------------------------------------------------- + + kj::Promise awaitNextMessage() { + // Waits until more data is available, but doesn't consume it. Only meant for server-side use, + // after a request is handled, to check for pipelined requests. Returns false on EOF. + + // Slightly-crappy code to snarf the expected line break. This will actually eat the leading + // regex /\r*\n?/. + while (lineBreakBeforeNextHeader && leftover.size() > 0) { + if (leftover[0] == '\r') { + leftover = leftover.slice(1, leftover.size()); + } else if (leftover[0] == '\n') { + leftover = leftover.slice(1, leftover.size()); + lineBreakBeforeNextHeader = false; + } else { + // Err, missing line break, whatever. + lineBreakBeforeNextHeader = false; + } + } + + if (!lineBreakBeforeNextHeader && leftover != nullptr) { + return true; + } + + return inner.tryRead(headerBuffer.begin(), 1, headerBuffer.size()) + .then([this](size_t amount) -> kj::Promise { + if (amount > 0) { + leftover = headerBuffer.slice(0, amount); + return awaitNextMessage(); + } else { + return false; + } + }); + } + + kj::Promise> readMessageHeaders() { + auto paf = kj::newPromiseAndFulfiller(); + + auto promise = messageReadQueue + .then(kj::mvCapture(paf.fulfiller, [this](kj::Own> fulfiller) { + onMessageDone = kj::mv(fulfiller); + return readHeader(HeaderType::MESSAGE, 0, 0); + })); + + messageReadQueue = kj::mv(paf.promise); + + return promise; + } + + kj::Promise readChunkHeader() { + KJ_REQUIRE(onMessageDone != nullptr); + + // We use the portion of the header after the end of message headers. + return readHeader(HeaderType::CHUNK, messageHeaderEnd, messageHeaderEnd) + .then([](kj::ArrayPtr text) -> uint64_t { + KJ_REQUIRE(text.size() > 0) { break; } + + uint64_t value = 0; + for (char c: text) { + if ('0' <= c && c <= '9') { + value = value * 16 + (c - '0'); + } else if ('a' <= c && c <= 'f') { + value = value * 16 + (c - 'a' + 10); + } else if ('A' <= c && c <= 'F') { + value = value * 16 + (c - 'A' + 10); + } else { + KJ_FAIL_REQUIRE("invalid HTTP chunk size", text, text.asBytes()) { + return value; + } + } + } + + return value; + }); + } + + inline kj::Promise> readRequestHeaders() { + headers.clear(); + return readMessageHeaders().then([this](kj::ArrayPtr text) { + return headers.tryParseRequest(text); + }); + } + + inline kj::Promise> readResponseHeaders() { + headers.clear(); + return readMessageHeaders().then([this](kj::ArrayPtr text) { + return headers.tryParseResponse(text); + }); + } + + inline const HttpHeaders& getHeaders() const { return headers; } + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) { + // Read message body data. + + KJ_REQUIRE(onMessageDone != nullptr); + + if (leftover == nullptr) { + // No leftovers. Forward directly to inner stream. + return inner.tryRead(buffer, minBytes, maxBytes); + } else if (leftover.size() >= maxBytes) { + // Didn't even read the entire leftover buffer. + memcpy(buffer, leftover.begin(), maxBytes); + leftover = leftover.slice(maxBytes, leftover.size()); + return maxBytes; + } else { + // Read the entire leftover buffer, plus some. + memcpy(buffer, leftover.begin(), leftover.size()); + size_t copied = leftover.size(); + leftover = nullptr; + if (copied >= minBytes) { + // Got enough to stop here. + return copied; + } else { + // Read the rest from the underlying stream. + return inner.tryRead(reinterpret_cast(buffer) + copied, + minBytes - copied, maxBytes - copied) + .then([copied](size_t n) { return n + copied; }); + } + } + } + + enum RequestOrResponse { + REQUEST, + RESPONSE + }; + + kj::Own getEntityBody( + RequestOrResponse type, HttpMethod method, uint statusCode, + HttpHeaders::ConnectionHeaders& connectionHeaders); + +private: + AsyncIoStream& inner; + kj::Array headerBuffer; + + size_t messageHeaderEnd = 0; + // Position in headerBuffer where the message headers end -- further buffer space can + // be used for chunk headers. + + kj::ArrayPtr leftover; + // Data in headerBuffer that comes immediately after the header content, if any. + + HttpHeaders headers; + // Parsed headers, after a call to parseAwaited*(). + + bool lineBreakBeforeNextHeader = false; + // If true, the next await should expect to start with a spurrious '\n' or '\r\n'. This happens + // as a side-effect of HTTP chunked encoding, where such a newline is added to the end of each + // chunk, for no good reason. + + kj::Promise messageReadQueue = kj::READY_NOW; + + kj::Maybe>> onMessageDone; + // Fulfill once the current message has been completely read. Unblocks reading of the next + // message headers. + + enum class HeaderType { + MESSAGE, + CHUNK + }; + + kj::Promise> readHeader( + HeaderType type, size_t bufferStart, size_t bufferEnd) { + // Reads the HTTP message header or a chunk header (as in transfer-encoding chunked) and + // returns the buffer slice containing it. + // + // The main source of complication here is that we want to end up with one continuous buffer + // containing the result, and that the input is delimited by newlines rather than by an upfront + // length. + + kj::Promise readPromise = nullptr; + + // Figure out where we're reading from. + if (leftover != nullptr) { + // Some data is still left over from the previous message, so start with that. + + // This can only happen if this is the initial call to readHeader() (not recursive). + KJ_ASSERT(bufferStart == bufferEnd); + + // OK, set bufferStart and bufferEnd to both point to the start of the leftover, and then + // fake a read promise as if we read the bytes from the leftover. + bufferStart = leftover.begin() - headerBuffer.begin(); + bufferEnd = bufferStart; + readPromise = leftover.size(); + leftover = nullptr; + } else { + // Need to read more data from the unfderlying stream. + + if (bufferEnd == headerBuffer.size()) { + // Out of buffer space. + + // Maybe we can move bufferStart backwards to make more space at the end? + size_t minStart = type == HeaderType::MESSAGE ? 0 : messageHeaderEnd; + + if (bufferStart > minStart) { + // Move to make space. + memmove(headerBuffer.begin() + minStart, headerBuffer.begin() + bufferStart, + bufferEnd - bufferStart); + bufferEnd = bufferEnd - bufferStart + minStart; + bufferStart = minStart; + } else { + // Really out of buffer space. Grow the buffer. + if (type != HeaderType::MESSAGE) { + // Can't grow because we'd invalidate the HTTP headers. + return KJ_EXCEPTION(FAILED, "invalid HTTP chunk size"); + } + KJ_REQUIRE(headerBuffer.size() < MAX_BUFFER, "request headers too large"); + auto newBuffer = kj::heapArray(headerBuffer.size() * 2); + memcpy(newBuffer.begin(), headerBuffer.begin(), headerBuffer.size()); + headerBuffer = kj::mv(newBuffer); + } + } + + // How many bytes will we read? + size_t maxBytes = headerBuffer.size() - bufferEnd; + + if (type == HeaderType::CHUNK) { + // Roughly limit the amount of data we read to MAX_CHUNK_HEADER_SIZE. + // TODO(perf): This is mainly to avoid copying a lot of body data into our buffer just to + // copy it again when it is read. But maybe the copy would be cheaper than overhead of + // extra event loop turns? + KJ_REQUIRE(bufferEnd - bufferStart <= MAX_CHUNK_HEADER_SIZE, "invalid HTTP chunk size"); + maxBytes = kj::min(maxBytes, MAX_CHUNK_HEADER_SIZE); + } + + readPromise = inner.read(headerBuffer.begin() + bufferEnd, 1, maxBytes); + } + + return readPromise.then([this,type,bufferStart,bufferEnd](size_t amount) mutable + -> kj::Promise> { + if (lineBreakBeforeNextHeader) { + // Hackily deal with expected leading line break. + if (bufferEnd == bufferStart && headerBuffer[bufferEnd] == '\r') { + ++bufferEnd; + --amount; + } + + if (amount > 0 && headerBuffer[bufferEnd] == '\n') { + lineBreakBeforeNextHeader = false; + ++bufferEnd; + --amount; + + // Cut the leading line break out of the buffer entirely. + bufferStart = bufferEnd; + } + + if (amount == 0) { + return readHeader(type, bufferStart, bufferEnd); + } + } + + size_t pos = bufferEnd; + size_t newEnd = pos + amount; + + for (;;) { + // Search for next newline. + char* nl = reinterpret_cast( + memchr(headerBuffer.begin() + pos, '\n', newEnd - pos)); + if (nl == nullptr) { + // No newline found. Wait for more data. + return readHeader(type, bufferStart, newEnd); + } + + // Is this newline which we found the last of the header? For a chunk header, always. For + // a message header, we search for two newlines in a row. We accept either "\r\n" or just + // "\n" as a newline sequence (though the standard requires "\r\n"). + if (type == HeaderType::CHUNK || + (nl - headerBuffer.begin() >= 4 && + ((nl[-1] == '\r' && nl[-2] == '\n') || (nl[-1] == '\n')))) { + // OK, we've got all the data! + + size_t endIndex = nl + 1 - headerBuffer.begin(); + size_t leftoverStart = endIndex; + + // Strip off the last newline from end. + endIndex -= 1 + (nl[-1] == '\r'); + + if (type == HeaderType::MESSAGE) { + if (headerBuffer.size() - newEnd < MAX_CHUNK_HEADER_SIZE) { + // Ugh, there's not enough space for the secondary await buffer. Grow once more. + auto newBuffer = kj::heapArray(headerBuffer.size() * 2); + memcpy(newBuffer.begin(), headerBuffer.begin(), headerBuffer.size()); + headerBuffer = kj::mv(newBuffer); + } + messageHeaderEnd = endIndex; + } else { + // For some reason, HTTP specifies that there will be a line break after each chunk. + lineBreakBeforeNextHeader = true; + } + + auto result = headerBuffer.slice(bufferStart, endIndex); + leftover = headerBuffer.slice(leftoverStart, newEnd); + return result; + } else { + pos = nl - headerBuffer.begin() + 1; + } + } + }); + } +}; + +// ----------------------------------------------------------------------------- + +class HttpEntityBodyReader: public kj::AsyncInputStream { +public: + HttpEntityBodyReader(HttpInputStream& inner): inner(inner) {} + ~HttpEntityBodyReader() noexcept(false) { + if (!finished) { + inner.abortRead(); + } + } + +protected: + HttpInputStream& inner; + + void doneReading() { + KJ_REQUIRE(!finished); + finished = true; + inner.finishRead(); + } + + inline bool alreadyDone() { return finished; } + +private: + bool finished = false; +}; + +class HttpNullEntityReader final: public HttpEntityBodyReader { + // Stream which reads until EOF. + +public: + HttpNullEntityReader(HttpInputStream& inner) + : HttpEntityBodyReader(inner) { + doneReading(); + } + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + return size_t(0); + } +}; + +class HttpConnectionCloseEntityReader final: public HttpEntityBodyReader { + // Stream which reads until EOF. + +public: + HttpConnectionCloseEntityReader(HttpInputStream& inner) + : HttpEntityBodyReader(inner) {} + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + if (alreadyDone()) return size_t(0); + + return inner.tryRead(buffer, minBytes, maxBytes) + .then([=](size_t amount) { + if (amount < minBytes) { + doneReading(); + } + return amount; + }); + } +}; + +class HttpFixedLengthEntityReader final: public HttpEntityBodyReader { + // Stream which reads only up to a fixed length from the underlying stream, then emulates EOF. + +public: + HttpFixedLengthEntityReader(HttpInputStream& inner, size_t length) + : HttpEntityBodyReader(inner), length(length) { + if (length == 0) doneReading(); + } + + Maybe tryGetLength() override { + return length; + } + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + if (length == 0) return size_t(0); + + return inner.tryRead(buffer, kj::min(minBytes, length), kj::min(maxBytes, length)) + .then([=](size_t amount) { + length -= amount; + if (length > 0 && amount < minBytes) { + kj::throwRecoverableException(KJ_EXCEPTION(DISCONNECTED, + "premature EOF in HTTP entity body; did not reach Content-Length")); + } else if (length == 0) { + doneReading(); + } + return amount; + }); + } + +private: + size_t length; +}; + +class HttpChunkedEntityReader final: public HttpEntityBodyReader { + // Stream which reads a Transfer-Encoding: Chunked stream. + +public: + HttpChunkedEntityReader(HttpInputStream& inner) + : HttpEntityBodyReader(inner) {} + + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + return tryReadInternal(buffer, minBytes, maxBytes, 0); + } + +private: + size_t chunkSize = 0; + + Promise tryReadInternal(void* buffer, size_t minBytes, size_t maxBytes, + size_t alreadyRead) { + if (alreadyDone()) { + return alreadyRead; + } else if (chunkSize == 0) { + // Read next chunk header. + return inner.readChunkHeader().then([=](uint64_t nextChunkSize) { + if (nextChunkSize == 0) { + doneReading(); + } + + chunkSize = nextChunkSize; + return tryReadInternal(buffer, minBytes, maxBytes, alreadyRead); + }); + } else if (chunkSize < minBytes) { + // Read entire current chunk and continue to next chunk. + return inner.tryRead(buffer, chunkSize, chunkSize) + .then([=](size_t amount) -> kj::Promise { + chunkSize -= amount; + if (chunkSize > 0) { + return KJ_EXCEPTION(DISCONNECTED, "premature EOF in HTTP chunk"); + } + + return tryReadInternal(reinterpret_cast(buffer) + amount, + minBytes - amount, maxBytes - amount, alreadyRead + amount); + }); + } else { + // Read only part of the current chunk. + return inner.tryRead(buffer, minBytes, kj::min(maxBytes, chunkSize)) + .then([=](size_t amount) -> size_t { + chunkSize -= amount; + return alreadyRead + amount; + }); + } + } +}; + +template +struct FastCaseCmp; + +template +struct FastCaseCmp { + static constexpr bool apply(const char* actual) { + return + 'a' <= first && first <= 'z' + ? (*actual | 0x20) == first && FastCaseCmp::apply(actual + 1) + : 'A' <= first && first <= 'Z' + ? (*actual & ~0x20) == first && FastCaseCmp::apply(actual + 1) + : *actual == first && FastCaseCmp::apply(actual + 1); + } +}; + +template <> +struct FastCaseCmp<> { + static constexpr bool apply(const char* actual) { + return *actual == '\0'; + } +}; + +template +constexpr bool fastCaseCmp(const char* actual) { + return FastCaseCmp::apply(actual); +} + +// Tests +static_assert(fastCaseCmp<'f','O','o','B','1'>("FooB1"), ""); +static_assert(!fastCaseCmp<'f','O','o','B','2'>("FooB1"), ""); +static_assert(!fastCaseCmp<'n','O','o','B','1'>("FooB1"), ""); +static_assert(!fastCaseCmp<'f','O','o','B'>("FooB1"), ""); +static_assert(!fastCaseCmp<'f','O','o','B','1','a'>("FooB1"), ""); + +kj::Own HttpInputStream::getEntityBody( + RequestOrResponse type, HttpMethod method, uint statusCode, + HttpHeaders::ConnectionHeaders& connectionHeaders) { + if (type == RESPONSE && (method == HttpMethod::HEAD || + statusCode == 204 || statusCode == 205 || statusCode == 304)) { + // No body. + return kj::heap(*this); + } + + if (connectionHeaders.transferEncoding != nullptr) { + // TODO(someday): Support plugable transfer encodings? Or at least gzip? + // TODO(0.7): Support stacked transfer encodings, e.g. "gzip, chunked". + if (fastCaseCmp<'c','h','u','n','k','e','d'>(connectionHeaders.transferEncoding.cStr())) { + return kj::heap(*this); + } else { + KJ_FAIL_REQUIRE("unknown transfer encoding") { break; } + } + } + + if (connectionHeaders.contentLength != nullptr) { + return kj::heap(*this, + strtoull(connectionHeaders.contentLength.cStr(), nullptr, 10)); + } + + if (type == REQUEST) { + // Lack of a Content-Length or Transfer-Encoding means no body for requests. + return kj::heap(*this); + } + + if (connectionHeaders.connection != nullptr) { + // TODO(0.7): Connection header can actually have multiple tokens... but no one ever uses + // that feature? + if (fastCaseCmp<'c','l','o','s','e'>(connectionHeaders.connection.cStr())) { + return kj::heap(*this); + } + } + + KJ_FAIL_REQUIRE("don't know how HTTP body is delimited", headers); + return kj::heap(*this); +} + +// ======================================================================================= + +class HttpOutputStream { +public: + HttpOutputStream(AsyncOutputStream& inner): inner(inner) {} + + void writeHeaders(String content) { + // Writes some header content and begins a new entity body. + + KJ_REQUIRE(!inBody, "previous HTTP message body incomplete; can't write more messages"); + inBody = true; + + queueWrite(kj::mv(content)); + } + + void writeBodyData(kj::String content) { + KJ_REQUIRE(inBody) { return; } + + queueWrite(kj::mv(content)); + } + + kj::Promise writeBodyData(const void* buffer, size_t size) { + KJ_REQUIRE(inBody) { return kj::READY_NOW; } + + auto fork = writeQueue.then([this,buffer,size]() { + inner.write(buffer, size); + }).fork(); + + writeQueue = fork.addBranch(); + return fork.addBranch(); + } + + kj::Promise writeBodyData(kj::ArrayPtr> pieces) { + KJ_REQUIRE(inBody) { return kj::READY_NOW; } + + auto fork = writeQueue.then([this,pieces]() { + inner.write(pieces); + }).fork(); + + writeQueue = fork.addBranch(); + return fork.addBranch(); + } + + Promise pumpBodyFrom(AsyncInputStream& input, uint64_t amount) { + KJ_REQUIRE(inBody) { return uint64_t(0); } + + auto fork = writeQueue.then([this,&input,amount]() { + return input.pumpTo(inner, amount); + }).fork(); + + writeQueue = fork.addBranch().ignoreResult(); + return fork.addBranch(); + } + + void finishBody() { + // Called when entire body was written. + + KJ_REQUIRE(inBody) { return; } + inBody = false; + } + + void abortBody() { + // Called if the application failed to write all expected body bytes. + KJ_REQUIRE(inBody) { return; } + inBody = false; + + writeQueue = writeQueue.then([]() -> kj::Promise { + return KJ_EXCEPTION(FAILED, + "previous HTTP message body incomplete; can't write more messages"); + }); + } + + kj::Promise flush() { + auto fork = writeQueue.fork(); + writeQueue = fork.addBranch(); + return fork.addBranch(); + } + +private: + AsyncOutputStream& inner; + kj::Promise writeQueue = kj::READY_NOW; + bool inBody = false; + + void queueWrite(kj::String content) { + writeQueue = writeQueue.then(kj::mvCapture(content, [this](kj::String&& content) { + auto promise = inner.write(content.begin(), content.size()); + return promise.attach(kj::mv(content)); + })); + } +}; + +class HttpNullEntityWriter final: public kj::AsyncOutputStream { +public: + Promise write(const void* buffer, size_t size) override { + return KJ_EXCEPTION(FAILED, "HTTP message has no entity-body; can't write()"); + } + Promise write(ArrayPtr> pieces) override { + return KJ_EXCEPTION(FAILED, "HTTP message has no entity-body; can't write()"); + } +}; + +class HttpDiscardingEntityWriter final: public kj::AsyncOutputStream { +public: + Promise write(const void* buffer, size_t size) override { + return kj::READY_NOW; + } + Promise write(ArrayPtr> pieces) override { + return kj::READY_NOW; + } +}; + +class HttpFixedLengthEntityWriter final: public kj::AsyncOutputStream { +public: + HttpFixedLengthEntityWriter(HttpOutputStream& inner, uint64_t length) + : inner(inner), length(length) {} + ~HttpFixedLengthEntityWriter() noexcept(false) { + if (length > 0) inner.abortBody(); + } + + Promise write(const void* buffer, size_t size) override { + KJ_REQUIRE(size <= length, "overwrote Content-Length"); + length -= size; + + return maybeFinishAfter(inner.writeBodyData(buffer, size)); + } + Promise write(ArrayPtr> pieces) override { + uint64_t size = 0; + for (auto& piece: pieces) size += piece.size(); + + KJ_REQUIRE(size <= length, "overwrote Content-Length"); + length -= size; + + return maybeFinishAfter(inner.writeBodyData(pieces)); + } + + Maybe> tryPumpFrom(AsyncInputStream& input, uint64_t amount) override { + KJ_REQUIRE(amount <= length, "overwrote Content-Length"); + length -= amount; + + return inner.pumpBodyFrom(input, amount).then([this,amount](uint64_t actual) { + // Adjust for bytes not written. + length += amount - actual; + if (length == 0) inner.finishBody(); + return actual; + }); + } + +private: + HttpOutputStream& inner; + uint64_t length; + + kj::Promise maybeFinishAfter(kj::Promise promise) { + if (length == 0) { + return promise.then([this]() { inner.finishBody(); }); + } else { + return kj::mv(promise); + } + } +}; + +class HttpChunkedEntityWriter final: public kj::AsyncOutputStream { +public: + HttpChunkedEntityWriter(HttpOutputStream& inner) + : inner(inner) {} + ~HttpChunkedEntityWriter() noexcept(false) { + inner.writeBodyData(kj::str("0\r\n\r\n")); + inner.finishBody(); + } + + Promise write(const void* buffer, size_t size) override { + if (size == 0) return kj::READY_NOW; // can't encode zero-size chunk since it indicates EOF. + + auto header = kj::str(kj::hex(size), "\r\n"); + auto parts = kj::heapArray>(3); + parts[0] = header.asBytes(); + parts[1] = kj::arrayPtr(reinterpret_cast(buffer), size); + parts[2] = kj::StringPtr("\r\n").asBytes(); + + auto promise = inner.writeBodyData(parts.asPtr()); + return promise.attach(kj::mv(header), kj::mv(parts)); + } + + Promise write(ArrayPtr> pieces) override { + uint64_t size = 0; + for (auto& piece: pieces) size += piece.size(); + + if (size == 0) return kj::READY_NOW; // can't encode zero-size chunk since it indicates EOF. + + auto header = kj::str(size, "\r\n"); + auto partsBuilder = kj::heapArrayBuilder>(pieces.size()); + partsBuilder.add(header.asBytes()); + for (auto& piece: pieces) { + partsBuilder.add(piece); + } + partsBuilder.add(kj::StringPtr("\r\n").asBytes()); + + auto parts = partsBuilder.finish(); + auto promise = inner.writeBodyData(parts.asPtr()); + return promise.attach(kj::mv(header), kj::mv(parts)); + } + + Maybe> tryPumpFrom(AsyncInputStream& input, uint64_t amount) override { + KJ_IF_MAYBE(length, input.tryGetLength()) { + // Hey, we know exactly how large the input is, so we can write just one chunk. + + inner.writeBodyData(kj::str(*length, "\r\n")); + auto lengthValue = *length; + return inner.pumpBodyFrom(input, *length) + .then([this,lengthValue](uint64_t actual) { + if (actual < lengthValue) { + inner.abortBody(); + KJ_FAIL_REQUIRE( + "value returned by input.tryGetLength() was greater than actual bytes transferred") { + break; + } + } + + inner.writeBodyData(kj::str("\r\n")); + return actual; + }); + } else { + // Need to use naive read/write loop. + return nullptr; + } + } + +private: + HttpOutputStream& inner; +}; + +// ======================================================================================= + +class HttpClientImpl final: public HttpClient { +public: + HttpClientImpl(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& rawStream) + : httpInput(rawStream, responseHeaderTable), + httpOutput(rawStream) {} + + Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::Maybe expectedBodySize = nullptr) override { + HttpHeaders::ConnectionHeaders connectionHeaders; + kj::String lengthStr; + + if (method == HttpMethod::GET || method == HttpMethod::HEAD) { + // No entity-body. + } else KJ_IF_MAYBE(s, expectedBodySize) { + lengthStr = kj::str(*s); + connectionHeaders.contentLength = lengthStr; + } else { + connectionHeaders.transferEncoding = "chunked"; + } + + httpOutput.writeHeaders(headers.serializeRequest(method, url, connectionHeaders)); + + kj::Own bodyStream; + if (method == HttpMethod::GET || method == HttpMethod::HEAD) { + // No entity-body. + httpOutput.finishBody(); + bodyStream = heap(); + } else KJ_IF_MAYBE(s, expectedBodySize) { + bodyStream = heap(httpOutput, *s); + } else { + bodyStream = heap(httpOutput); + } + + auto responsePromise = httpInput.readResponseHeaders() + .then([this,method](kj::Maybe&& response) -> HttpClient::Response { + KJ_IF_MAYBE(r, response) { + return { + r->statusCode, + r->statusText, + &httpInput.getHeaders(), + httpInput.getEntityBody(HttpInputStream::RESPONSE, method, r->statusCode, + r->connectionHeaders) + }; + } else { + KJ_FAIL_REQUIRE("received invalid HTTP response") { break; } + return HttpClient::Response(); + } + }); + + return { kj::mv(bodyStream), kj::mv(responsePromise) }; + } + +private: + HttpInputStream httpInput; + HttpOutputStream httpOutput; +}; + +} // namespace + +kj::Promise HttpClient::openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, kj::Own downstream) { + return request(HttpMethod::GET, url, headers, nullptr) + .response.then([](HttpClient::Response&& response) -> WebSocketResponse { + kj::OneOf, kj::Own> body; + body.init>(kj::mv(response.body)); + + return { + response.statusCode, + response.statusText, + response.headers, + kj::mv(body) + }; + }); +} + +kj::Promise> HttpClient::connect(kj::String host) { + KJ_UNIMPLEMENTED("CONNECT is not implemented by this HttpClient"); +} + +kj::Own newHttpClient( + HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream) { + return kj::heap(responseHeaderTable, stream); +} + +// ======================================================================================= + +kj::Promise HttpService::openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response) { + class EmptyStream final: public kj::AsyncInputStream { + public: + Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { + return size_t(0); + } + }; + + auto requestBody = heap(); + auto promise = request(HttpMethod::GET, url, headers, *requestBody, response); + return promise.attach(kj::mv(requestBody)); +} + +kj::Promise> HttpService::connect(kj::String host) { + KJ_UNIMPLEMENTED("CONNECT is not implemented by this HttpService"); +} + +class HttpServer::Connection final: private HttpService::Response { +public: + Connection(HttpServer& server, kj::AsyncIoStream& stream) + : server(server), + httpInput(stream, server.requestHeaderTable), + httpOutput(stream) { + ++server.connectionCount; + } + Connection(HttpServer& server, kj::Own&& stream) + : server(server), + httpInput(*stream, server.requestHeaderTable), + httpOutput(*stream), + ownStream(kj::mv(stream)) { + ++server.connectionCount; + } + ~Connection() noexcept(false) { + if (--server.connectionCount == 0) { + KJ_IF_MAYBE(f, server.zeroConnectionsFulfiller) { + f->get()->fulfill(); + } + } + } + + kj::Promise loop() { + // If the timeout promise finishes before the headers do, we kill the connection. + auto timeoutPromise = server.timer.afterDelay(server.settings.headerTimeout) + .then([this]() -> kj::Maybe { + timedOut = true; + return nullptr; + }); + + return httpInput.readRequestHeaders().exclusiveJoin(kj::mv(timeoutPromise)) + .then([this](kj::Maybe&& request) -> kj::Promise { + if (timedOut) { + return sendError(408, "Request Timeout", kj::str( + "ERROR: Your client took too long to send HTTP headers.")); + } + + KJ_IF_MAYBE(req, request) { + currentMethod = req->method; + auto body = httpInput.getEntityBody( + HttpInputStream::REQUEST, req->method, 0, req->connectionHeaders); + + // TODO(perf): If the client disconnects, should we cancel the response? Probably, to + // prevent permanent deadlock. It's slightly weird in that arguably the client should + // be able to shutdown the upstream but still wait on the downstream, but I believe many + // other HTTP servers do similar things. + + auto promise = server.service.request( + req->method, req->url, httpInput.getHeaders(), *body, *this); + return promise.attach(kj::mv(body)) + .then([this]() { return httpOutput.flush(); }) + .then([this]() -> kj::Promise { + // Response done. Await next request. + + if (currentMethod != nullptr) { + return sendError(500, "Internal Server Error", kj::str( + "ERROR: The HttpService did not generate a response.")); + } + + if (server.draining) { + // Never mind, drain time. + return kj::READY_NOW; + } + + auto timeoutPromise = server.timer.afterDelay(server.settings.pipelineTimeout) + .then([]() { return false; }); + auto awaitPromise = httpInput.awaitNextMessage(); + + return timeoutPromise.exclusiveJoin(kj::mv(awaitPromise)) + .then([this](bool hasMore) -> kj::Promise { + if (hasMore) { + return loop(); + } else { + // In this case we assume the client has no more requests, so we simply close the + // connection. + return kj::READY_NOW; + } + }); + }); + } else { + // Bad request. + + return sendError(400, "Bad Request", kj::str( + "ERROR: The headers sent by your client were not valid.")); + } + }).catch_([this](kj::Exception&& e) -> kj::Promise { + // Exception; report 500. + + if (currentMethod == nullptr) { + // Dang, already sent a partial response. Can't do anything else. + KJ_LOG(ERROR, "HttpService threw exception after generating a partial response", + "too late to report error to client", e); + return kj::READY_NOW; + } + + if (e.getType() == kj::Exception::Type::OVERLOADED) { + return sendError(503, "Service Unavailable", kj::str( + "ERROR: The server is temporarily unable to handle your request. Details:\n\n", e)); + } else if (e.getType() == kj::Exception::Type::UNIMPLEMENTED) { + return sendError(501, "Not Implemented", kj::str( + "ERROR: The server does not implement this operation. Details:\n\n", e)); + } else if (e.getType() == kj::Exception::Type::DISCONNECTED) { + // How do we tell an HTTP client that there was a transient network error, and it should + // try again immediately? There's no HTTP status code for this (503 is meant for "try + // again later, not now"). Here's an idea: Don't send any response; just close the + // connection, so that it looks like the connection between the HTTP client and server + // was dropped. A good client should treat this exactly the way we want. + return kj::READY_NOW; + } else { + return sendError(500, "Internal Server Error", kj::str( + "ERROR: The server threw an exception. Details:\n\n", e)); + } + }); + } + +private: + HttpServer& server; + HttpInputStream httpInput; + HttpOutputStream httpOutput; + kj::Own ownStream; + kj::Maybe currentMethod; + bool timedOut = false; + + kj::Own send( + uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, + kj::Maybe expectedBodySize) override { + auto method = KJ_REQUIRE_NONNULL(currentMethod, "already called startResponse()"); + currentMethod = nullptr; + + HttpHeaders::ConnectionHeaders connectionHeaders; + kj::String lengthStr; + + if (statusCode == 204 || statusCode == 205 || statusCode == 304) { + // No entity-body. + } else KJ_IF_MAYBE(s, expectedBodySize) { + lengthStr = kj::str(*s); + connectionHeaders.contentLength = lengthStr; + } else { + connectionHeaders.transferEncoding = "chunked"; + } + + httpOutput.writeHeaders(headers.serializeResponse(statusCode, statusText, connectionHeaders)); + + kj::Own bodyStream; + if (method == HttpMethod::HEAD) { + // Ignore entity-body. + httpOutput.finishBody(); + return heap(); + } else if (statusCode == 204 || statusCode == 205 || statusCode == 304) { + // No entity-body. + httpOutput.finishBody(); + return heap(); + } else KJ_IF_MAYBE(s, expectedBodySize) { + return heap(httpOutput, *s); + } else { + return heap(httpOutput); + } + } + + kj::Promise sendError(uint statusCode, kj::StringPtr statusText, kj::String body) { + auto bodySize = kj::str(body.size()); + + HttpHeaders failed(server.requestHeaderTable); + HttpHeaders::ConnectionHeaders connHeaders; + connHeaders.connection = "close"; + connHeaders.contentLength = bodySize; + + failed.set(HttpHeaderId::CONTENT_TYPE, "text/plain"); + + httpOutput.writeHeaders(failed.serializeResponse(statusCode, statusText, connHeaders)); + httpOutput.writeBodyData(kj::mv(body)); + httpOutput.finishBody(); + return httpOutput.flush(); // loop ends after flush + } +}; + +HttpServer::HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings) + : HttpServer(timer, requestHeaderTable, service, settings, + kj::newPromiseAndFulfiller()) {} + +HttpServer::HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings, kj::PromiseFulfillerPair paf) + : timer(timer), requestHeaderTable(requestHeaderTable), service(service), settings(settings), + onDrain(paf.promise.fork()), drainFulfiller(kj::mv(paf.fulfiller)), tasks(*this) {} + +kj::Promise HttpServer::drain() { + KJ_REQUIRE(!draining, "you can only call drain() once"); + + draining = true; + drainFulfiller->fulfill(); + + if (connectionCount == 0) { + return kj::READY_NOW; + } else { + auto paf = kj::newPromiseAndFulfiller(); + zeroConnectionsFulfiller = kj::mv(paf.fulfiller); + return kj::mv(paf.promise); + } +} + +kj::Promise HttpServer::listenHttp(kj::ConnectionReceiver& port) { + return listenLoop(port).exclusiveJoin(onDrain.addBranch()); +} + +kj::Promise HttpServer::listenLoop(kj::ConnectionReceiver& port) { + return port.accept() + .then([this,&port](kj::Own&& connection) -> kj::Promise { + if (draining) { + // Can get here if we *just* started draining. + return kj::READY_NOW; + } + + tasks.add(listenHttp(kj::mv(connection))); + return listenLoop(port); + }); +} + +kj::Promise HttpServer::listenHttp(kj::Own connection) { + auto obj = heap(*this, kj::mv(connection)); + auto promise = obj->loop(); + + // Eagerly evaluate so that we drop the connection when the promise resolves, even if the caller + // doesn't eagerly evaluate. + return promise.attach(kj::mv(obj)).eagerlyEvaluate(nullptr); +} + +void HttpServer::taskFailed(kj::Exception&& exception) { + KJ_LOG(ERROR, "unhandled exception in HTTP server", exception); +} + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/compat/http.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/compat/http.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,636 @@ +// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_COMPAT_HTTP_H_ +#define KJ_COMPAT_HTTP_H_ +// The KJ HTTP client/server library. +// +// This is a simple library which can be used to implement an HTTP client or server. Properties +// of this library include: +// - Uses KJ async framework. +// - Agnostic to transport layer -- you can provide your own. +// - Header parsing is zero-copy -- it results in strings that point directly into the buffer +// received off the wire. +// - Application code which reads and writes headers refers to headers by symbolic names, not by +// string literals, with lookups being array-index-based, not map-based. To make this possible, +// the application announces what headers it cares about in advance, in order to assign numeric +// values to them. +// - Methods are identified by an enum. + +#include +#include +#include +#include +#include + +namespace kj { + +#define KJ_HTTP_FOR_EACH_METHOD(MACRO) \ + MACRO(GET) \ + MACRO(HEAD) \ + MACRO(POST) \ + MACRO(PUT) \ + MACRO(DELETE) \ + MACRO(PATCH) \ + MACRO(PURGE) \ + MACRO(OPTIONS) \ + MACRO(TRACE) \ + /* standard methods */ \ + /* */ \ + /* (CONNECT is intentionally omitted since it is handled specially in HttpHandler) */ \ + \ + MACRO(COPY) \ + MACRO(LOCK) \ + MACRO(MKCOL) \ + MACRO(MOVE) \ + MACRO(PROPFIND) \ + MACRO(PROPPATCH) \ + MACRO(SEARCH) \ + MACRO(UNLOCK) \ + /* WebDAV */ \ + \ + MACRO(REPORT) \ + MACRO(MKACTIVITY) \ + MACRO(CHECKOUT) \ + MACRO(MERGE) \ + /* Subversion */ \ + \ + MACRO(MSEARCH) \ + MACRO(NOTIFY) \ + MACRO(SUBSCRIBE) \ + MACRO(UNSUBSCRIBE) + /* UPnP */ + +#define KJ_HTTP_FOR_EACH_CONNECTION_HEADER(MACRO) \ + MACRO(connection, "Connection") \ + MACRO(contentLength, "Content-Length") \ + MACRO(keepAlive, "Keep-Alive") \ + MACRO(te, "TE") \ + MACRO(trailer, "Trailer") \ + MACRO(transferEncoding, "Transfer-Encoding") \ + MACRO(upgrade, "Upgrade") + +enum class HttpMethod { + // Enum of known HTTP methods. + // + // We use an enum rather than a string to allow for faster parsing and switching and to reduce + // ambiguity. + +#define DECLARE_METHOD(id) id, +KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD) +#undef DECALRE_METHOD +}; + +kj::StringPtr KJ_STRINGIFY(HttpMethod method); +kj::Maybe tryParseHttpMethod(kj::StringPtr name); + +class HttpHeaderTable; + +class HttpHeaderId { + // Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable. + // + // The KJ HTTP API prefers that headers be identified by these IDs for a few reasons: + // - Integer lookups are much more efficient than string lookups. + // - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup + // method. + // - Writing out strings less often means fewer typos. + // + // See HttpHeaderTable for usage hints. + +public: + HttpHeaderId() = default; + + inline bool operator==(const HttpHeaderId& other) const { return id == other.id; } + inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; } + inline bool operator< (const HttpHeaderId& other) const { return id < other.id; } + inline bool operator> (const HttpHeaderId& other) const { return id > other.id; } + inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; } + inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; } + + inline size_t hashCode() const { return id; } + + kj::StringPtr toString() const; + + void requireFrom(HttpHeaderTable& table) const; + // In debug mode, throws an exception if the HttpHeaderId is not from the given table. + // + // In opt mode, no-op. + +#define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \ + MACRO(HOST, "Host") \ + MACRO(DATE, "Date") \ + MACRO(LOCATION, "Location") \ + MACRO(CONTENT_TYPE, "Content-Type") + // For convenience, these very-common headers are valid for all HttpHeaderTables. You can refer + // to them like: + // + // HttpHeaderId::HOST + // + // TODO(0.7): Fill this out with more common headers. + +#define DECLARE_HEADER(id, name) \ + static const HttpHeaderId id; + // Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION + + KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER); +#undef DECLARE_HEADER + +private: + HttpHeaderTable* table; + uint id; + + inline explicit constexpr HttpHeaderId(HttpHeaderTable* table, uint id): table(table), id(id) {} + friend class HttpHeaderTable; + friend class HttpHeaders; +}; + +class HttpHeaderTable { + // Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and + // to manufacture IDs for them. + // + // Example: + // + // // Build a header table with the headers we are interested in. + // kj::HttpHeaderTable::Builder builder; + // const HttpHeaderId accept = builder.add("Accept"); + // const HttpHeaderId contentType = builder.add("Content-Type"); + // kj::HttpHeaderTable table(kj::mv(builder)); + // + // // Create an HTTP client. + // auto client = kj::newHttpClient(table, network); + // + // // Get http://example.com. + // HttpHeaders headers(table); + // headers.set(accept, "text/html"); + // auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers) + // .wait(waitScope); + // auto msg = kj::str("Response content type: ", response.headers.get(contentType)); + + struct IdsByNameMap; + +public: + HttpHeaderTable(); + // Constructs a table that only contains the builtin headers. + + class Builder { + public: + Builder(); + HttpHeaderId add(kj::StringPtr name); + Own build(); + + HttpHeaderTable& getFutureTable(); + // Get the still-unbuilt header table. You cannot actually use it until build() has been + // called. + // + // This method exists to help when building a shared header table -- the Builder may be passed + // to several components, each of which will register the headers they need and get a reference + // to the future table. + + private: + kj::Own table; + }; + + KJ_DISALLOW_COPY(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table. + ~HttpHeaderTable() noexcept(false); + + uint idCount(); + // Return the number of IDs in the table. + + kj::Maybe stringToId(kj::StringPtr name); + // Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec. + // + // Note: if `name` contains characters that aren't allowed in HTTP header names, this may return + // a bogus value rather than null, due to optimizations used in case-insensitive matching. + + kj::StringPtr idToString(HttpHeaderId id); + // Get the canonical string name for the given ID. + +private: + kj::Vector namesById; + kj::Own idsByName; +}; + +class HttpHeaders { + // Represents a set of HTTP headers. + // + // This class guards against basic HTTP header injection attacks: Trying to set a header name or + // value containing a newline, carriage return, or other invalid character will throw an + // exception. + +public: + explicit HttpHeaders(HttpHeaderTable& table); + + KJ_DISALLOW_COPY(HttpHeaders); + HttpHeaders(HttpHeaders&&) = default; + HttpHeaders& operator=(HttpHeaders&&) = default; + + void clear(); + // Clears all contents, as if the object was freshly-allocated. However, calling this rather + // than actually re-allocating the object may avoid re-allocation of internal objects. + + HttpHeaders clone() const; + // Creates a deep clone of the HttpHeaders. The returned object owns all strings it references. + + HttpHeaders cloneShallow() const; + // Creates a shallow clone of the HttpHeaders. The returned object references the same strings + // as the original, owning none of them. + + kj::Maybe get(HttpHeaderId id) const; + // Read a header. + + template + void forEach(Func&& func) const; + // Calls `func(name, value)` for each header in the set -- including headers that aren't mapped + // to IDs in the header table. Both inputs are of type kj::StringPtr. + + void set(HttpHeaderId id, kj::StringPtr value); + void set(HttpHeaderId id, kj::String&& value); + // Sets a header value, overwriting the existing value. + // + // The String&& version is equivalent to calling the other version followed by takeOwnership(). + // + // WARNING: It is the caller's responsibility to ensure that `value` remains valid until the + // HttpHeaders object is destroyed. This allows string literals to be passed without making a + // copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`. + + void add(kj::StringPtr name, kj::StringPtr value); + void add(kj::StringPtr name, kj::String&& value); + void add(kj::String&& name, kj::String&& value); + // Append a header. `name` will be looked up in the header table, but if it's not mapped, the + // header will be added to the list of unmapped headers. + // + // The String&& versions are equivalent to calling the other version followed by takeOwnership(). + // + // WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid + // until the HttpHeaders object is destroyed. This allows string literals to be passed without + // making a copy, but complicates the use of dynamic values. Hint: Consider using + // `takeOwnership()`. + + void unset(HttpHeaderId id); + // Removes a header. + // + // It's not possible to remove a header by string name because non-indexed headers would take + // O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents. + + void takeOwnership(kj::String&& string); + void takeOwnership(kj::Array&& chars); + void takeOwnership(HttpHeaders&& otherHeaders); + // Takes overship of a string so that it lives until the HttpHeaders object is destroyed. Useful + // when you've passed a dynamic value to set() or add() or parse*(). + + struct ConnectionHeaders { + // These headers govern details of the specific HTTP connection or framing of the content. + // Hence, they are managed internally within the HTTP library, and never appear in an + // HttpHeaders structure. + +#define DECLARE_HEADER(id, name) \ + kj::StringPtr id; + KJ_HTTP_FOR_EACH_CONNECTION_HEADER(DECLARE_HEADER) +#undef DECLARE_HEADER + }; + + struct Request { + HttpMethod method; + kj::StringPtr url; + ConnectionHeaders connectionHeaders; + }; + struct Response { + uint statusCode; + kj::StringPtr statusText; + ConnectionHeaders connectionHeaders; + }; + + kj::Maybe tryParseRequest(kj::ArrayPtr content); + kj::Maybe tryParseResponse(kj::ArrayPtr content); + // Parse an HTTP header blob and add all the headers to this object. + // + // `content` should be all text from the start of the request to the first occurrance of two + // newlines in a row -- including the first of these two newlines, but excluding the second. + // + // The parse is performed with zero copies: The callee clobbers `content` with '\0' characters + // to split it into a bunch of shorter strings. The caller must keep `content` valid until the + // `HttpHeaders` is destroyed, or pass it to `takeOwnership()`. + + kj::String serializeRequest(HttpMethod method, kj::StringPtr url, + const ConnectionHeaders& connectionHeaders) const; + kj::String serializeResponse(uint statusCode, kj::StringPtr statusText, + const ConnectionHeaders& connectionHeaders) const; + // Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines + // and includes the double-newline to indicate the end of the headers. + + kj::String toString() const; + +private: + HttpHeaderTable* table; + + kj::Array indexedHeaders; + // Size is always table->idCount(). + + struct Header { + kj::StringPtr name; + kj::StringPtr value; + }; + kj::Vector

unindexedHeaders; + + kj::Vector> ownedStrings; + + kj::Maybe addNoCheck(kj::StringPtr name, kj::StringPtr value); + + kj::StringPtr cloneToOwn(kj::StringPtr str); + + kj::String serialize(kj::ArrayPtr word1, + kj::ArrayPtr word2, + kj::ArrayPtr word3, + const ConnectionHeaders& connectionHeaders) const; + + bool parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders); + + // TODO(perf): Arguably we should store a map, but header sets are never very long + // TODO(perf): We could optimize for common headers by storing them directly as fields. We could + // also add direct accessors for those headers. +}; + +class WebSocket { +public: + WebSocket(kj::Own stream); + // Create a WebSocket wrapping the given I/O stream. + + kj::Promise send(kj::ArrayPtr message); + kj::Promise send(kj::ArrayPtr message); +}; + +class HttpClient { + // Interface to the client end of an HTTP connection. + // + // There are two kinds of clients: + // * Host clients are used when talking to a specific host. The `url` specified in a request + // is actually just a path. (A `Host` header is still required in all requests.) + // * Proxy clients are used when the target could be any arbitrary host on the internet. + // The `url` specified in a request is a full URL including protocol and hostname. + +public: + struct Response { + uint statusCode; + kj::StringPtr statusText; + const HttpHeaders* headers; + kj::Own body; + // `statusText` and `headers` remain valid until `body` is dropped. + }; + + struct Request { + kj::Own body; + // Write the request entity body to this stream, then drop it when done. + // + // May be null for GET and HEAD requests (which have no body) and requests that have + // Content-Length: 0. + + kj::Promise response; + // Promise for the eventual respnose. + }; + + virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::Maybe expectedBodySize = nullptr) = 0; + // Perform an HTTP request. + // + // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, + // depending on whether the client is a proxy client or a host client. + // + // `url` and `headers` need only remain valid until `request()` returns (they can be + // stack-allocated). + // + // `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to + // the body. This will trigger use of the `Content-Length` connection header. Otherwise, + // `Transfer-Encoding: chunked` will be used. + + struct WebSocketResponse { + uint statusCode; + kj::StringPtr statusText; + const HttpHeaders* headers; + kj::OneOf, kj::Own> upstreamOrBody; + // `statusText` and `headers` remain valid until `upstreamOrBody` is dropped. + }; + virtual kj::Promise openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, kj::Own downstream); + // Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket. + // + // `url` and `headers` are invalidated when the returned promise resolves. + + virtual kj::Promise> connect(kj::String host); + // Handles CONNECT requests. Only relevant for proxy clients. Default implementation throws + // UNIMPLEMENTED. +}; + +class HttpService { + // Interface which HTTP services should implement. + // + // This interface is functionally equivalent to HttpClient, but is intended for applications to + // implement rather than call. The ergonomics and performance of the method signatures are + // optimized for the serving end. + // + // As with clients, there are two kinds of services: + // * Host services are used when talking to a specific host. The `url` specified in a request + // is actually just a path. (A `Host` header is still required in all requests, and the service + // may in fact serve multiple origins via this header.) + // * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to + // implement an HTTP proxy. The `url` specified in a request is a full URL including protocol + // and hostname. + +public: + class Response { + public: + virtual kj::Own send( + uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, + kj::Maybe expectedBodySize = nullptr) = 0; + // Begin the response. + // + // `statusText` and `headers` need only remain valid until send() returns (they can be + // stack-allocated). + }; + + virtual kj::Promise request( + HttpMethod method, kj::StringPtr url, const HttpHeaders& headers, + kj::AsyncInputStream& requestBody, Response& response) = 0; + // Perform an HTTP request. + // + // `url` may be a full URL (with protocol and host) or it may be only the path part of the URL, + // depending on whether the service is a proxy service or a host service. + // + // `url` and `headers` are invalidated on the first read from `requestBody` or when the returned + // promise resolves, whichever comes first. + + class WebSocketResponse: public Response { + public: + kj::Own startWebSocket( + uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers, + WebSocket& upstream); + // Begin the response. + // + // `statusText` and `headers` need only remain valid until startWebSocket() returns (they can + // be stack-allocated). + }; + + virtual kj::Promise openWebSocket( + kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response); + // Tries to open a WebSocket. Default implementation calls request() and never returns a + // WebSocket. + // + // `url` and `headers` are invalidated when the returned promise resolves. + + virtual kj::Promise> connect(kj::String host); + // Handles CONNECT requests. Only relevant for proxy services. Default implementation throws + // UNIMPLEMENTED. +}; + +kj::Own newHttpClient(HttpHeaderTable& responseHeaderTable, kj::Network& network, + kj::Maybe tlsNetwork = nullptr); +// Creates a proxy HttpClient that connects to hosts over the given network. +// +// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table. +// +// `tlsNetwork` is required to support HTTPS destination URLs. Otherwise, only HTTP URLs can be +// fetched. + +kj::Own newHttpClient(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream); +// Creates an HttpClient that speaks over the given pre-established connection. The client may +// be used as a proxy client or a host client depending on whether the peer is operating as +// a proxy. +// +// Note that since this client has only one stream to work with, it will try to pipeline all +// requests on this stream. If one request or response has an I/O failure, all subsequent requests +// fail as well. If the destination server chooses to close the connection after a response, +// subsequent requests will fail. If a response takes a long time, it blocks subsequent responses. +// If a WebSocket is opened successfully, all subsequent requests fail. + +kj::Own newHttpClient(HttpService& service); +kj::Own newHttpService(HttpClient& client); +// Adapts an HttpClient to an HttpService and vice versa. + +struct HttpServerSettings { + kj::Duration headerTimeout = 15 * kj::SECONDS; + // After initial connection open, or after receiving the first byte of a pipelined request, + // the client must send the complete request within this time. + + kj::Duration pipelineTimeout = 5 * kj::SECONDS; + // After one request/response completes, we'll wait up to this long for a pipelined request to + // arrive. +}; + +class HttpServer: private kj::TaskSet::ErrorHandler { + // Class which listens for requests on ports or connections and sends them to an HttpService. + +public: + typedef HttpServerSettings Settings; + + HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings = Settings()); + // Set up an HttpServer that directs incoming connections to the given service. The service + // may be a host service or a proxy service depending on whether you are intending to implement + // an HTTP server or an HTTP proxy. + + kj::Promise drain(); + // Stop accepting new connections or new requests on existing connections. Finish any requests + // that are already executing, then close the connections. Returns once no more requests are + // in-flight. + + kj::Promise listenHttp(kj::ConnectionReceiver& port); + // Accepts HTTP connections on the given port and directs them to the handler. + // + // The returned promise never completes normally. It may throw if port.accept() throws. Dropping + // the returned promise will cause the server to stop listening on the port, but already-open + // connections will continue to be served. Destroy the whole HttpServer to cancel all I/O. + + kj::Promise listenHttp(kj::Own connection); + // Reads HTTP requests from the given connection and directs them to the handler. A successful + // completion of the promise indicates that all requests received on the connection resulted in + // a complete response, and the client closed the connection gracefully or drain() was called. + // The promise throws if an unparseable request is received or if some I/O error occurs. Dropping + // the returned promise will cancel all I/O on the connection and cancel any in-flight requests. + +private: + class Connection; + + kj::Timer& timer; + HttpHeaderTable& requestHeaderTable; + HttpService& service; + Settings settings; + + bool draining = false; + kj::ForkedPromise onDrain; + kj::Own> drainFulfiller; + + uint connectionCount = 0; + kj::Maybe>> zeroConnectionsFulfiller; + + kj::TaskSet tasks; + + HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service, + Settings settings, kj::PromiseFulfillerPair paf); + + kj::Promise listenLoop(kj::ConnectionReceiver& port); + + void taskFailed(kj::Exception&& exception) override; +}; + +// ======================================================================================= +// inline implementation + +inline void HttpHeaderId::requireFrom(HttpHeaderTable& table) const { + KJ_IREQUIRE(this->table == nullptr || this->table == &table, + "the provided HttpHeaderId is from the wrong HttpHeaderTable"); +} + +inline kj::Own HttpHeaderTable::Builder::build() { return kj::mv(table); } +inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; } + +inline uint HttpHeaderTable::idCount() { return namesById.size(); } + +inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) { + id.requireFrom(*this); + return namesById[id.id]; +} + +inline kj::Maybe HttpHeaders::get(HttpHeaderId id) const { + id.requireFrom(*table); + auto result = indexedHeaders[id.id]; + return result == nullptr ? kj::Maybe(nullptr) : result; +} + +inline void HttpHeaders::unset(HttpHeaderId id) { + id.requireFrom(*table); + indexedHeaders[id.id] = nullptr; +} + +template +inline void HttpHeaders::forEach(Func&& func) const { + for (auto i: kj::indices(indexedHeaders)) { + if (indexedHeaders[i] != nullptr) { + func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]); + } + } + + for (auto& header: unindexedHeaders) { + func(header.name, header.value); + } +} + +} // namespace kj + +#endif // KJ_COMPAT_HTTP_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/debug-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/debug-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,431 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "debug.h" +#include "exception.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "miniposix.h" + +#if !_WIN32 +#include +#endif + +#if _MSC_VER +#pragma warning(disable: 4996) +// Warns that sprintf() is buffer-overrunny. Yeah, I know, it's cool. +#endif + +namespace kj { +namespace _ { // private +namespace { + +class MockException {}; + +class MockExceptionCallback: public ExceptionCallback { +public: + ~MockExceptionCallback() {} + + std::string text; + + int outputPipe = -1; + + bool forkForDeathTest() { + // This is called when exceptions are disabled. We fork the process instead and then expect + // the child to die. + +#if _WIN32 + // Windows doesn't support fork() or anything like it. Just skip the test. + return false; + +#else + int pipeFds[2]; + KJ_SYSCALL(pipe(pipeFds)); + pid_t child = fork(); + if (child == 0) { + // This is the child! + close(pipeFds[0]); + outputPipe = pipeFds[1]; + return true; + } else { + close(pipeFds[1]); + + // Read child error messages into our local buffer. + char buf[1024]; + for (;;) { + ssize_t n = read(pipeFds[0], buf, sizeof(buf)); + if (n < 0) { + if (errno == EINTR) { + continue; + } else { + break; + } + } else if (n == 0) { + break; + } else { + text.append(buf, n); + } + } + + close(pipeFds[0]); + + // Get exit status. + int status; + KJ_SYSCALL(waitpid(child, &status, 0)); + + EXPECT_TRUE(WIFEXITED(status)); + EXPECT_EQ(74, WEXITSTATUS(status)); + + return false; + } +#endif // _WIN32, else + } + + void flush() { + if (outputPipe != -1) { + const char* pos = &*text.begin(); + const char* end = pos + text.size(); + + while (pos < end) { + miniposix::ssize_t n = miniposix::write(outputPipe, pos, end - pos); + if (n < 0) { + if (errno == EINTR) { + continue; + } else { + break; // Give up on error. + } + } + pos += n; + } + + text.clear(); + } + } + + void onRecoverableException(Exception&& exception) override { + text += "recoverable exception: "; + auto what = str(exception); + // Discard the stack trace. + const char* end = strstr(what.cStr(), "\nstack: "); + if (end == nullptr) { + text += what.cStr(); + } else { + text.append(what.cStr(), end); + } + text += '\n'; + flush(); + } + + void onFatalException(Exception&& exception) override { + text += "fatal exception: "; + auto what = str(exception); + // Discard the stack trace. + const char* end = strstr(what.cStr(), "\nstack: "); + if (end == nullptr) { + text += what.cStr(); + } else { + text.append(what.cStr(), end); + } + text += '\n'; + flush(); +#if KJ_NO_EXCEPTIONS + if (outputPipe >= 0) { + // This is a child process. We got what we want, now exit quickly without writing any + // additional messages, with a status code that the parent will interpret as "exited in the + // way we expected". + _exit(74); + } +#else + throw MockException(); +#endif + } + + void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) override { + this->text += "log message: "; + text = str(file, ":", line, ":+", contextDepth, ": ", severity, ": ", mv(text)); + this->text.append(text.begin(), text.end()); + } +}; + +#if KJ_NO_EXCEPTIONS +#define EXPECT_FATAL(code) if (mockCallback.forkForDeathTest()) { code; abort(); } +#else +#define EXPECT_FATAL(code) \ + try { code; KJ_FAIL_EXPECT("expected exception"); } \ + catch (MockException e) {} \ + catch (...) { KJ_FAIL_EXPECT("wrong exception"); } +#endif + +std::string fileLine(std::string file, int line) { + file = trimSourceFilename(file.c_str()).cStr(); + + file += ':'; + char buffer[32]; + sprintf(buffer, "%d", line); + file += buffer; + return file; +} + +TEST(Debug, Log) { + MockExceptionCallback mockCallback; + int line; + + KJ_LOG(WARNING, "Hello world!"); line = __LINE__; + EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: warning: Hello world!\n", + mockCallback.text); + mockCallback.text.clear(); + + int i = 123; + const char* str = "foo"; + + KJ_LOG(ERROR, i, str); line = __LINE__; + EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: error: i = 123; str = foo\n", + mockCallback.text); + mockCallback.text.clear(); + + KJ_DBG("Some debug text."); line = __LINE__; + EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: debug: Some debug text.\n", + mockCallback.text); + mockCallback.text.clear(); + + // INFO logging is disabled by default. + KJ_LOG(INFO, "Info."); line = __LINE__; + EXPECT_EQ("", mockCallback.text); + mockCallback.text.clear(); + + // Enable it. + Debug::setLogLevel(Debug::Severity::INFO); + KJ_LOG(INFO, "Some text."); line = __LINE__; + EXPECT_EQ("log message: " + fileLine(__FILE__, line) + ":+0: info: Some text.\n", + mockCallback.text); + mockCallback.text.clear(); + + // Back to default. + Debug::setLogLevel(Debug::Severity::WARNING); + + KJ_ASSERT(1 == 1); + EXPECT_FATAL(KJ_ASSERT(1 == 2)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected " + "1 == 2\n", mockCallback.text); + mockCallback.text.clear(); + + KJ_ASSERT(1 == 1) { + ADD_FAILURE() << "Shouldn't call recovery code when check passes."; + break; + }; + + bool recovered = false; + KJ_ASSERT(1 == 2, "1 is not 2") { recovered = true; break; } line = __LINE__; + EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + ": failed: expected " + "1 == 2; 1 is not 2\n", mockCallback.text); + EXPECT_TRUE(recovered); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_ASSERT(1 == 2, i, "hi", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected " + "1 == 2; i = 123; hi; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_REQUIRE(1 == 2, i, "hi", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: expected " + "1 == 2; i = 123; hi; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_FAIL_ASSERT("foo")); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": failed: foo\n", + mockCallback.text); + mockCallback.text.clear(); +} + +TEST(Debug, Exception) { + int i = 123; + + int line = __LINE__; Exception exception = KJ_EXCEPTION(DISCONNECTED, "foo", i); + + EXPECT_EQ(Exception::Type::DISCONNECTED, exception.getType()); + EXPECT_TRUE(kj::StringPtr(__FILE__).endsWith(exception.getFile())); + EXPECT_EQ(line, exception.getLine()); + EXPECT_EQ("foo; i = 123", exception.getDescription()); +} + +TEST(Debug, Catch) { + int line; + + { + // Catch recoverable as kj::Exception. + Maybe exception = kj::runCatchingExceptions([&](){ + line = __LINE__; KJ_FAIL_ASSERT("foo") { break; } + }); + + KJ_IF_MAYBE(e, exception) { + String what = str(*e); + KJ_IF_MAYBE(eol, what.findFirst('\n')) { + what = kj::str(what.slice(0, *eol)); + } + std::string text(what.cStr()); + EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text); + } else { + ADD_FAILURE() << "Expected exception."; + } + } + +#if !KJ_NO_EXCEPTIONS + { + // Catch fatal as kj::Exception. + Maybe exception = kj::runCatchingExceptions([&](){ + line = __LINE__; KJ_FAIL_ASSERT("foo"); + }); + + KJ_IF_MAYBE(e, exception) { + String what = str(*e); + KJ_IF_MAYBE(eol, what.findFirst('\n')) { + what = kj::str(what.slice(0, *eol)); + } + std::string text(what.cStr()); + EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text); + } else { + ADD_FAILURE() << "Expected exception."; + } + } + + { + // Catch as std::exception. + try { + line = __LINE__; KJ_FAIL_ASSERT("foo"); + ADD_FAILURE() << "Expected exception."; + } catch (const std::exception& e) { + kj::StringPtr what = e.what(); + std::string text; + KJ_IF_MAYBE(eol, what.findFirst('\n')) { + text.assign(what.cStr(), *eol); + } else { + text.assign(what.cStr()); + } + EXPECT_EQ(fileLine(__FILE__, line) + ": failed: foo", text); + } + } +#endif +} + +int mockSyscall(int i, int error = 0) { + errno = error; + return i; +} + +TEST(Debug, Syscall) { + MockExceptionCallback mockCallback; + int line; + + int i = 123; + const char* str = "foo"; + + KJ_SYSCALL(mockSyscall(0)); + KJ_SYSCALL(mockSyscall(1)); + + EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, EBADF), i, "bar", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + + ": failed: mockSyscall(-1, EBADF): " + strerror(EBADF) + + "; i = 123; bar; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ECONNRESET), i, "bar", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + + ": disconnected: mockSyscall(-1, ECONNRESET): " + strerror(ECONNRESET) + + "; i = 123; bar; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ENOMEM), i, "bar", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + + ": overloaded: mockSyscall(-1, ENOMEM): " + strerror(ENOMEM) + + "; i = 123; bar; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, ENOSYS), i, "bar", str)); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + + ": unimplemented: mockSyscall(-1, ENOSYS): " + strerror(ENOSYS) + + "; i = 123; bar; str = foo\n", mockCallback.text); + mockCallback.text.clear(); + + int result = 0; + bool recovered = false; + KJ_SYSCALL(result = mockSyscall(-2, EBADF), i, "bar", str) { recovered = true; break; } line = __LINE__; + EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + + ": failed: mockSyscall(-2, EBADF): " + strerror(EBADF) + + "; i = 123; bar; str = foo\n", mockCallback.text); + EXPECT_EQ(-2, result); + EXPECT_TRUE(recovered); +} + +TEST(Debug, Context) { + MockExceptionCallback mockCallback; + + { + KJ_CONTEXT("foo"); int cline = __LINE__; + + KJ_LOG(WARNING, "blah"); int line = __LINE__; + EXPECT_EQ("log message: " + fileLine(__FILE__, cline) + ":+0: context: foo\n" + "log message: " + fileLine(__FILE__, line) + ":+1: warning: blah\n", + mockCallback.text); + mockCallback.text.clear(); + + EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__; + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n" + + fileLine(__FILE__, line) + ": failed: bar\n", + mockCallback.text); + mockCallback.text.clear(); + + { + int i = 123; + const char* str = "qux"; + KJ_CONTEXT("baz", i, "corge", str); int cline2 = __LINE__; + EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__; + + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n" + + fileLine(__FILE__, cline2) + ": context: baz; i = 123; corge; str = qux\n" + + fileLine(__FILE__, line) + ": failed: bar\n", + mockCallback.text); + mockCallback.text.clear(); + } + + { + KJ_CONTEXT("grault"); int cline2 = __LINE__; + EXPECT_FATAL(KJ_FAIL_ASSERT("bar")); line = __LINE__; + + EXPECT_EQ("fatal exception: " + fileLine(__FILE__, cline) + ": context: foo\n" + + fileLine(__FILE__, cline2) + ": context: grault\n" + + fileLine(__FILE__, line) + ": failed: bar\n", + mockCallback.text); + mockCallback.text.clear(); + } + } +} + +} // namespace +} // namespace _ (private) +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/debug.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/debug.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,439 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "debug.h" +#include +#include +#include +#include + +#if _WIN32 +#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) +#define NOMINMAX 1 +#define WIN32_LEAN_AND_MEAN 1 +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#include +#include "windows-sanity.h" +#endif + +namespace kj { +namespace _ { // private + +LogSeverity Debug::minSeverity = LogSeverity::WARNING; + +namespace { + +Exception::Type typeOfErrno(int error) { + switch (error) { +#ifdef EDQUOT + case EDQUOT: +#endif +#ifdef EMFILE + case EMFILE: +#endif +#ifdef ENFILE + case ENFILE: +#endif +#ifdef ENOBUFS + case ENOBUFS: +#endif +#ifdef ENOLCK + case ENOLCK: +#endif +#ifdef ENOMEM + case ENOMEM: +#endif +#ifdef ENOSPC + case ENOSPC: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#endif +#ifdef EUSERS + case EUSERS: +#endif + return Exception::Type::OVERLOADED; + +#ifdef ENOTCONN + case ENOTCONN: +#endif +#ifdef ECONNABORTED + case ECONNABORTED: +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: +#endif +#ifdef ECONNRESET + case ECONNRESET: +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: +#endif +#ifdef ENETDOWN + case ENETDOWN: +#endif +#ifdef ENETRESET + case ENETRESET: +#endif +#ifdef ENETUNREACH + case ENETUNREACH: +#endif +#ifdef ENONET + case ENONET: +#endif +#ifdef EPIPE + case EPIPE: +#endif + return Exception::Type::DISCONNECTED; + +#ifdef ENOSYS + case ENOSYS: +#endif +#ifdef ENOTSUP + case ENOTSUP: +#endif +#if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOTSUP + case EOPNOTSUPP: +#endif +#ifdef ENOPROTOOPT + case ENOPROTOOPT: +#endif +#ifdef ENOTSOCK + // This is really saying "syscall not implemented for non-sockets". + case ENOTSOCK: +#endif + return Exception::Type::UNIMPLEMENTED; + + default: + return Exception::Type::FAILED; + } +} + +#if _WIN32 + +Exception::Type typeOfWin32Error(DWORD error) { + switch (error) { + // TODO(0.7): This needs more work. + + case WSAETIMEDOUT: + return Exception::Type::OVERLOADED; + + case WSAENOTCONN: + case WSAECONNABORTED: + case WSAECONNREFUSED: + case WSAECONNRESET: + case WSAEHOSTDOWN: + case WSAEHOSTUNREACH: + case WSAENETDOWN: + case WSAENETRESET: + case WSAENETUNREACH: + case WSAESHUTDOWN: + return Exception::Type::DISCONNECTED; + + case WSAEOPNOTSUPP: + case WSAENOPROTOOPT: + case WSAENOTSOCK: // This is really saying "syscall not implemented for non-sockets". + return Exception::Type::UNIMPLEMENTED; + + default: + return Exception::Type::FAILED; + } +} + +#endif // _WIN32 + +enum DescriptionStyle { + LOG, + ASSERTION, + SYSCALL +}; + +static String makeDescriptionImpl(DescriptionStyle style, const char* code, int errorNumber, + const char* sysErrorString, const char* macroArgs, + ArrayPtr argValues) { + KJ_STACK_ARRAY(ArrayPtr, argNames, argValues.size(), 8, 64); + + if (argValues.size() > 0) { + size_t index = 0; + const char* start = macroArgs; + while (isspace(*start)) ++start; + const char* pos = start; + uint depth = 0; + bool quoted = false; + while (char c = *pos++) { + if (quoted) { + if (c == '\\' && *pos != '\0') { + ++pos; + } else if (c == '\"') { + quoted = false; + } + } else { + if (c == '(') { + ++depth; + } else if (c == ')') { + --depth; + } else if (c == '\"') { + quoted = true; + } else if (c == ',' && depth == 0) { + if (index < argValues.size()) { + argNames[index] = arrayPtr(start, pos - 1); + } + ++index; + while (isspace(*pos)) ++pos; + start = pos; + } + } + } + if (index < argValues.size()) { + argNames[index] = arrayPtr(start, pos - 1); + } + ++index; + + if (index != argValues.size()) { + getExceptionCallback().logMessage(LogSeverity::ERROR, __FILE__, __LINE__, 0, + str("Failed to parse logging macro args into ", + argValues.size(), " names: ", macroArgs, '\n')); + } + } + + if (style == SYSCALL) { + // Strip off leading "foo = " from code, since callers will sometimes write things like: + // ssize_t n; + // RECOVERABLE_SYSCALL(n = read(fd, buffer, sizeof(buffer))) { return ""; } + // return std::string(buffer, n); + const char* equalsPos = strchr(code, '='); + if (equalsPos != nullptr && equalsPos[1] != '=') { + code = equalsPos + 1; + while (isspace(*code)) ++code; + } + } + + if (style == ASSERTION && code == nullptr) { + style = LOG; + } + + { + StringPtr expected = "expected "; + StringPtr codeArray = style == LOG ? nullptr : StringPtr(code); + StringPtr sep = " = "; + StringPtr delim = "; "; + StringPtr colon = ": "; + + StringPtr sysErrorArray; +#if __USE_GNU + char buffer[256]; + if (style == SYSCALL) { + if (sysErrorString == nullptr) { + sysErrorArray = strerror_r(errorNumber, buffer, sizeof(buffer)); + } else { + sysErrorArray = sysErrorString; + } + } +#else + char buffer[256]; + if (style == SYSCALL) { + if (sysErrorString == nullptr) { + strerror_r(errorNumber, buffer, sizeof(buffer)); + sysErrorArray = buffer; + } else { + sysErrorArray = sysErrorString; + } + } +#endif + + size_t totalSize = 0; + switch (style) { + case LOG: + break; + case ASSERTION: + totalSize += expected.size() + codeArray.size(); + break; + case SYSCALL: + totalSize += codeArray.size() + colon.size() + sysErrorArray.size(); + break; + } + + for (size_t i = 0; i < argValues.size(); i++) { + if (i > 0 || style != LOG) { + totalSize += delim.size(); + } + if (argNames[i].size() > 0 && argNames[i][0] != '\"') { + totalSize += argNames[i].size() + sep.size(); + } + totalSize += argValues[i].size(); + } + + String result = heapString(totalSize); + char* pos = result.begin(); + + switch (style) { + case LOG: + break; + case ASSERTION: + pos = _::fill(pos, expected, codeArray); + break; + case SYSCALL: + pos = _::fill(pos, codeArray, colon, sysErrorArray); + break; + } + + for (size_t i = 0; i < argValues.size(); i++) { + if (i > 0 || style != LOG) { + pos = _::fill(pos, delim); + } + if (argNames[i].size() > 0 && argNames[i][0] != '\"') { + pos = _::fill(pos, argNames[i], sep); + } + pos = _::fill(pos, argValues[i]); + } + + return result; + } +} + +} // namespace + +void Debug::logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs, + ArrayPtr argValues) { + getExceptionCallback().logMessage(severity, trimSourceFilename(file).cStr(), line, 0, + makeDescriptionImpl(LOG, nullptr, 0, nullptr, macroArgs, argValues)); +} + +Debug::Fault::~Fault() noexcept(false) { + if (exception != nullptr) { + Exception copy = mv(*exception); + delete exception; + throwRecoverableException(mv(copy), 2); + } +} + +void Debug::Fault::fatal() { + Exception copy = mv(*exception); + delete exception; + exception = nullptr; + throwFatalException(mv(copy), 2); + abort(); +} + +void Debug::Fault::init( + const char* file, int line, Exception::Type type, + const char* condition, const char* macroArgs, ArrayPtr argValues) { + exception = new Exception(type, file, line, + makeDescriptionImpl(ASSERTION, condition, 0, nullptr, macroArgs, argValues)); +} + +void Debug::Fault::init( + const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues) { + exception = new Exception(typeOfErrno(osErrorNumber), file, line, + makeDescriptionImpl(SYSCALL, condition, osErrorNumber, nullptr, macroArgs, argValues)); +} + +#if _WIN32 +void Debug::Fault::init( + const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues) { + LPVOID ptr; + // TODO(0.7): Use FormatMessageW() instead. + // TODO(0.7): Why doesn't this work for winsock errors? + DWORD result = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, osErrorNumber.number, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &ptr, 0, NULL); + + if (result > 0) { + KJ_DEFER(LocalFree(ptr)); + exception = new Exception(typeOfWin32Error(osErrorNumber.number), file, line, + makeDescriptionImpl(SYSCALL, condition, 0, reinterpret_cast(ptr), + macroArgs, argValues)); + } else { + auto message = kj::str("win32 error code: ", osErrorNumber.number); + exception = new Exception(typeOfWin32Error(osErrorNumber.number), file, line, + makeDescriptionImpl(SYSCALL, condition, 0, message.cStr(), + macroArgs, argValues)); + } +} +#endif + +String Debug::makeDescriptionInternal(const char* macroArgs, ArrayPtr argValues) { + return makeDescriptionImpl(LOG, nullptr, 0, nullptr, macroArgs, argValues); +} + +int Debug::getOsErrorNumber(bool nonblocking) { + int result = errno; + + // On many systems, EAGAIN and EWOULDBLOCK have the same value, but this is not strictly required + // by POSIX, so we need to check both. + return result == EINTR ? -1 + : nonblocking && (result == EAGAIN || result == EWOULDBLOCK) ? 0 + : result; +} + +#if _WIN32 +Debug::Win32Error Debug::getWin32Error() { + return Win32Error(::GetLastError()); +} +#endif + +Debug::Context::Context(): logged(false) {} +Debug::Context::~Context() noexcept(false) {} + +Debug::Context::Value Debug::Context::ensureInitialized() { + KJ_IF_MAYBE(v, value) { + return Value(v->file, v->line, heapString(v->description)); + } else { + Value result = evaluate(); + value = Value(result.file, result.line, heapString(result.description)); + return result; + } +} + +void Debug::Context::onRecoverableException(Exception&& exception) { + Value v = ensureInitialized(); + exception.wrapContext(v.file, v.line, mv(v.description)); + next.onRecoverableException(kj::mv(exception)); +} +void Debug::Context::onFatalException(Exception&& exception) { + Value v = ensureInitialized(); + exception.wrapContext(v.file, v.line, mv(v.description)); + next.onFatalException(kj::mv(exception)); +} +void Debug::Context::logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) { + if (!logged) { + Value v = ensureInitialized(); + next.logMessage(LogSeverity::INFO, v.file, v.line, 0, + str("context: ", mv(v.description), '\n')); + logged = true; + } + + next.logMessage(severity, file, line, contextDepth + 1, mv(text)); +} + +} // namespace _ (private) +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/debug.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,555 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This file declares convenient macros for debug logging and error handling. The macros make +// it excessively easy to extract useful context information from code. Example: +// +// KJ_ASSERT(a == b, a, b, "a and b must be the same."); +// +// On failure, this will throw an exception whose description looks like: +// +// myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same. +// +// As you can see, all arguments after the first provide additional context. +// +// The macros available are: +// +// * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can +// intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`, +// `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the +// user should be able to pass a flag like `--verbose` to enable them. Other log levels are +// enabled by default. Log messages -- like exceptions -- can be intercepted by registering an +// ExceptionCallback. +// +// * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while +// debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing +// code. It is suggested that you set up a pre-commit hook that checks for this. +// +// * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if +// exceptions are disabled. This macro should be used to check for bugs in the surrounding code +// and its dependencies, but NOT to check for invalid input. The macro may be followed by a +// brace-delimited code block; if so, the block will be executed in the case where the assertion +// fails, before throwing the exception. If control jumps out of the block (e.g. with "break", +// "return", or "goto"), then the error is considered "recoverable" -- in this case, if +// exceptions are disabled, execution will continue normally rather than aborting (but if +// exceptions are enabled, an exception will still be thrown on exiting the block). A "break" +// statement in particular will jump to the code immediately after the block (it does not break +// any surrounding loop or switch). Example: +// +// KJ_ASSERT(value >= 0, "Value cannot be negative.", value) { +// // Assertion failed. Set value to zero to "recover". +// value = 0; +// // Don't abort if exceptions are disabled. Continue normally. +// // (Still throw an exception if they are enabled, though.) +// break; +// } +// // When exceptions are disabled, we'll get here even if the assertion fails. +// // Otherwise, we get here only if the assertion passes. +// +// * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to +// validate parameters passed from a caller. A failure indicates that the caller is buggy. +// +// * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result +// is considered an error, with error code reported via `errno`. EINTR is handled by retrying. +// Other errors are handled by throwing an exception. If you need to examine the return code, +// assign it to a variable like so: +// +// int fd; +// KJ_SYSCALL(fd = open(filename, O_RDONLY), filename); +// +// `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`. +// +// * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on +// EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it +// indicates an error; in this case, it can assume the error was EAGAIN because any other error +// would have caused an exception to be thrown. +// +// * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown +// from within the current scope. That is, until control exits the block in which KJ_CONTEXT() +// is used, if any exception is generated, it will contain the given information in its context +// chain. This is helpful because it can otherwise be very difficult to come up with error +// messages that make sense within low-level helper code. Note that the parameters to +// KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables +// used must remain valid until the end of the scope. +// +// Notes: +// * Do not write expressions with side-effects in the message content part of the macro, as the +// message will not necessarily be evaluated. +// * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report +// failures that already happened. For the macros that check a boolean condition, `FAIL_FOO` +// omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and +// `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters. +// The string should be the name of the failed system call. +// * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only +// executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically +// by common.h when compiling without optimization (unless NDEBUG is defined), but you can also +// define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG +// as it may enable expensive checks that are unlikely to fail. + +#ifndef KJ_DEBUG_H_ +#define KJ_DEBUG_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "string.h" +#include "exception.h" + +#ifdef ERROR +// This is problematic because windows.h #defines ERROR, which we use in an enum here. +#error "Make sure to to undefine ERROR (or just #include ) before this file" +#endif + +namespace kj { + +#if _MSC_VER +// MSVC does __VA_ARGS__ differently from GCC: +// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants +// you to request this behavior with "##__VA_ARGS__". +// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a +// *single* argument rather than an argument list. This can be worked around by wrapping the +// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before +// the macro is evaluated. I don't understand the C preprocessor. +// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is +// empty, rather than expanding to an empty string literal. We can work around by concatenating +// with an empty string literal. + +#define KJ_EXPAND(X) X + +#define KJ_LOG(severity, ...) \ + if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ + ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ + "" #__VA_ARGS__, __VA_ARGS__) + +#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__)) + +#define KJ_REQUIRE(cond, ...) \ + if (KJ_LIKELY(cond)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_REQUIRE(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_NONBLOCKING_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#if _WIN32 + +#define KJ_WIN32(call, ...) \ + if (::kj::_::Debug::isWin32Success(call)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_WINSOCK(call, ...) \ + if ((call) != SOCKET_ERROR) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_WIN32(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +#endif + +#define KJ_UNIMPLEMENTED(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ + nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal()) + +// TODO(msvc): MSVC mis-deduces `ContextImpl` as `ContextImpl` in some edge +// cases, such as inside nested lambdas inside member functions. Wrapping the type in +// `decltype(instance<...>())` helps it deduce the context function's type correctly. +#define KJ_CONTEXT(...) \ + auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ + return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \ + }; \ + decltype(::kj::instance<::kj::_::Debug::ContextImpl>()) \ + KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) + +#define KJ_REQUIRE_NONNULL(value, ...) \ + (*[&] { \ + auto _kj_result = ::kj::_::readMaybe(value); \ + if (KJ_UNLIKELY(!_kj_result)) { \ + ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \ + } \ + return _kj_result; \ + }()) + +#define KJ_EXCEPTION(type, ...) \ + ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)) + +#else + +#define KJ_LOG(severity, ...) \ + if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \ + ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \ + #__VA_ARGS__, ##__VA_ARGS__) + +#define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__) + +#define KJ_REQUIRE(cond, ...) \ + if (KJ_LIKELY(cond)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_REQUIRE(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_NONBLOCKING_SYSCALL(call, ...) \ + if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#if _WIN32 + +#define KJ_WIN32(call, ...) \ + if (::kj::_::Debug::isWin32Success(call)) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_WINSOCK(call, ...) \ + if ((call) != SOCKET_ERROR) {} else \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_FAIL_WIN32(code, errorNumber, ...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \ + ::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#endif + +#define KJ_UNIMPLEMENTED(...) \ + for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \ + nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal()) + +#define KJ_CONTEXT(...) \ + auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \ + return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \ + }; \ + ::kj::_::Debug::ContextImpl \ + KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc)) + +#define KJ_REQUIRE_NONNULL(value, ...) \ + (*({ \ + auto _kj_result = ::kj::_::readMaybe(value); \ + if (KJ_UNLIKELY(!_kj_result)) { \ + ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \ + #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \ + } \ + kj::mv(_kj_result); \ + })) + +#define KJ_EXCEPTION(type, ...) \ + ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \ + ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)) + +#endif + +#define KJ_SYSCALL_HANDLE_ERRORS(call) \ + if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \ + switch (int error = _kjSyscallError) +// Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the +// error. Additionally, the int value `error` is defined within the block. So you can do: +// +// KJ_SYSCALL_HANDLE_ERRORS(foo()) { +// case ENOENT: +// handleNoSuchFile(); +// break; +// case EEXIST: +// handleExists(); +// break; +// default: +// KJ_FAIL_SYSCALL("foo()", error); +// } else { +// handleSuccessCase(); +// } + +#define KJ_ASSERT KJ_REQUIRE +#define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE +#define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL +// Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code. +// That is, if the assert ever fails, it indicates that the immediate surrounding code is broken. + +#ifdef KJ_DEBUG +#define KJ_DLOG KJ_LOG +#define KJ_DASSERT KJ_ASSERT +#define KJ_DREQUIRE KJ_REQUIRE +#else +#define KJ_DLOG(...) do {} while (false) +#define KJ_DASSERT(...) do {} while (false) +#define KJ_DREQUIRE(...) do {} while (false) +#endif + +namespace _ { // private + +class Debug { +public: + Debug() = delete; + + typedef LogSeverity Severity; // backwards-compatibility + +#if _WIN32 + struct Win32Error { + // Hack for overloading purposes. + uint number; + inline explicit Win32Error(uint number): number(number) {} + }; +#endif + + static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; } + // Returns whether messages of the given severity should be logged. + + static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; } + // Set the minimum message severity which will be logged. + // + // TODO(someday): Expose publicly. + + template + static void log(const char* file, int line, LogSeverity severity, const char* macroArgs, + Params&&... params); + + class Fault { + public: + template + Fault(const char* file, int line, Code code, + const char* condition, const char* macroArgs, Params&&... params); + Fault(const char* file, int line, Exception::Type type, + const char* condition, const char* macroArgs); + Fault(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs); +#if _WIN32 + Fault(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs); +#endif + ~Fault() noexcept(false); + + KJ_NOINLINE KJ_NORETURN(void fatal()); + // Throw the exception. + + private: + void init(const char* file, int line, Exception::Type type, + const char* condition, const char* macroArgs, ArrayPtr argValues); + void init(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues); +#if _WIN32 + void init(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs, ArrayPtr argValues); +#endif + + Exception* exception; + }; + + class SyscallResult { + public: + inline SyscallResult(int errorNumber): errorNumber(errorNumber) {} + inline operator void*() { return errorNumber == 0 ? this : nullptr; } + inline int getErrorNumber() { return errorNumber; } + + private: + int errorNumber; + }; + + template + static SyscallResult syscall(Call&& call, bool nonblocking); + template + static int syscallError(Call&& call, bool nonblocking); + +#if _WIN32 + static bool isWin32Success(int boolean); + static bool isWin32Success(void* handle); + static Win32Error getWin32Error(); +#endif + + class Context: public ExceptionCallback { + public: + Context(); + KJ_DISALLOW_COPY(Context); + virtual ~Context() noexcept(false); + + struct Value { + const char* file; + int line; + String description; + + inline Value(const char* file, int line, String&& description) + : file(file), line(line), description(mv(description)) {} + }; + + virtual Value evaluate() = 0; + + virtual void onRecoverableException(Exception&& exception) override; + virtual void onFatalException(Exception&& exception) override; + virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) override; + + private: + bool logged; + Maybe value; + + Value ensureInitialized(); + }; + + template + class ContextImpl: public Context { + public: + inline ContextImpl(Func& func): func(func) {} + KJ_DISALLOW_COPY(ContextImpl); + + Value evaluate() override { + return func(); + } + private: + Func& func; + }; + + template + static String makeDescription(const char* macroArgs, Params&&... params); + +private: + static LogSeverity minSeverity; + + static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs, + ArrayPtr argValues); + static String makeDescriptionInternal(const char* macroArgs, ArrayPtr argValues); + + static int getOsErrorNumber(bool nonblocking); + // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR. +}; + +template +void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs, + Params&&... params) { + String argValues[sizeof...(Params)] = {str(params)...}; + logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params))); +} + +template <> +inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) { + logInternal(file, line, severity, macroArgs, nullptr); +} + +template +Debug::Fault::Fault(const char* file, int line, Code code, + const char* condition, const char* macroArgs, Params&&... params) + : exception(nullptr) { + String argValues[sizeof...(Params)] = {str(params)...}; + init(file, line, code, condition, macroArgs, + arrayPtr(argValues, sizeof...(Params))); +} + +inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, osErrorNumber, condition, macroArgs, nullptr); +} + +inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, type, condition, macroArgs, nullptr); +} + +#if _WIN32 +inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber, + const char* condition, const char* macroArgs) + : exception(nullptr) { + init(file, line, osErrorNumber, condition, macroArgs, nullptr); +} + +inline bool Debug::isWin32Success(int boolean) { + return boolean; +} +inline bool Debug::isWin32Success(void* handle) { + // Assume null and INVALID_HANDLE_VALUE mean failure. + return handle != nullptr && handle != (void*)-1; +} +#endif + +template +Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) { + while (call() < 0) { + int errorNum = getOsErrorNumber(nonblocking); + // getOsErrorNumber() returns -1 to indicate EINTR. + // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a + // non-error. + if (errorNum != -1) { + return SyscallResult(errorNum); + } + } + return SyscallResult(0); +} + +template +int Debug::syscallError(Call&& call, bool nonblocking) { + while (call() < 0) { + int errorNum = getOsErrorNumber(nonblocking); + // getOsErrorNumber() returns -1 to indicate EINTR. + // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a + // non-error. + if (errorNum != -1) { + return errorNum; + } + } + return 0; +} + +template +String Debug::makeDescription(const char* macroArgs, Params&&... params) { + String argValues[sizeof...(Params)] = {str(params)...}; + return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params))); +} + +template <> +inline String Debug::makeDescription<>(const char* macroArgs) { + return makeDescriptionInternal(macroArgs, nullptr); +} + +} // namespace _ (private) +} // namespace kj + +#endif // KJ_DEBUG_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/exception-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/exception-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,143 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "exception.h" +#include "debug.h" +#include + +namespace kj { +namespace _ { // private +namespace { + +TEST(Exception, TrimSourceFilename) { +#if _WIN32 + if (trimSourceFilename(__FILE__) != "kj\\exception-test.c++") +#endif + EXPECT_EQ(trimSourceFilename(__FILE__), "kj/exception-test.c++"); +} + +TEST(Exception, RunCatchingExceptions) { + bool recovered = false; + Maybe e = kj::runCatchingExceptions([&]() { + KJ_FAIL_ASSERT("foo") { + break; + } + recovered = true; + }); + +#if KJ_NO_EXCEPTIONS + EXPECT_TRUE(recovered); +#else + EXPECT_FALSE(recovered); +#endif + + KJ_IF_MAYBE(ex, e) { + EXPECT_EQ("foo", ex->getDescription()); + } else { + ADD_FAILURE() << "Expected exception"; + } +} + +#if !KJ_NO_EXCEPTIONS +// We skip this test when exceptions are disabled because making it no-exceptions-safe defeats +// the purpose of the test: recoverable exceptions won't throw inside a destructor in the first +// place. + +class ThrowingDestructor: public UnwindDetector { +public: + ~ThrowingDestructor() noexcept(false) { + catchExceptionsIfUnwinding([]() { + KJ_FAIL_ASSERT("this is a test, not a real bug"); + }); + } +}; + +TEST(Exception, UnwindDetector) { + // If no other exception is happening, ThrowingDestructor's destructor throws one. + Maybe e = kj::runCatchingExceptions([&]() { + ThrowingDestructor t; + }); + + KJ_IF_MAYBE(ex, e) { + EXPECT_EQ("this is a test, not a real bug", ex->getDescription()); + } else { + ADD_FAILURE() << "Expected exception"; + } + + // If another exception is happening, ThrowingDestructor's destructor's exception is squelched. + e = kj::runCatchingExceptions([&]() { + ThrowingDestructor t; + KJ_FAIL_ASSERT("baz") { + break; + } + }); + + KJ_IF_MAYBE(ex, e) { + EXPECT_EQ("baz", ex->getDescription()); + } else { + ADD_FAILURE() << "Expected exception"; + } +} +#endif + +#if !__MINGW32__ // Inexplicably crashes when exception is thrown from constructor. +TEST(Exception, ExceptionCallbackMustBeOnStack) { + KJ_EXPECT_THROW_MESSAGE("must be allocated on the stack", new ExceptionCallback); +} +#endif // !__MINGW32__ + +#if !KJ_NO_EXCEPTIONS +TEST(Exception, ScopeSuccessFail) { + bool success = false; + bool failure = false; + + { + KJ_ON_SCOPE_SUCCESS(success = true); + KJ_ON_SCOPE_FAILURE(failure = true); + + EXPECT_FALSE(success); + EXPECT_FALSE(failure); + } + + EXPECT_TRUE(success); + EXPECT_FALSE(failure); + + success = false; + failure = false; + + try { + KJ_ON_SCOPE_SUCCESS(success = true); + KJ_ON_SCOPE_FAILURE(failure = true); + + EXPECT_FALSE(success); + EXPECT_FALSE(failure); + + throw 1; + } catch (int) {} + + EXPECT_FALSE(success); + EXPECT_TRUE(failure); +} +#endif + +} // namespace +} // namespace _ (private) +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/exception.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/exception.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,875 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "exception.h" +#include "string.h" +#include "debug.h" +#include "threadlocal.h" +#include "miniposix.h" +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include "io.h" + +#if (__linux__ && __GLIBC__) || __APPLE__ +#define KJ_HAS_BACKTRACE 1 +#include +#endif + +#if _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include "windows-sanity.h" +#include +#endif + +#if (__linux__ || __APPLE__) +#include +#include +#endif + +namespace kj { + +StringPtr KJ_STRINGIFY(LogSeverity severity) { + static const char* SEVERITY_STRINGS[] = { + "info", + "warning", + "error", + "fatal", + "debug" + }; + + return SEVERITY_STRINGS[static_cast(severity)]; +} + +#if _WIN32 && _M_X64 +// Currently the Win32 stack-trace code only supports x86_64. We could easily extend it to support +// i386 as well but it requires some code changes around how we read the context to start the +// trace. + +namespace { + +struct Dbghelp { + // Load dbghelp.dll dynamically since we don't really need it, it's just for debugging. + + HINSTANCE lib; + + BOOL (WINAPI *symInitialize)(HANDLE hProcess,PCSTR UserSearchPath,BOOL fInvadeProcess); + BOOL (WINAPI *stackWalk64)( + DWORD MachineType,HANDLE hProcess,HANDLE hThread, + LPSTACKFRAME64 StackFrame,PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + PVOID (WINAPI *symFunctionTableAccess64)(HANDLE hProcess,DWORD64 AddrBase); + DWORD64 (WINAPI *symGetModuleBase64)(HANDLE hProcess,DWORD64 qwAddr); + BOOL (WINAPI *symGetLineFromAddr64)( + HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE64 Line64); + + Dbghelp() + : lib(LoadLibraryA("dbghelp.dll")), + symInitialize(lib == nullptr ? nullptr : + reinterpret_cast( + GetProcAddress(lib, "SymInitialize"))), + stackWalk64(symInitialize == nullptr ? nullptr : + reinterpret_cast( + GetProcAddress(lib, "StackWalk64"))), + symFunctionTableAccess64(symInitialize == nullptr ? nullptr : + reinterpret_cast( + GetProcAddress(lib, "SymFunctionTableAccess64"))), + symGetModuleBase64(symInitialize == nullptr ? nullptr : + reinterpret_cast( + GetProcAddress(lib, "SymGetModuleBase64"))), + symGetLineFromAddr64(symInitialize == nullptr ? nullptr : + reinterpret_cast( + GetProcAddress(lib, "SymGetLineFromAddr64"))) { + if (symInitialize != nullptr) { + symInitialize(GetCurrentProcess(), NULL, TRUE); + } + } +}; + +const Dbghelp& getDbghelp() { + static Dbghelp dbghelp; + return dbghelp; +} + +ArrayPtr getStackTrace(ArrayPtr space, uint ignoreCount, + HANDLE thread, CONTEXT& context) { + const Dbghelp& dbghelp = getDbghelp(); + if (dbghelp.stackWalk64 == nullptr || + dbghelp.symFunctionTableAccess64 == nullptr || + dbghelp.symGetModuleBase64 == nullptr) { + return nullptr; + } + + STACKFRAME64 frame; + memset(&frame, 0, sizeof(frame)); + + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + + HANDLE process = GetCurrentProcess(); + + uint count = 0; + for (; count < space.size(); count++) { + if (!dbghelp.stackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread, + &frame, &context, NULL, dbghelp.symFunctionTableAccess64, + dbghelp.symGetModuleBase64, NULL)){ + break; + } + + space[count] = reinterpret_cast(frame.AddrPC.Offset); + } + + return space.slice(kj::min(ignoreCount, count), count); +} + +} // namespace +#endif + +ArrayPtr getStackTrace(ArrayPtr space, uint ignoreCount) { + if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) { + return nullptr; + } + +#if _WIN32 && _M_X64 + CONTEXT context; + RtlCaptureContext(&context); + return getStackTrace(space, ignoreCount, GetCurrentThread(), context); +#elif KJ_HAS_BACKTRACE + size_t size = backtrace(space.begin(), space.size()); + return space.slice(kj::min(ignoreCount + 1, size), size); +#else + return nullptr; +#endif +} + +String stringifyStackTrace(ArrayPtr trace) { + if (trace.size() == 0) return nullptr; + if (getExceptionCallback().stackTraceMode() != ExceptionCallback::StackTraceMode::FULL) { + return nullptr; + } + +#if _WIN32 && _M_X64 && _MSC_VER + + // Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since + // this requires MSVC debug info. + // + // TODO(someday): We could perhaps shell out to addr2line on MinGW. + + const Dbghelp& dbghelp = getDbghelp(); + if (dbghelp.symGetLineFromAddr64 == nullptr) return nullptr; + + HANDLE process = GetCurrentProcess(); + + KJ_STACK_ARRAY(String, lines, trace.size(), 32, 32); + + for (auto i: kj::indices(trace)) { + IMAGEHLP_LINE64 lineInfo; + memset(&lineInfo, 0, sizeof(lineInfo)); + lineInfo.SizeOfStruct = sizeof(lineInfo); + if (dbghelp.symGetLineFromAddr64(process, reinterpret_cast(trace[i]), NULL, &lineInfo)) { + lines[i] = kj::str('\n', lineInfo.FileName, ':', lineInfo.LineNumber); + } + } + + return strArray(lines, ""); + +#elif (__linux__ || __APPLE__) && !__ANDROID__ + // We want to generate a human-readable stack trace. + + // TODO(someday): It would be really great if we could avoid farming out to another process + // and do this all in-process, but that may involve onerous requirements like large library + // dependencies or using -rdynamic. + + // The environment manipulation is not thread-safe, so lock a mutex. This could still be + // problematic if another thread is manipulating the environment in unrelated code, but there's + // not much we can do about that. This is debug-only anyway and only an issue when LD_PRELOAD + // is in use. + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&mutex); + KJ_DEFER(pthread_mutex_unlock(&mutex)); + + // Don't heapcheck / intercept syscalls. + const char* preload = getenv("LD_PRELOAD"); + String oldPreload; + if (preload != nullptr) { + oldPreload = heapString(preload); + unsetenv("LD_PRELOAD"); + } + KJ_DEFER(if (oldPreload != nullptr) { setenv("LD_PRELOAD", oldPreload.cStr(), true); }); + + String lines[32]; + FILE* p = nullptr; + auto strTrace = strArray(trace, " "); + +#if __linux__ + if (access("/proc/self/exe", R_OK) < 0) { + // Apparently /proc is not available? + return nullptr; + } + + // Obtain symbolic stack trace using addr2line. + // TODO(cleanup): Use fork() and exec() or maybe our own Subprocess API (once it exists), to + // avoid depending on a shell. + p = popen(str("addr2line -e /proc/", getpid(), "/exe ", strTrace).cStr(), "r"); +#elif __APPLE__ + // The Mac OS X equivalent of addr2line is atos. + // (Internally, it uses the private CoreSymbolication.framework library.) + p = popen(str("xcrun atos -p ", getpid(), ' ', strTrace).cStr(), "r"); +#endif + + if (p == nullptr) { + return nullptr; + } + + char line[512]; + size_t i = 0; + while (i < kj::size(lines) && fgets(line, sizeof(line), p) != nullptr) { + // Don't include exception-handling infrastructure or promise infrastructure in stack trace. + // addr2line output matches file names; atos output matches symbol names. + if (strstr(line, "kj/common.c++") != nullptr || + strstr(line, "kj/exception.") != nullptr || + strstr(line, "kj/debug.") != nullptr || + strstr(line, "kj/async.") != nullptr || + strstr(line, "kj/async-prelude.h") != nullptr || + strstr(line, "kj/async-inl.h") != nullptr || + strstr(line, "kj::Exception") != nullptr || + strstr(line, "kj::_::Debug") != nullptr) { + continue; + } + + size_t len = strlen(line); + if (len > 0 && line[len-1] == '\n') line[len-1] = '\0'; + lines[i++] = str("\n ", trimSourceFilename(line), ": returning here"); + } + + // Skip remaining input. + while (fgets(line, sizeof(line), p) != nullptr) {} + + pclose(p); + + return strArray(arrayPtr(lines, i), ""); + +#else + return nullptr; +#endif +} + +String getStackTrace() { + void* space[32]; + auto trace = getStackTrace(space, 2); + return kj::str(kj::strArray(trace, " "), stringifyStackTrace(trace)); +} + +#if _WIN32 && _M_X64 +namespace { + +DWORD mainThreadId = 0; + +BOOL WINAPI breakHandler(DWORD type) { + switch (type) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: { + HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThreadId); + if (thread != NULL) { + if (SuspendThread(thread) != (DWORD)-1) { + CONTEXT context; + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_FULL; + if (GetThreadContext(thread, &context)) { + void* traceSpace[32]; + auto trace = getStackTrace(traceSpace, 2, thread, context); + ResumeThread(thread); + auto message = kj::str("*** Received CTRL+C. stack: ", strArray(trace, " "), + stringifyStackTrace(trace), '\n'); + FdOutputStream(STDERR_FILENO).write(message.begin(), message.size()); + } else { + ResumeThread(thread); + } + } + CloseHandle(thread); + } + break; + } + default: + break; + } + + return FALSE; // still crash +} + +} // namespace + +void printStackTraceOnCrash() { + mainThreadId = GetCurrentThreadId(); + KJ_WIN32(SetConsoleCtrlHandler(breakHandler, TRUE)); +} + +#elif KJ_HAS_BACKTRACE +namespace { + +void crashHandler(int signo, siginfo_t* info, void* context) { + void* traceSpace[32]; + + // ignoreCount = 2 to ignore crashHandler() and signal trampoline. + auto trace = getStackTrace(traceSpace, 2); + + auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo), + "\nstack: ", strArray(trace, " "), + stringifyStackTrace(trace), '\n'); + + FdOutputStream(STDERR_FILENO).write(message.begin(), message.size()); + _exit(1); +} + +} // namespace + +void printStackTraceOnCrash() { + // Set up alternate signal stack so that stack overflows can be handled. + stack_t stack; + memset(&stack, 0, sizeof(stack)); + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#ifndef MAP_GROWSDOWN +#define MAP_GROWSDOWN 0 +#endif + + stack.ss_size = 65536; + // Note: ss_sp is char* on FreeBSD, void* on Linux and OSX. + stack.ss_sp = reinterpret_cast(mmap( + nullptr, stack.ss_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0)); + KJ_SYSCALL(sigaltstack(&stack, nullptr)); + + // Catch all relevant signals. + struct sigaction action; + memset(&action, 0, sizeof(action)); + + action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND; + action.sa_sigaction = &crashHandler; + + // Dump stack on common "crash" signals. + KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr)); + KJ_SYSCALL(sigaction(SIGBUS, &action, nullptr)); + KJ_SYSCALL(sigaction(SIGFPE, &action, nullptr)); + KJ_SYSCALL(sigaction(SIGABRT, &action, nullptr)); + KJ_SYSCALL(sigaction(SIGILL, &action, nullptr)); + + // Dump stack on unimplemented syscalls -- useful in seccomp sandboxes. + KJ_SYSCALL(sigaction(SIGSYS, &action, nullptr)); + +#ifdef KJ_DEBUG + // Dump stack on keyboard interrupt -- useful for infinite loops. Only in debug mode, though, + // because stack traces on ctrl+c can be obnoxious for, say, command-line tools. + KJ_SYSCALL(sigaction(SIGINT, &action, nullptr)); +#endif +} +#else +void printStackTraceOnCrash() { +} +#endif + +kj::StringPtr trimSourceFilename(kj::StringPtr filename) { + // Removes noisy prefixes from source code file name. + // + // The goal here is to produce the "canonical" filename given the filename returned by e.g. + // addr2line. addr2line gives us the full path of the file as passed on the compiler + // command-line, which in turn is affected by build system and by whether and where we're + // performing an out-of-tree build. + // + // To deal with all this, we look for directory names in the path which we recognize to be + // locations that represent roots of the source tree. We strip said root and everything before + // it. + // + // On Windows, we often get filenames containing backslashes. Since we aren't allowed to allocate + // a new string here, we can't do much about this, so our returned "canonical" name will + // unfortunately end up with backslashes. + + static constexpr const char* ROOTS[] = { + "ekam-provider/canonical/", // Ekam source file. + "ekam-provider/c++header/", // Ekam include file. + "src/", // Non-Ekam source root. + "tmp/", // Non-Ekam generated code. +#if _WIN32 + "src\\", // Win32 source root. + "tmp\\", // Win32 generated code. +#endif + }; + +retry: + for (size_t i: kj::indices(filename)) { + if (i == 0 || filename[i-1] == '/' +#if _WIN32 + || filename[i-1] == '\\' +#endif + ) { + // We're at the start of a directory name. Check for valid prefixes. + for (kj::StringPtr root: ROOTS) { + if (filename.slice(i).startsWith(root)) { + filename = filename.slice(i + root.size()); + + // We should keep searching to find the last instance of a root name. `i` is no longer + // a valid index for `filename` so start the loop over. + goto retry; + } + } + } + } + + return filename; +} + +StringPtr KJ_STRINGIFY(Exception::Type type) { + static const char* TYPE_STRINGS[] = { + "failed", + "overloaded", + "disconnected", + "unimplemented" + }; + + return TYPE_STRINGS[static_cast(type)]; +} + +String KJ_STRINGIFY(const Exception& e) { + uint contextDepth = 0; + + Maybe contextPtr = e.getContext(); + for (;;) { + KJ_IF_MAYBE(c, contextPtr) { + ++contextDepth; + contextPtr = c->next; + } else { + break; + } + } + + Array contextText = heapArray(contextDepth); + + contextDepth = 0; + contextPtr = e.getContext(); + for (;;) { + KJ_IF_MAYBE(c, contextPtr) { + contextText[contextDepth++] = + str(c->file, ":", c->line, ": context: ", c->description, "\n"); + contextPtr = c->next; + } else { + break; + } + } + + return str(strArray(contextText, ""), + e.getFile(), ":", e.getLine(), ": ", e.getType(), + e.getDescription() == nullptr ? "" : ": ", e.getDescription(), + e.getStackTrace().size() > 0 ? "\nstack: " : "", strArray(e.getStackTrace(), " "), + stringifyStackTrace(e.getStackTrace())); +} + +Exception::Exception(Type type, const char* file, int line, String description) noexcept + : file(trimSourceFilename(file).cStr()), line(line), type(type), description(mv(description)), + traceCount(0) {} + +Exception::Exception(Type type, String file, int line, String description) noexcept + : ownFile(kj::mv(file)), file(trimSourceFilename(ownFile).cStr()), line(line), type(type), + description(mv(description)), traceCount(0) {} + +Exception::Exception(const Exception& other) noexcept + : file(other.file), line(other.line), type(other.type), + description(heapString(other.description)), traceCount(other.traceCount) { + if (file == other.ownFile.cStr()) { + ownFile = heapString(other.ownFile); + file = ownFile.cStr(); + } + + memcpy(trace, other.trace, sizeof(trace[0]) * traceCount); + + KJ_IF_MAYBE(c, other.context) { + context = heap(**c); + } +} + +Exception::~Exception() noexcept {} + +Exception::Context::Context(const Context& other) noexcept + : file(other.file), line(other.line), description(str(other.description)) { + KJ_IF_MAYBE(n, other.next) { + next = heap(**n); + } +} + +void Exception::wrapContext(const char* file, int line, String&& description) { + context = heap(file, line, mv(description), mv(context)); +} + +void Exception::extendTrace(uint ignoreCount) { + KJ_STACK_ARRAY(void*, newTraceSpace, kj::size(trace) + ignoreCount + 1, + sizeof(trace)/sizeof(trace[0]) + 8, 128); + + auto newTrace = kj::getStackTrace(newTraceSpace, ignoreCount + 1); + if (newTrace.size() > ignoreCount + 2) { + // Remove suffix that won't fit into our static-sized trace. + newTrace = newTrace.slice(0, kj::min(kj::size(trace) - traceCount, newTrace.size())); + + // Copy the rest into our trace. + memcpy(trace + traceCount, newTrace.begin(), newTrace.asBytes().size()); + traceCount += newTrace.size(); + } +} + +void Exception::truncateCommonTrace() { + if (traceCount > 0) { + // Create a "reference" stack trace that is a little bit deeper than the one in the exception. + void* refTraceSpace[sizeof(this->trace) / sizeof(this->trace[0]) + 4]; + auto refTrace = kj::getStackTrace(refTraceSpace, 0); + + // We expect that the deepest frame in the exception's stack trace should be somewhere in our + // own trace, since our own trace has a deeper limit. Search for it. + for (uint i = refTrace.size(); i > 0; i--) { + if (refTrace[i-1] == trace[traceCount-1]) { + // See how many frames match. + for (uint j = 0; j < i; j++) { + if (j >= traceCount) { + // We matched the whole trace, apparently? + traceCount = 0; + return; + } else if (refTrace[i-j-1] != trace[traceCount-j-1]) { + // Found mismatching entry. + + // If we matched more than half of the reference trace, guess that this is in fact + // the prefix we're looking for. + if (j > refTrace.size() / 2) { + // Delete the matching suffix. Also delete one non-matched entry on the assumption + // that both traces contain that stack frame but are simply at different points in + // the function. + traceCount -= j + 1; + return; + } + } + } + } + } + + // No match. Ignore. + } +} + +void Exception::addTrace(void* ptr) { + if (traceCount < kj::size(trace)) { + trace[traceCount++] = ptr; + } +} + +class ExceptionImpl: public Exception, public std::exception { +public: + inline ExceptionImpl(Exception&& other): Exception(mv(other)) {} + ExceptionImpl(const ExceptionImpl& other): Exception(other) { + // No need to copy whatBuffer since it's just to hold the return value of what(). + } + + const char* what() const noexcept override; + +private: + mutable String whatBuffer; +}; + +const char* ExceptionImpl::what() const noexcept { + whatBuffer = str(*this); + return whatBuffer.begin(); +} + +// ======================================================================================= + +namespace { + +KJ_THREADLOCAL_PTR(ExceptionCallback) threadLocalCallback = nullptr; + +} // namespace + +ExceptionCallback::ExceptionCallback(): next(getExceptionCallback()) { + char stackVar; + ptrdiff_t offset = reinterpret_cast(this) - &stackVar; + KJ_ASSERT(offset < 65536 && offset > -65536, + "ExceptionCallback must be allocated on the stack."); + + threadLocalCallback = this; +} + +ExceptionCallback::ExceptionCallback(ExceptionCallback& next): next(next) {} + +ExceptionCallback::~ExceptionCallback() noexcept(false) { + if (&next != this) { + threadLocalCallback = &next; + } +} + +void ExceptionCallback::onRecoverableException(Exception&& exception) { + next.onRecoverableException(mv(exception)); +} + +void ExceptionCallback::onFatalException(Exception&& exception) { + next.onFatalException(mv(exception)); +} + +void ExceptionCallback::logMessage( + LogSeverity severity, const char* file, int line, int contextDepth, String&& text) { + next.logMessage(severity, file, line, contextDepth, mv(text)); +} + +ExceptionCallback::StackTraceMode ExceptionCallback::stackTraceMode() { + return next.stackTraceMode(); +} + +class ExceptionCallback::RootExceptionCallback: public ExceptionCallback { +public: + RootExceptionCallback(): ExceptionCallback(*this) {} + + void onRecoverableException(Exception&& exception) override { +#if KJ_NO_EXCEPTIONS + logException(LogSeverity::ERROR, mv(exception)); +#else + if (std::uncaught_exception()) { + // Bad time to throw an exception. Just log instead. + // + // TODO(someday): We should really compare uncaughtExceptionCount() against the count at + // the innermost runCatchingExceptions() frame in this thread to tell if exceptions are + // being caught correctly. + logException(LogSeverity::ERROR, mv(exception)); + } else { + throw ExceptionImpl(mv(exception)); + } +#endif + } + + void onFatalException(Exception&& exception) override { +#if KJ_NO_EXCEPTIONS + logException(LogSeverity::FATAL, mv(exception)); +#else + throw ExceptionImpl(mv(exception)); +#endif + } + + void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text) override { + text = str(kj::repeat('_', contextDepth), file, ":", line, ": ", severity, ": ", + mv(text), '\n'); + + StringPtr textPtr = text; + + while (text != nullptr) { + miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size()); + if (n <= 0) { + // stderr is broken. Give up. + return; + } + textPtr = textPtr.slice(n); + } + } + + StackTraceMode stackTraceMode() override { +#ifdef KJ_DEBUG + return StackTraceMode::FULL; +#else + return StackTraceMode::ADDRESS_ONLY; +#endif + } + +private: + void logException(LogSeverity severity, Exception&& e) { + // We intentionally go back to the top exception callback on the stack because we don't want to + // bypass whatever log processing is in effect. + // + // We intentionally don't log the context since it should get re-added by the exception callback + // anyway. + getExceptionCallback().logMessage(severity, e.getFile(), e.getLine(), 0, str( + e.getType(), e.getDescription() == nullptr ? "" : ": ", e.getDescription(), + e.getStackTrace().size() > 0 ? "\nstack: " : "", strArray(e.getStackTrace(), " "), + stringifyStackTrace(e.getStackTrace()), "\n")); + } +}; + +ExceptionCallback& getExceptionCallback() { + static ExceptionCallback::RootExceptionCallback defaultCallback; + ExceptionCallback* scoped = threadLocalCallback; + return scoped != nullptr ? *scoped : defaultCallback; +} + +void throwFatalException(kj::Exception&& exception, uint ignoreCount) { + exception.extendTrace(ignoreCount + 1); + getExceptionCallback().onFatalException(kj::mv(exception)); + abort(); +} + +void throwRecoverableException(kj::Exception&& exception, uint ignoreCount) { + exception.extendTrace(ignoreCount + 1); + getExceptionCallback().onRecoverableException(kj::mv(exception)); +} + +// ======================================================================================= + +namespace _ { // private + +#if __GNUC__ + +// Horrible -- but working -- hack: We can dig into __cxa_get_globals() in order to extract the +// count of uncaught exceptions. This function is part of the C++ ABI implementation used on Linux, +// OSX, and probably other platforms that use GCC. Unfortunately, __cxa_get_globals() is only +// actually defined in cxxabi.h on some platforms (e.g. Linux, but not OSX), and even where it is +// defined, it returns an incomplete type. Here we use the same hack used by Evgeny Panasyuk: +// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp +// +// Notice that a similar hack is possible on MSVC -- if its C++11 support ever gets to the point of +// supporting KJ in the first place. +// +// It appears likely that a future version of the C++ standard may include an +// uncaught_exception_count() function in the standard library, or an equivalent language feature. +// Some discussion: +// https://groups.google.com/a/isocpp.org/d/msg/std-proposals/HglEslyZFYs/kKdu5jJw5AgJ + +struct FakeEhGlobals { + // Fake + + void* caughtExceptions; + uint uncaughtExceptions; +}; + +// Because of the 'extern "C"', the symbol name is not mangled and thus the namespace is effectively +// ignored for linking. Thus it doesn't matter that we are declaring __cxa_get_globals() in a +// different namespace from the ABI's definition. +extern "C" { +FakeEhGlobals* __cxa_get_globals(); +} + +uint uncaughtExceptionCount() { + // TODO(perf): Use __cxa_get_globals_fast()? Requires that __cxa_get_globals() has been called + // from somewhere. + return __cxa_get_globals()->uncaughtExceptions; +} + +#elif _MSC_VER + +#if _MSC_VER >= 1900 +// MSVC14 has a refactored CRT which now provides a direct accessor for this value. +// See https://svn.boost.org/trac/boost/ticket/10158 for a brief discussion. +extern "C" int *__cdecl __processing_throw(); + +uint uncaughtExceptionCount() { + return static_cast(*__processing_throw()); +} + +#elif _MSC_VER >= 1400 +// The below was copied from: +// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp + +extern "C" char *__cdecl _getptd(); + +uint uncaughtExceptionCount() { + return *reinterpret_cast(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90)); +} +#else +uint uncaughtExceptionCount() { + // Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect + // results in very obscure cases that Cap'n Proto doesn't really rely on anyway. + return std::uncaught_exception(); +} +#endif + +#else +#error "This needs to be ported to your compiler / C++ ABI." +#endif + +} // namespace _ (private) + +UnwindDetector::UnwindDetector(): uncaughtCount(_::uncaughtExceptionCount()) {} + +bool UnwindDetector::isUnwinding() const { + return _::uncaughtExceptionCount() > uncaughtCount; +} + +void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const { + // TODO(someday): Attach the secondary exception to whatever primary exception is causing + // the unwind. For now we just drop it on the floor as this is probably fine most of the + // time. + runCatchingExceptions(runnable); +} + +namespace _ { // private + +class RecoverableExceptionCatcher: public ExceptionCallback { + // Catches a recoverable exception without using try/catch. Used when compiled with + // -fno-exceptions. + +public: + virtual ~RecoverableExceptionCatcher() noexcept(false) {} + + void onRecoverableException(Exception&& exception) override { + if (caught == nullptr) { + caught = mv(exception); + } else { + // TODO(someday): Consider it a secondary fault? + } + } + + Maybe caught; +}; + +Maybe runCatchingExceptions(Runnable& runnable) noexcept { +#if KJ_NO_EXCEPTIONS + RecoverableExceptionCatcher catcher; + runnable.run(); + KJ_IF_MAYBE(e, catcher.caught) { + e->truncateCommonTrace(); + } + return mv(catcher.caught); +#else + try { + runnable.run(); + return nullptr; + } catch (Exception& e) { + e.truncateCommonTrace(); + return kj::mv(e); + } catch (std::bad_alloc& e) { + return Exception(Exception::Type::OVERLOADED, + "(unknown)", -1, str("std::bad_alloc: ", e.what())); + } catch (std::exception& e) { + return Exception(Exception::Type::FAILED, + "(unknown)", -1, str("std::exception: ", e.what())); + } catch (...) { + return Exception(Exception::Type::FAILED, + "(unknown)", -1, str("Unknown non-KJ exception.")); + } +#endif +} + +} // namespace _ (private) + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/exception.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/exception.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,363 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_EXCEPTION_H_ +#define KJ_EXCEPTION_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" +#include "array.h" +#include "string.h" + +namespace kj { + +class ExceptionImpl; + +class Exception { + // Exception thrown in case of fatal errors. + // + // Actually, a subclass of this which also implements std::exception will be thrown, but we hide + // that fact from the interface to avoid #including . + +public: + enum class Type { + // What kind of failure? + + FAILED = 0, + // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this + // error type. + + OVERLOADED = 1, + // The call failed because of a temporary lack of resources. This could be space resources + // (out of memory, out of disk space) or time resources (request queue overflow, operation + // timed out). + // + // The operation might work if tried again, but it should NOT be repeated immediately as this + // may simply exacerbate the problem. + + DISCONNECTED = 2, + // The call required communication over a connection that has been lost. The callee will need + // to re-establish connections and try again. + + UNIMPLEMENTED = 3 + // The requested method is not implemented. The caller may wish to revert to a fallback + // approach based on other methods. + + // IF YOU ADD A NEW VALUE: + // - Update the stringifier. + // - Update Cap'n Proto's RPC protocol's Exception.Type enum. + }; + + Exception(Type type, const char* file, int line, String description = nullptr) noexcept; + Exception(Type type, String file, int line, String description = nullptr) noexcept; + Exception(const Exception& other) noexcept; + Exception(Exception&& other) = default; + ~Exception() noexcept; + + const char* getFile() const { return file; } + int getLine() const { return line; } + Type getType() const { return type; } + StringPtr getDescription() const { return description; } + ArrayPtr getStackTrace() const { return arrayPtr(trace, traceCount); } + + struct Context { + // Describes a bit about what was going on when the exception was thrown. + + const char* file; + int line; + String description; + Maybe> next; + + Context(const char* file, int line, String&& description, Maybe>&& next) + : file(file), line(line), description(mv(description)), next(mv(next)) {} + Context(const Context& other) noexcept; + }; + + inline Maybe getContext() const { + KJ_IF_MAYBE(c, context) { + return **c; + } else { + return nullptr; + } + } + + void wrapContext(const char* file, int line, String&& description); + // Wraps the context in a new node. This becomes the head node returned by getContext() -- it + // is expected that contexts will be added in reverse order as the exception passes up the + // callback stack. + + KJ_NOINLINE void extendTrace(uint ignoreCount); + // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount` + // frames (see `getStackTrace()` for discussion of `ignoreCount`). + + KJ_NOINLINE void truncateCommonTrace(); + // Remove the part of the stack trace which the exception shares with the caller of this method. + // This is used by the async library to remove the async infrastructure from the stack trace + // before replacing it with the async trace. + + void addTrace(void* ptr); + // Append the given pointer to the backtrace, if it is not already full. This is used by the + // async library to trace through the promise chain that led to the exception. + +private: + String ownFile; + const char* file; + int line; + Type type; + String description; + Maybe> context; + void* trace[32]; + uint traceCount; + + friend class ExceptionImpl; +}; + +StringPtr KJ_STRINGIFY(Exception::Type type); +String KJ_STRINGIFY(const Exception& e); + +// ======================================================================================= + +enum class LogSeverity { + INFO, // Information describing what the code is up to, which users may request to see + // with a flag like `--verbose`. Does not indicate a problem. Not printed by + // default; you must call setLogLevel(INFO) to enable. + WARNING, // A problem was detected but execution can continue with correct output. + ERROR, // Something is wrong, but execution can continue with garbage output. + FATAL, // Something went wrong, and execution cannot continue. + DBG // Temporary debug logging. See KJ_DBG. + + // Make sure to update the stringifier if you add a new severity level. +}; + +StringPtr KJ_STRINGIFY(LogSeverity severity); + +class ExceptionCallback { + // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order + // to perform your own exception handling. For example, a reasonable thing to do is to have + // onRecoverableException() set a flag indicating that an error occurred, and then check for that + // flag just before writing to storage and/or returning results to the user. If the flag is set, + // discard whatever you have and return an error instead. + // + // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the + // newest ExceptionCallback on the calling thread's stack is called. The default implementation + // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks + // behave a lot like try/catch blocks, except that they are called before any stack unwinding + // occurs. + +public: + ExceptionCallback(); + KJ_DISALLOW_COPY(ExceptionCallback); + virtual ~ExceptionCallback() noexcept(false); + + virtual void onRecoverableException(Exception&& exception); + // Called when an exception has been raised, but the calling code has the ability to continue by + // producing garbage output. This method _should_ throw the exception, but is allowed to simply + // return if garbage output is acceptable. + // + // The global default implementation throws an exception unless the library was compiled with + // -fno-exceptions, in which case it logs an error and returns. + + virtual void onFatalException(Exception&& exception); + // Called when an exception has been raised and the calling code cannot continue. If this method + // returns normally, abort() will be called. The method must throw the exception to avoid + // aborting. + // + // The global default implementation throws an exception unless the library was compiled with + // -fno-exceptions, in which case it logs an error and returns. + + virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth, + String&& text); + // Called when something wants to log some debug text. `contextDepth` indicates how many levels + // of context the message passed through; it may make sense to indent the message accordingly. + // + // The global default implementation writes the text to stderr. + + enum class StackTraceMode { + FULL, + // Stringifying a stack trace will attempt to determine source file and line numbers. This may + // be expensive. For example, on Linux, this shells out to `addr2line`. + // + // This is the default in debug builds. + + ADDRESS_ONLY, + // Stringifying a stack trace will only generate a list of code addresses. + // + // This is the default in release builds. + + NONE + // Generating a stack trace will always return an empty array. + // + // This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library + // has been observed to be pretty slow, so exception-heavy code might benefit significantly + // from this setting. (But exceptions should be rare...) + }; + + virtual StackTraceMode stackTraceMode(); + // Returns the current preferred stack trace mode. + +protected: + ExceptionCallback& next; + +private: + ExceptionCallback(ExceptionCallback& next); + + class RootExceptionCallback; + friend ExceptionCallback& getExceptionCallback(); +}; + +ExceptionCallback& getExceptionCallback(); +// Returns the current exception callback. + +KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0)); +// Invoke the exception callback to throw the given fatal exception. If the exception callback +// returns, abort. + +KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0); +// Invoke the exception callback to throw the given recoverable exception. If the exception +// callback returns, return normally. + +// ======================================================================================= + +namespace _ { class Runnable; } + +template +Maybe runCatchingExceptions(Func&& func) noexcept; +// Executes the given function (usually, a lambda returning nothing) catching any exceptions that +// are thrown. Returns the Exception if there was one, or null if the operation completed normally. +// Non-KJ exceptions will be wrapped. +// +// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any +// recoverable exceptions occurred while running the function and will return those. + +class UnwindDetector { + // Utility for detecting when a destructor is called due to unwind. Useful for: + // - Avoiding throwing exceptions in this case, which would terminate the program. + // - Detecting whether to commit or roll back a transaction. + // + // To use this class, either inherit privately from it or declare it as a member. The detector + // works by comparing the exception state against that when the constructor was called, so for + // an object that was actually constructed during exception unwind, it will behave as if no + // unwind is taking place. This is usually the desired behavior. + +public: + UnwindDetector(); + + bool isUnwinding() const; + // Returns true if the current thread is in a stack unwind that it wasn't in at the time the + // object was constructed. + + template + void catchExceptionsIfUnwinding(Func&& func) const; + // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are + // caught and treated as secondary faults, meaning they are considered to be side-effects of the + // exception that is unwinding the stack. Otherwise, exceptions are passed through normally. + +private: + uint uncaughtCount; + + void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const; +}; + +namespace _ { // private + +class Runnable { +public: + virtual void run() = 0; +}; + +template +class RunnableImpl: public Runnable { +public: + RunnableImpl(Func&& func): func(kj::mv(func)) {} + void run() override { + func(); + } +private: + Func func; +}; + +Maybe runCatchingExceptions(Runnable& runnable) noexcept; + +} // namespace _ (private) + +template +Maybe runCatchingExceptions(Func&& func) noexcept { + _::RunnableImpl> runnable(kj::fwd(func)); + return _::runCatchingExceptions(runnable); +} + +template +void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const { + if (isUnwinding()) { + _::RunnableImpl> runnable(kj::fwd(func)); + catchExceptionsAsSecondaryFaults(runnable); + } else { + func(); + } +} + +#define KJ_ON_SCOPE_SUCCESS(code) \ + ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ + KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) +// Runs `code` if the current scope is exited normally (not due to an exception). + +#define KJ_ON_SCOPE_FAILURE(code) \ + ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \ + KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; }) +// Runs `code` if the current scope is exited due to an exception. + +// ======================================================================================= + +KJ_NOINLINE ArrayPtr getStackTrace(ArrayPtr space, uint ignoreCount); +// Attempt to get the current stack trace, returning a list of pointers to instructions. The +// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace. +// If the platform doesn't support stack traces, returns an empty array. +// +// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping +// off a prefix of the trace that is uninteresting to the developer because it's just locations +// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as +// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the +// ignored entries will still waste space in the `space` array (and the returned array's `begin()` +// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero +// since `getStackTrace()` needs to ignore its own internal frames). + +String stringifyStackTrace(ArrayPtr); +// Convert the stack trace to a string with file names and line numbers. This may involve executing +// suprocesses. + +String getStackTrace(); +// Get a stack trace right now and stringify it. Useful for debugging. + +void printStackTraceOnCrash(); +// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print +// a stack trace. You should call this as early as possible on program startup. Programs using +// KJ_MAIN get this automatically. + +kj::StringPtr trimSourceFilename(kj::StringPtr filename); +// Given a source code file name, trim off noisy prefixes like "src/" or +// "/ekam-provider/canonical/". + +} // namespace kj + +#endif // KJ_EXCEPTION_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/function-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/function-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,121 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "function.h" +#include + +namespace kj { +namespace { + +TEST(Function, Lambda) { + int i = 0; + + Function f = [&](int a, int b) { return a + b + i++; }; + + EXPECT_EQ(123 + 456, f(123, 456)); + EXPECT_EQ(7 + 8 + 1, f(7, 8)); + EXPECT_EQ(9 + 2 + 2, f(2, 9)); + + EXPECT_EQ(i, 3); +} + +struct TestType { + int callCount; + + TestType(int callCount = 0): callCount(callCount) {} + + ~TestType() { callCount = 1234; } + // Make sure we catch invalid post-destruction uses. + + int foo(int a, int b) { + return a + b + callCount++; + } +}; + +TEST(Function, Method) { + TestType obj; + Function f = KJ_BIND_METHOD(obj, foo); + Function f2 = KJ_BIND_METHOD(obj, foo); + + EXPECT_EQ(123 + 456, f(123, 456)); + EXPECT_EQ(7 + 8 + 1, f(7, 8)); + EXPECT_EQ(9u + 2u + 2u, f2(2, 9)); + + EXPECT_EQ(3, obj.callCount); + + // Bind to a temporary. + f = KJ_BIND_METHOD(TestType(10), foo); + + EXPECT_EQ(123 + 456 + 10, f(123, 456)); + EXPECT_EQ(7 + 8 + 11, f(7, 8)); + EXPECT_EQ(9 + 2 + 12, f(2, 9)); + + // Bind to a move. + f = KJ_BIND_METHOD(kj::mv(obj), foo); + obj.callCount = 1234; + + EXPECT_EQ(123 + 456 + 3, f(123, 456)); + EXPECT_EQ(7 + 8 + 4, f(7, 8)); + EXPECT_EQ(9 + 2 + 5, f(2, 9)); +} + +struct TestConstType { + mutable int callCount; + + TestConstType(int callCount = 0): callCount(callCount) {} + + ~TestConstType() { callCount = 1234; } + // Make sure we catch invalid post-destruction uses. + + int foo(int a, int b) const { + return a + b + callCount++; + } +}; + +TEST(ConstFunction, Method) { + TestConstType obj; + ConstFunction f = KJ_BIND_METHOD(obj, foo); + ConstFunction f2 = KJ_BIND_METHOD(obj, foo); + + EXPECT_EQ(123 + 456, f(123, 456)); + EXPECT_EQ(7 + 8 + 1, f(7, 8)); + EXPECT_EQ(9u + 2u + 2u, f2(2, 9)); + + EXPECT_EQ(3, obj.callCount); + + // Bind to a temporary. + f = KJ_BIND_METHOD(TestConstType(10), foo); + + EXPECT_EQ(123 + 456 + 10, f(123, 456)); + EXPECT_EQ(7 + 8 + 11, f(7, 8)); + EXPECT_EQ(9 + 2 + 12, f(2, 9)); + + // Bind to a move. + f = KJ_BIND_METHOD(kj::mv(obj), foo); + obj.callCount = 1234; + + EXPECT_EQ(123 + 456 + 3, f(123, 456)); + EXPECT_EQ(7 + 8 + 4, f(7, 8)); + EXPECT_EQ(9 + 2 + 5, f(2, 9)); +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/function.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/function.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,277 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_FUNCTION_H_ +#define KJ_FUNCTION_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "memory.h" + +namespace kj { + +template +class Function; +// Function wrapper using virtual-based polymorphism. Use this when template polymorphism is +// not possible. You can, for example, accept a Function as a parameter: +// +// void setFilter(Function filter); +// +// The caller of `setFilter()` may then pass any callable object as the parameter. The callable +// object does not have to have the exact signature specified, just one that is "compatible" -- +// i.e. the return type is covariant and the parameters are contravariant. +// +// Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This +// is to avoid unexpected heap allocation or slow atomic reference counting. +// +// When a `Function` is constructed from an lvalue, it captures only a reference to the value. +// When constructed from an rvalue, it invokes the value's move constructor. So, for example: +// +// struct AddN { +// int n; +// int operator(int i) { return i + n; } +// } +// +// Function f1 = AddN{2}; +// // f1 owns an instance of AddN. It may safely be moved out +// // of the local scope. +// +// AddN adder(2); +// Function f2 = adder; +// // f2 contains a reference to `adder`. Thus, it becomes invalid +// // when `adder` goes out-of-scope. +// +// AddN adder2(2); +// Function f3 = kj::mv(adder2); +// // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely +// // be moved out of the local scope. +// +// Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName). +// For example: +// +// class Printer { +// public: +// void print(int i); +// void print(kj::StringPtr s); +// }; +// +// Printer p; +// +// Function intPrinter = KJ_BIND_METHOD(p, print); +// // Will call Printer::print(int). +// +// Function strPrinter = KJ_BIND_METHOD(p, print); +// // Will call Printer::print(kj::StringPtr). +// +// Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of +// Function it is binding to. + +template +class ConstFunction; +// Like Function, but wraps a "const" (i.e. thread-safe) call. + +template +class Function { +public: + template + inline Function(F&& f): impl(heap>(kj::fwd(f))) {} + Function() = default; + + // Make sure people don't accidentally end up wrapping a reference when they meant to return + // a function. + KJ_DISALLOW_COPY(Function); + Function(Function&) = delete; + Function& operator=(Function&) = delete; + template Function(const Function&) = delete; + template Function& operator=(const Function&) = delete; + template Function(const ConstFunction&) = delete; + template Function& operator=(const ConstFunction&) = delete; + Function(Function&&) = default; + Function& operator=(Function&&) = default; + + inline Return operator()(Params... params) { + return (*impl)(kj::fwd(params)...); + } + + Function reference() { + // Forms a new Function of the same type that delegates to this Function by reference. + // Therefore, this Function must outlive the returned Function, but otherwise they behave + // exactly the same. + + return *impl; + } + +private: + class Iface { + public: + virtual Return operator()(Params... params) = 0; + }; + + template + class Impl final: public Iface { + public: + explicit Impl(F&& f): f(kj::fwd(f)) {} + + Return operator()(Params... params) override { + return f(kj::fwd(params)...); + } + + private: + F f; + }; + + Own impl; +}; + +template +class ConstFunction { +public: + template + inline ConstFunction(F&& f): impl(heap>(kj::fwd(f))) {} + ConstFunction() = default; + + // Make sure people don't accidentally end up wrapping a reference when they meant to return + // a function. + KJ_DISALLOW_COPY(ConstFunction); + ConstFunction(ConstFunction&) = delete; + ConstFunction& operator=(ConstFunction&) = delete; + template ConstFunction(const ConstFunction&) = delete; + template ConstFunction& operator=(const ConstFunction&) = delete; + template ConstFunction(const Function&) = delete; + template ConstFunction& operator=(const Function&) = delete; + ConstFunction(ConstFunction&&) = default; + ConstFunction& operator=(ConstFunction&&) = default; + + inline Return operator()(Params... params) const { + return (*impl)(kj::fwd(params)...); + } + + ConstFunction reference() const { + // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference. + // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they + // behave exactly the same. + + return *impl; + } + +private: + class Iface { + public: + virtual Return operator()(Params... params) const = 0; + }; + + template + class Impl final: public Iface { + public: + explicit Impl(F&& f): f(kj::fwd(f)) {} + + Return operator()(Params... params) const override { + return f(kj::fwd(params)...); + } + + private: + F f; + }; + + Own impl; +}; + +#if 1 + +namespace _ { // private + +template +class BoundMethod; + +template ::*method)(Params...)> +class BoundMethod::*)(Params...), method> { +public: + BoundMethod(T&& t): t(kj::fwd(t)) {} + + Return operator()(Params&&... params) { + return (t.*method)(kj::fwd(params)...); + } + +private: + T t; +}; + +template ::*method)(Params...) const> +class BoundMethod::*)(Params...) const, method> { +public: + BoundMethod(T&& t): t(kj::fwd(t)) {} + + Return operator()(Params&&... params) const { + return (t.*method)(kj::fwd(params)...); + } + +private: + T t; +}; + +} // namespace _ (private) + +#define KJ_BIND_METHOD(obj, method) \ + ::kj::_::BoundMethod::method), \ + &::kj::Decay::method>(obj) +// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an +// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will +// contain a copy (by move) of it. +// +// The current implementation requires that the method is not overloaded. +// +// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and +// probably make it work with overloaded methods. + +#else +// Here's a better implementation of the above that doesn't work with GCC (but does with Clang) +// because it uses a local class with a template method. Sigh. This implementation supports +// overloaded methods. + +#define KJ_BIND_METHOD(obj, method) \ + ({ \ + typedef KJ_DECLTYPE_REF(obj) T; \ + class F { \ + public: \ + inline F(T&& t): t(::kj::fwd(t)) {} \ + template \ + auto operator()(Params&&... params) \ + -> decltype(::kj::instance().method(::kj::fwd(params)...)) { \ + return t.method(::kj::fwd(params)...); \ + } \ + private: \ + T t; \ + }; \ + (F(obj)); \ + }) +// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an +// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will +// contain a copy (by move) of it. + +#endif + +} // namespace kj + +#endif // KJ_FUNCTION_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/io-test.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/io-test.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,112 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "io.h" +#include "debug.h" +#include "miniposix.h" +#include + +namespace kj { +namespace { + +TEST(Io, WriteVec) { + // Check that writing an array of arrays works even when some of the arrays are empty. (This + // used to not work in some cases.) + + int fds[2]; + KJ_SYSCALL(miniposix::pipe(fds)); + + FdInputStream in((AutoCloseFd(fds[0]))); + FdOutputStream out((AutoCloseFd(fds[1]))); + + ArrayPtr pieces[5] = { + arrayPtr(implicitCast(nullptr), 0), + arrayPtr(reinterpret_cast("foo"), 3), + arrayPtr(implicitCast(nullptr), 0), + arrayPtr(reinterpret_cast("bar"), 3), + arrayPtr(implicitCast(nullptr), 0) + }; + + out.write(pieces); + + char buf[7]; + in.read(buf, 6); + buf[6] = '\0'; + + EXPECT_STREQ("foobar", buf); +} + +KJ_TEST("stringify AutoCloseFd") { + int fds[2]; + KJ_SYSCALL(miniposix::pipe(fds)); + AutoCloseFd in(fds[0]), out(fds[1]); + + KJ_EXPECT(kj::str(in) == kj::str(fds[0]), in, fds[0]); +} + +KJ_TEST("VectorOutputStream") { + VectorOutputStream output(16); + auto buf = output.getWriteBuffer(); + KJ_ASSERT(buf.size() == 16); + + for (auto i: kj::indices(buf)) { + buf[i] = 'a' + i; + } + + output.write(buf.begin(), 4); + KJ_ASSERT(output.getArray().begin() == buf.begin()); + KJ_ASSERT(output.getArray().size() == 4); + + auto buf2 = output.getWriteBuffer(); + KJ_ASSERT(buf2.end() == buf.end()); + KJ_ASSERT(buf2.size() == 12); + + output.write(buf2.begin(), buf2.size()); + KJ_ASSERT(output.getArray().begin() == buf.begin()); + KJ_ASSERT(output.getArray().size() == 16); + + auto buf3 = output.getWriteBuffer(); + KJ_ASSERT(buf3.size() == 16); + KJ_ASSERT(output.getArray().begin() != buf.begin()); + KJ_ASSERT(output.getArray().end() == buf3.begin()); + KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnop"); + + byte junk[24]; + for (auto i: kj::indices(junk)) { + junk[i] = 'A' + i; + } + + output.write(junk, 4); + KJ_ASSERT(output.getArray().begin() != buf.begin()); + KJ_ASSERT(output.getArray().end() == buf3.begin() + 4); + KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnopABCD"); + + output.write(junk + 4, 20); + KJ_ASSERT(output.getArray().begin() != buf.begin()); + KJ_ASSERT(output.getArray().end() != buf3.begin() + 24); + KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnopABCDEFGHIJKLMNOPQRSTUVWX"); + + KJ_ASSERT(output.getWriteBuffer().size() == 24); + KJ_ASSERT(output.getWriteBuffer().begin() == output.getArray().begin() + 40); +} + +} // namespace +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/io.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/io.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,426 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "io.h" +#include "debug.h" +#include "miniposix.h" +#include +#include + +#if _WIN32 +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#define WIN32_LEAN_AND_MEAN +#include +#include "windows-sanity.h" +#else +#include +#endif + +namespace kj { + +InputStream::~InputStream() noexcept(false) {} +OutputStream::~OutputStream() noexcept(false) {} +BufferedInputStream::~BufferedInputStream() noexcept(false) {} +BufferedOutputStream::~BufferedOutputStream() noexcept(false) {} + +size_t InputStream::read(void* buffer, size_t minBytes, size_t maxBytes) { + size_t n = tryRead(buffer, minBytes, maxBytes); + KJ_REQUIRE(n >= minBytes, "Premature EOF") { + // Pretend we read zeros from the input. + memset(reinterpret_cast(buffer) + n, 0, minBytes - n); + return minBytes; + } + return n; +} + +void InputStream::skip(size_t bytes) { + char scratch[8192]; + while (bytes > 0) { + size_t amount = std::min(bytes, sizeof(scratch)); + read(scratch, amount); + bytes -= amount; + } +} + +void OutputStream::write(ArrayPtr> pieces) { + for (auto piece: pieces) { + write(piece.begin(), piece.size()); + } +} + +ArrayPtr BufferedInputStream::getReadBuffer() { + auto result = tryGetReadBuffer(); + KJ_REQUIRE(result.size() > 0, "Premature EOF"); + return result; +} + +// ======================================================================================= + +BufferedInputStreamWrapper::BufferedInputStreamWrapper(InputStream& inner, ArrayPtr buffer) + : inner(inner), ownedBuffer(buffer == nullptr ? heapArray(8192) : nullptr), + buffer(buffer == nullptr ? ownedBuffer : buffer) {} + +BufferedInputStreamWrapper::~BufferedInputStreamWrapper() noexcept(false) {} + +ArrayPtr BufferedInputStreamWrapper::tryGetReadBuffer() { + if (bufferAvailable.size() == 0) { + size_t n = inner.tryRead(buffer.begin(), 1, buffer.size()); + bufferAvailable = buffer.slice(0, n); + } + + return bufferAvailable; +} + +size_t BufferedInputStreamWrapper::tryRead(void* dst, size_t minBytes, size_t maxBytes) { + if (minBytes <= bufferAvailable.size()) { + // Serve from current buffer. + size_t n = std::min(bufferAvailable.size(), maxBytes); + memcpy(dst, bufferAvailable.begin(), n); + bufferAvailable = bufferAvailable.slice(n, bufferAvailable.size()); + return n; + } else { + // Copy current available into destination. + memcpy(dst, bufferAvailable.begin(), bufferAvailable.size()); + size_t fromFirstBuffer = bufferAvailable.size(); + + dst = reinterpret_cast(dst) + fromFirstBuffer; + minBytes -= fromFirstBuffer; + maxBytes -= fromFirstBuffer; + + if (maxBytes <= buffer.size()) { + // Read the next buffer-full. + size_t n = inner.read(buffer.begin(), minBytes, buffer.size()); + size_t fromSecondBuffer = std::min(n, maxBytes); + memcpy(dst, buffer.begin(), fromSecondBuffer); + bufferAvailable = buffer.slice(fromSecondBuffer, n); + return fromFirstBuffer + fromSecondBuffer; + } else { + // Forward large read to the underlying stream. + bufferAvailable = nullptr; + return fromFirstBuffer + inner.read(dst, minBytes, maxBytes); + } + } +} + +void BufferedInputStreamWrapper::skip(size_t bytes) { + if (bytes <= bufferAvailable.size()) { + bufferAvailable = bufferAvailable.slice(bytes, bufferAvailable.size()); + } else { + bytes -= bufferAvailable.size(); + if (bytes <= buffer.size()) { + // Read the next buffer-full. + size_t n = inner.read(buffer.begin(), bytes, buffer.size()); + bufferAvailable = buffer.slice(bytes, n); + } else { + // Forward large skip to the underlying stream. + bufferAvailable = nullptr; + inner.skip(bytes); + } + } +} + +// ------------------------------------------------------------------- + +BufferedOutputStreamWrapper::BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr buffer) + : inner(inner), + ownedBuffer(buffer == nullptr ? heapArray(8192) : nullptr), + buffer(buffer == nullptr ? ownedBuffer : buffer), + bufferPos(this->buffer.begin()) {} + +BufferedOutputStreamWrapper::~BufferedOutputStreamWrapper() noexcept(false) { + unwindDetector.catchExceptionsIfUnwinding([&]() { + flush(); + }); +} + +void BufferedOutputStreamWrapper::flush() { + if (bufferPos > buffer.begin()) { + inner.write(buffer.begin(), bufferPos - buffer.begin()); + bufferPos = buffer.begin(); + } +} + +ArrayPtr BufferedOutputStreamWrapper::getWriteBuffer() { + return arrayPtr(bufferPos, buffer.end()); +} + +void BufferedOutputStreamWrapper::write(const void* src, size_t size) { + if (src == bufferPos) { + // Oh goody, the caller wrote directly into our buffer. + bufferPos += size; + } else { + size_t available = buffer.end() - bufferPos; + + if (size <= available) { + memcpy(bufferPos, src, size); + bufferPos += size; + } else if (size <= buffer.size()) { + // Too much for this buffer, but not a full buffer's worth, so we'll go ahead and copy. + memcpy(bufferPos, src, available); + inner.write(buffer.begin(), buffer.size()); + + size -= available; + src = reinterpret_cast(src) + available; + + memcpy(buffer.begin(), src, size); + bufferPos = buffer.begin() + size; + } else { + // Writing so much data that we might as well write directly to avoid a copy. + inner.write(buffer.begin(), bufferPos - buffer.begin()); + bufferPos = buffer.begin(); + inner.write(src, size); + } + } +} + +// ======================================================================================= + +ArrayInputStream::ArrayInputStream(ArrayPtr array): array(array) {} +ArrayInputStream::~ArrayInputStream() noexcept(false) {} + +ArrayPtr ArrayInputStream::tryGetReadBuffer() { + return array; +} + +size_t ArrayInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) { + size_t n = std::min(maxBytes, array.size()); + memcpy(dst, array.begin(), n); + array = array.slice(n, array.size()); + return n; +} + +void ArrayInputStream::skip(size_t bytes) { + KJ_REQUIRE(array.size() >= bytes, "ArrayInputStream ended prematurely.") { + bytes = array.size(); + break; + } + array = array.slice(bytes, array.size()); +} + +// ------------------------------------------------------------------- + +ArrayOutputStream::ArrayOutputStream(ArrayPtr array): array(array), fillPos(array.begin()) {} +ArrayOutputStream::~ArrayOutputStream() noexcept(false) {} + +ArrayPtr ArrayOutputStream::getWriteBuffer() { + return arrayPtr(fillPos, array.end()); +} + +void ArrayOutputStream::write(const void* src, size_t size) { + if (src == fillPos) { + // Oh goody, the caller wrote directly into our buffer. + KJ_REQUIRE(size <= array.end() - fillPos); + fillPos += size; + } else { + KJ_REQUIRE(size <= (size_t)(array.end() - fillPos), + "ArrayOutputStream's backing array was not large enough for the data written."); + memcpy(fillPos, src, size); + fillPos += size; + } +} + +// ------------------------------------------------------------------- + +VectorOutputStream::VectorOutputStream(size_t initialCapacity) + : vector(heapArray(initialCapacity)), fillPos(vector.begin()) {} +VectorOutputStream::~VectorOutputStream() noexcept(false) {} + +ArrayPtr VectorOutputStream::getWriteBuffer() { + // Grow if needed. + if (fillPos == vector.end()) { + grow(vector.size() + 1); + } + + return arrayPtr(fillPos, vector.end()); +} + +void VectorOutputStream::write(const void* src, size_t size) { + if (src == fillPos) { + // Oh goody, the caller wrote directly into our buffer. + KJ_REQUIRE(size <= vector.end() - fillPos); + fillPos += size; + } else { + if (vector.end() - fillPos < size) { + grow(fillPos - vector.begin() + size); + } + + memcpy(fillPos, src, size); + fillPos += size; + } +} + +void VectorOutputStream::grow(size_t minSize) { + size_t newSize = vector.size() * 2; + while (newSize < minSize) newSize *= 2; + auto newVector = heapArray(newSize); + memcpy(newVector.begin(), vector.begin(), fillPos - vector.begin()); + fillPos = fillPos - vector.begin() + newVector.begin(); + vector = kj::mv(newVector); +} + +// ======================================================================================= + +AutoCloseFd::~AutoCloseFd() noexcept(false) { + if (fd >= 0) { + unwindDetector.catchExceptionsIfUnwinding([&]() { + // Don't use SYSCALL() here because close() should not be repeated on EINTR. + if (miniposix::close(fd) < 0) { + KJ_FAIL_SYSCALL("close", errno, fd) { + break; + } + } + }); + } +} + +FdInputStream::~FdInputStream() noexcept(false) {} + +size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) { + byte* pos = reinterpret_cast(buffer); + byte* min = pos + minBytes; + byte* max = pos + maxBytes; + + while (pos < min) { + miniposix::ssize_t n; + KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd); + if (n == 0) { + break; + } + pos += n; + } + + return pos - reinterpret_cast(buffer); +} + +FdOutputStream::~FdOutputStream() noexcept(false) {} + +void FdOutputStream::write(const void* buffer, size_t size) { + const char* pos = reinterpret_cast(buffer); + + while (size > 0) { + miniposix::ssize_t n; + KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd); + KJ_ASSERT(n > 0, "write() returned zero."); + pos += n; + size -= n; + } +} + +void FdOutputStream::write(ArrayPtr> pieces) { +#if _WIN32 + // Windows has no reasonable writev(). It has WriteFileGather, but this call has the unreasonable + // restriction that each segment must be page-aligned. So, fall back to the default implementation + + OutputStream::write(pieces); + +#else + const size_t iovmax = miniposix::iovMax(pieces.size()); + while (pieces.size() > iovmax) { + write(pieces.slice(0, iovmax)); + pieces = pieces.slice(iovmax, pieces.size()); + } + + KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128); + + for (uint i = 0; i < pieces.size(); i++) { + // writev() interface is not const-correct. :( + iov[i].iov_base = const_cast(pieces[i].begin()); + iov[i].iov_len = pieces[i].size(); + } + + struct iovec* current = iov.begin(); + + // Advance past any leading empty buffers so that a write full of only empty buffers does not + // cause a syscall at all. + while (current < iov.end() && current->iov_len == 0) { + ++current; + } + + while (current < iov.end()) { + // Issue the write. + ssize_t n = 0; + KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd); + KJ_ASSERT(n > 0, "writev() returned zero."); + + // Advance past all buffers that were fully-written. + while (current < iov.end() && static_cast(n) >= current->iov_len) { + n -= current->iov_len; + ++current; + } + + // If we only partially-wrote one of the buffers, adjust the pointer and size to include only + // the unwritten part. + if (n > 0) { + current->iov_base = reinterpret_cast(current->iov_base) + n; + current->iov_len -= n; + } + } +#endif +} + +// ======================================================================================= + +#if _WIN32 + +AutoCloseHandle::~AutoCloseHandle() noexcept(false) { + if (handle != (void*)-1) { + KJ_WIN32(CloseHandle(handle)); + } +} + +HandleInputStream::~HandleInputStream() noexcept(false) {} + +size_t HandleInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) { + byte* pos = reinterpret_cast(buffer); + byte* min = pos + minBytes; + byte* max = pos + maxBytes; + + while (pos < min) { + DWORD n; + KJ_WIN32(ReadFile(handle, pos, kj::min(max - pos, DWORD(kj::maxValue)), &n, nullptr)); + if (n == 0) { + break; + } + pos += n; + } + + return pos - reinterpret_cast(buffer); +} + +HandleOutputStream::~HandleOutputStream() noexcept(false) {} + +void HandleOutputStream::write(const void* buffer, size_t size) { + const char* pos = reinterpret_cast(buffer); + + while (size > 0) { + DWORD n; + KJ_WIN32(WriteFile(handle, pos, kj::min(size, DWORD(kj::maxValue)), &n, nullptr)); + KJ_ASSERT(n > 0, "write() returned zero."); + pos += n; + size -= n; + } +} + +#endif // _WIN32 + +} // namespace kj diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/io.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/io.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,419 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_IO_H_ +#define KJ_IO_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include +#include "common.h" +#include "array.h" +#include "exception.h" + +namespace kj { + +// ======================================================================================= +// Abstract interfaces + +class InputStream { +public: + virtual ~InputStream() noexcept(false); + + size_t read(void* buffer, size_t minBytes, size_t maxBytes); + // Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns + // the size read. Throws an exception on errors. Implemented in terms of tryRead(). + // + // maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount + // needed by the caller before it can start doing useful processing. If the stream returns less + // than maxBytes, the caller will usually call read() again later to get the rest. Returning + // less than maxBytes is useful when it makes sense for the caller to parallelize processing + // with I/O. + // + // Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may + // attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes. + // To detect EOF without throwing an exception, use tryRead(). + // + // If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not + // expected to understand how to deal with partial reads. + + virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0; + // Like read(), but may return fewer than minBytes on EOF. + + inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); } + // Convenience method for reading an exact number of bytes. + + virtual void skip(size_t bytes); + // Skips past the given number of bytes, discarding them. The default implementation read()s + // into a scratch buffer. +}; + +class OutputStream { +public: + virtual ~OutputStream() noexcept(false); + + virtual void write(const void* buffer, size_t size) = 0; + // Always writes the full size. Throws exception on error. + + virtual void write(ArrayPtr> pieces); + // Equivalent to write()ing each byte array in sequence, which is what the default implementation + // does. Override if you can do something better, e.g. use writev() to do the write in a single + // syscall. +}; + +class BufferedInputStream: public InputStream { + // An input stream which buffers some bytes in memory to reduce system call overhead. + // - OR - + // An input stream that actually reads from some in-memory data structure and wants to give its + // caller a direct pointer to that memory to potentially avoid a copy. + +public: + virtual ~BufferedInputStream() noexcept(false); + + ArrayPtr getReadBuffer(); + // Get a direct pointer into the read buffer, which contains the next bytes in the input. If the + // caller consumes any bytes, it should then call skip() to indicate this. This always returns a + // non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer(). + + virtual ArrayPtr tryGetReadBuffer() = 0; + // Like getReadBuffer() but may return an empty buffer on EOF. +}; + +class BufferedOutputStream: public OutputStream { + // An output stream which buffers some bytes in memory to reduce system call overhead. + // - OR - + // An output stream that actually writes into some in-memory data structure and wants to give its + // caller a direct pointer to that memory to potentially avoid a copy. + +public: + virtual ~BufferedOutputStream() noexcept(false); + + virtual ArrayPtr getWriteBuffer() = 0; + // Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of + // this buffer and then pass it to write(), in which case write() may avoid a copy. It is + // incorrect to pass to write any slice of this buffer which is not a prefix. +}; + +// ======================================================================================= +// Buffered streams implemented as wrappers around regular streams + +class BufferedInputStreamWrapper: public BufferedInputStream { + // Implements BufferedInputStream in terms of an InputStream. + // + // Note that the underlying stream's position is unpredictable once the wrapper is destroyed, + // unless the entire stream was consumed. To read a predictable number of bytes in a buffered + // way without going over, you'd need this wrapper to wrap some other wrapper which itself + // implements an artificial EOF at the desired point. Such a stream should be trivial to write + // but is not provided by the library at this time. + +public: + explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr buffer = nullptr); + // Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about + // the position of the inner stream after a buffered wrapper has been created unless the entire + // input is read. + // + // If the second parameter is non-null, the stream uses the given buffer instead of allocating + // its own. This may improve performance if the buffer can be reused. + + KJ_DISALLOW_COPY(BufferedInputStreamWrapper); + ~BufferedInputStreamWrapper() noexcept(false); + + // implements BufferedInputStream ---------------------------------- + ArrayPtr tryGetReadBuffer() override; + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + InputStream& inner; + Array ownedBuffer; + ArrayPtr buffer; + ArrayPtr bufferAvailable; +}; + +class BufferedOutputStreamWrapper: public BufferedOutputStream { + // Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the + // underlying stream may be delayed until flush() is called or the wrapper is destroyed. + +public: + explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr buffer = nullptr); + // Creates a buffered stream wrapping the given non-buffered stream. + // + // If the second parameter is non-null, the stream uses the given buffer instead of allocating + // its own. This may improve performance if the buffer can be reused. + + KJ_DISALLOW_COPY(BufferedOutputStreamWrapper); + ~BufferedOutputStreamWrapper() noexcept(false); + + void flush(); + // Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that + // this only flushes this object's buffer; this object has no idea how to flush any other buffers + // that may be present in the underlying stream. + + // implements BufferedOutputStream --------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + OutputStream& inner; + Array ownedBuffer; + ArrayPtr buffer; + byte* bufferPos; + UnwindDetector unwindDetector; +}; + +// ======================================================================================= +// Array I/O + +class ArrayInputStream: public BufferedInputStream { +public: + explicit ArrayInputStream(ArrayPtr array); + KJ_DISALLOW_COPY(ArrayInputStream); + ~ArrayInputStream() noexcept(false); + + // implements BufferedInputStream ---------------------------------- + ArrayPtr tryGetReadBuffer() override; + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + void skip(size_t bytes) override; + +private: + ArrayPtr array; +}; + +class ArrayOutputStream: public BufferedOutputStream { +public: + explicit ArrayOutputStream(ArrayPtr array); + KJ_DISALLOW_COPY(ArrayOutputStream); + ~ArrayOutputStream() noexcept(false); + + ArrayPtr getArray() { + // Get the portion of the array which has been filled in. + return arrayPtr(array.begin(), fillPos); + } + + // implements BufferedInputStream ---------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + ArrayPtr array; + byte* fillPos; +}; + +class VectorOutputStream: public BufferedOutputStream { +public: + explicit VectorOutputStream(size_t initialCapacity = 4096); + KJ_DISALLOW_COPY(VectorOutputStream); + ~VectorOutputStream() noexcept(false); + + ArrayPtr getArray() { + // Get the portion of the array which has been filled in. + return arrayPtr(vector.begin(), fillPos); + } + + // implements BufferedInputStream ---------------------------------- + ArrayPtr getWriteBuffer() override; + void write(const void* buffer, size_t size) override; + +private: + Array vector; + byte* fillPos; + + void grow(size_t minSize); +}; + +// ======================================================================================= +// File descriptor I/O + +class AutoCloseFd { + // A wrapper around a file descriptor which automatically closes the descriptor when destroyed. + // The wrapper supports move construction for transferring ownership of the descriptor. If + // close() returns an error, the destructor throws an exception, UNLESS the destructor is being + // called during unwind from another exception, in which case the close error is ignored. + // + // If your code is not exception-safe, you should not use AutoCloseFd. In this case you will + // have to call close() yourself and handle errors appropriately. + +public: + inline AutoCloseFd(): fd(-1) {} + inline AutoCloseFd(decltype(nullptr)): fd(-1) {} + inline explicit AutoCloseFd(int fd): fd(fd) {} + inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; } + KJ_DISALLOW_COPY(AutoCloseFd); + ~AutoCloseFd() noexcept(false); + + inline AutoCloseFd& operator=(AutoCloseFd&& other) { + AutoCloseFd old(kj::mv(*this)); + fd = other.fd; + other.fd = -1; + return *this; + } + + inline AutoCloseFd& operator=(decltype(nullptr)) { + AutoCloseFd old(kj::mv(*this)); + return *this; + } + + inline operator int() const { return fd; } + inline int get() const { return fd; } + + operator bool() const = delete; + // Deleting this operator prevents accidental use in boolean contexts, which + // the int conversion operator above would otherwise allow. + + inline bool operator==(decltype(nullptr)) { return fd < 0; } + inline bool operator!=(decltype(nullptr)) { return fd >= 0; } + +private: + int fd; + UnwindDetector unwindDetector; +}; + +inline auto KJ_STRINGIFY(const AutoCloseFd& fd) + -> decltype(kj::toCharSequence(implicitCast(fd))) { + return kj::toCharSequence(implicitCast(fd)); +} + +class FdInputStream: public InputStream { + // An InputStream wrapping a file descriptor. + +public: + explicit FdInputStream(int fd): fd(fd) {} + explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} + KJ_DISALLOW_COPY(FdInputStream); + ~FdInputStream() noexcept(false); + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + + inline int getFd() const { return fd; } + +private: + int fd; + AutoCloseFd autoclose; +}; + +class FdOutputStream: public OutputStream { + // An OutputStream wrapping a file descriptor. + +public: + explicit FdOutputStream(int fd): fd(fd) {} + explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {} + KJ_DISALLOW_COPY(FdOutputStream); + ~FdOutputStream() noexcept(false); + + void write(const void* buffer, size_t size) override; + void write(ArrayPtr> pieces) override; + + inline int getFd() const { return fd; } + +private: + int fd; + AutoCloseFd autoclose; +}; + +// ======================================================================================= +// Win32 Handle I/O + +#ifdef _WIN32 + +class AutoCloseHandle { + // A wrapper around a Win32 HANDLE which automatically closes the handle when destroyed. + // The wrapper supports move construction for transferring ownership of the handle. If + // CloseHandle() returns an error, the destructor throws an exception, UNLESS the destructor is + // being called during unwind from another exception, in which case the close error is ignored. + // + // If your code is not exception-safe, you should not use AutoCloseHandle. In this case you will + // have to call close() yourself and handle errors appropriately. + +public: + inline AutoCloseHandle(): handle((void*)-1) {} + inline AutoCloseHandle(decltype(nullptr)): handle((void*)-1) {} + inline explicit AutoCloseHandle(void* handle): handle(handle) {} + inline AutoCloseHandle(AutoCloseHandle&& other) noexcept: handle(other.handle) { + other.handle = (void*)-1; + } + KJ_DISALLOW_COPY(AutoCloseHandle); + ~AutoCloseHandle() noexcept(false); + + inline AutoCloseHandle& operator=(AutoCloseHandle&& other) { + AutoCloseHandle old(kj::mv(*this)); + handle = other.handle; + other.handle = (void*)-1; + return *this; + } + + inline AutoCloseHandle& operator=(decltype(nullptr)) { + AutoCloseHandle old(kj::mv(*this)); + return *this; + } + + inline operator void*() const { return handle; } + inline void* get() const { return handle; } + + operator bool() const = delete; + // Deleting this operator prevents accidental use in boolean contexts, which + // the void* conversion operator above would otherwise allow. + + inline bool operator==(decltype(nullptr)) { return handle != (void*)-1; } + inline bool operator!=(decltype(nullptr)) { return handle == (void*)-1; } + +private: + void* handle; // -1 (aka INVALID_HANDLE_VALUE) if not valid. +}; + +class HandleInputStream: public InputStream { + // An InputStream wrapping a Win32 HANDLE. + +public: + explicit HandleInputStream(void* handle): handle(handle) {} + explicit HandleInputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {} + KJ_DISALLOW_COPY(HandleInputStream); + ~HandleInputStream() noexcept(false); + + size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; + +private: + void* handle; + AutoCloseHandle autoclose; +}; + +class HandleOutputStream: public OutputStream { + // An OutputStream wrapping a Win32 HANDLE. + +public: + explicit HandleOutputStream(void* handle): handle(handle) {} + explicit HandleOutputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {} + KJ_DISALLOW_COPY(HandleOutputStream); + ~HandleOutputStream() noexcept(false); + + void write(const void* buffer, size_t size) override; + +private: + void* handle; + AutoCloseHandle autoclose; +}; + +#endif // _WIN32 + +} // namespace kj + +#endif // KJ_IO_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/main.c++ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/main.c++ Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,823 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "main.h" +#include "debug.h" +#include "arena.h" +#include "miniposix.h" +#include +#include +#include +#include +#include + +#if _WIN32 +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include +#include "windows-sanity.h" +#else +#include +#endif + +namespace kj { + +// ======================================================================================= + +TopLevelProcessContext::TopLevelProcessContext(StringPtr programName) + : programName(programName), + cleanShutdown(getenv("KJ_CLEAN_SHUTDOWN") != nullptr) { + printStackTraceOnCrash(); +} + +StringPtr TopLevelProcessContext::getProgramName() { + return programName; +} + +void TopLevelProcessContext::exit() { + int exitCode = hadErrors ? 1 : 0; + if (cleanShutdown) { +#if KJ_NO_EXCEPTIONS + // This is the best we can do. + warning("warning: KJ_CLEAN_SHUTDOWN may not work correctly when compiled " + "with -fno-exceptions."); + ::exit(exitCode); +#else + throw CleanShutdownException { exitCode }; +#endif + } + _exit(exitCode); +} + +#if _WIN32 +void setStandardIoMode(int fd) { + // Set mode to binary if the fd is not a console. + HANDLE handle = reinterpret_cast(_get_osfhandle(fd)); + DWORD consoleMode; + if (GetConsoleMode(handle, &consoleMode)) { + // It's a console. + } else { + KJ_SYSCALL(_setmode(fd, _O_BINARY)); + } +} +#else +void setStandardIoMode(int fd) {} +#endif + +static void writeLineToFd(int fd, StringPtr message) { + // Write the given message to the given file descriptor with a trailing newline iff the message + // is non-empty and doesn't already have a trailing newline. We use writev() to do this in a + // single system call without any copying (OS permitting). + + if (message.size() == 0) { + return; + } + +#if _WIN32 + KJ_STACK_ARRAY(char, newlineExpansionBuffer, 2 * (message.size() + 1), 128, 512); + char* p = newlineExpansionBuffer.begin(); + for(char ch : message) { + if(ch == '\n') { + *(p++) = '\r'; + } + *(p++) = ch; + } + if(!message.endsWith("\n")) { + *(p++) = '\r'; + *(p++) = '\n'; + } + + size_t newlineExpandedSize = p - newlineExpansionBuffer.begin(); + + KJ_ASSERT(newlineExpandedSize <= newlineExpansionBuffer.size()); + + HANDLE handle = reinterpret_cast(_get_osfhandle(fd)); + DWORD consoleMode; + bool redirectedToFile = !GetConsoleMode(handle, &consoleMode); + + DWORD writtenSize; + if(redirectedToFile) { + WriteFile(handle, newlineExpansionBuffer.begin(), newlineExpandedSize, &writtenSize, nullptr); + } else { + KJ_STACK_ARRAY(wchar_t, buffer, newlineExpandedSize, 128, 512); + + size_t finalSize = MultiByteToWideChar( + CP_UTF8, + 0, + newlineExpansionBuffer.begin(), + newlineExpandedSize, + buffer.begin(), + buffer.size()); + + KJ_ASSERT(finalSize <= buffer.size()); + + WriteConsoleW(handle, buffer.begin(), finalSize, &writtenSize, nullptr); + } +#else + // Unfortunately the writev interface requires non-const pointers even though it won't modify + // the data. + struct iovec vec[2]; + vec[0].iov_base = const_cast(message.begin()); + vec[0].iov_len = message.size(); + vec[1].iov_base = const_cast("\n"); + vec[1].iov_len = 1; + + struct iovec* pos = vec; + + // Only use the second item in the vec if the message doesn't already end with \n. + uint count = message.endsWith("\n") ? 1 : 2; + + for (;;) { + ssize_t n = writev(fd, pos, count); + if (n < 0) { + if (errno == EINTR) { + continue; + } else { + // This function is meant for writing to stdout and stderr. If writes fail on those FDs + // there's not a whole lot we can reasonably do, so just ignore it. + return; + } + } + + // Update chunks to discard what was successfully written. + for (;;) { + if (count == 0) { + // Done writing. + return; + } else if (pos->iov_len <= implicitCast(n)) { + // Wrote this entire chunk. + n -= pos->iov_len; + ++pos; + --count; + } else { + // Wrote only part of this chunk. Adjust the pointer and then retry. + pos->iov_base = reinterpret_cast(pos->iov_base) + n; + pos->iov_len -= n; + break; + } + } + } +#endif +} + +void TopLevelProcessContext::warning(StringPtr message) { + writeLineToFd(STDERR_FILENO, message); +} + +void TopLevelProcessContext::error(StringPtr message) { + hadErrors = true; + writeLineToFd(STDERR_FILENO, message); +} + +void TopLevelProcessContext::exitError(StringPtr message) { + error(message); + exit(); +} + +void TopLevelProcessContext::exitInfo(StringPtr message) { + writeLineToFd(STDOUT_FILENO, message); + exit(); +} + +void TopLevelProcessContext::increaseLoggingVerbosity() { + // At the moment, there is only one log level that isn't enabled by default. + _::Debug::setLogLevel(_::Debug::Severity::INFO); +} + +// ======================================================================================= + +int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]) { + setStandardIoMode(STDIN_FILENO); + setStandardIoMode(STDOUT_FILENO); + setStandardIoMode(STDERR_FILENO); + +#if !KJ_NO_EXCEPTIONS + try { +#endif + KJ_ASSERT(argc > 0); + + KJ_STACK_ARRAY(StringPtr, params, argc - 1, 8, 32); + for (int i = 1; i < argc; i++) { + params[i - 1] = argv[i]; + } + + KJ_IF_MAYBE(exception, runCatchingExceptions([&]() { + func(argv[0], params); + })) { + context.error(str("*** Uncaught exception ***\n", *exception)); + } + context.exit(); +#if !KJ_NO_EXCEPTIONS + } catch (const TopLevelProcessContext::CleanShutdownException& e) { + return e.exitCode; + } +#endif + KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT +} + +// ======================================================================================= + +struct MainBuilder::Impl { + inline Impl(ProcessContext& context, StringPtr version, + StringPtr briefDescription, StringPtr extendedDescription) + : context(context), version(version), + briefDescription(briefDescription), extendedDescription(extendedDescription) {} + + ProcessContext& context; + StringPtr version; + StringPtr briefDescription; + StringPtr extendedDescription; + + Arena arena; + + struct CharArrayCompare { + inline bool operator()(const ArrayPtr& a, const ArrayPtr& b) const { + int cmp = memcmp(a.begin(), b.begin(), min(a.size(), b.size())); + if (cmp == 0) { + return a.size() < b.size(); + } else { + return cmp < 0; + } + } + }; + + struct Option { + ArrayPtr names; + bool hasArg; + union { + Function* func; + Function* funcWithArg; + }; + StringPtr argTitle; + StringPtr helpText; + }; + + class OptionDisplayOrder; + + std::map shortOptions; + std::map, Option*, CharArrayCompare> longOptions; + + struct SubCommand { + Function func; + StringPtr helpText; + }; + std::map subCommands; + + struct Arg { + StringPtr title; + Function callback; + uint minCount; + uint maxCount; + }; + + Vector args; + + Maybe> finalCallback; + + Option& addOption(std::initializer_list names, bool hasArg, StringPtr helpText) { + KJ_REQUIRE(names.size() > 0, "option must have at least one name"); + + Option& option = arena.allocate, BoundedConst) { + return bounded(); +} +template +inline constexpr BoundedConst max(BoundedConst, BoundedConst) { + return bounded(); +} +// We need to override min() and max() between constants because the ternary operator in the +// default implementation would complain. + +// ------------------------------------------------------------------- + +template +class Bounded { +public: + static_assert(maxN <= T(kj::maxValue), "possible overflow detected"); + + Bounded() = default; + + Bounded(const Bounded& other) = default; + template ()>> + inline constexpr Bounded(OtherInt value): value(value) { + static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); + } + template + inline constexpr Bounded(const Bounded& other) + : value(other.value) { + static_assert(otherMax <= maxN, "possible overflow detected"); + } + template + inline constexpr Bounded(BoundedConst) + : value(otherValue) { + static_assert(otherValue <= maxN, "overflow detected"); + } + + Bounded& operator=(const Bounded& other) = default; + template ()>> + Bounded& operator=(OtherInt other) { + static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); + value = other; + return *this; + } + template + inline Bounded& operator=(const Bounded& other) { + static_assert(otherMax <= maxN, "possible overflow detected"); + value = other.value; + return *this; + } + template + inline Bounded& operator=(BoundedConst) { + static_assert(otherValue <= maxN, "overflow detected"); + value = otherValue; + return *this; + } + + inline constexpr T unwrap() const { return value; } + +#define OP(op, newMax) \ + template \ + inline constexpr Bounded \ + operator op(const Bounded& other) const { \ + return Bounded(value op other.value, unsafe); \ + } +#define COMPARE_OP(op) \ + template \ + inline constexpr bool operator op(const Bounded& other) const { \ + return value op other.value; \ + } + + OP(+, (boundedAdd())) + OP(*, (boundedMul())) + OP(/, maxN) + OP(%, otherMax - 1) + + // operator- is intentionally omitted because we mostly use this with unsigned types, and + // subtraction requires proof that subtrahend is not greater than the minuend. + + COMPARE_OP(==) + COMPARE_OP(!=) + COMPARE_OP(< ) + COMPARE_OP(> ) + COMPARE_OP(<=) + COMPARE_OP(>=) + +#undef OP +#undef COMPARE_OP + + template + inline Bounded assertMax(ErrorFunc&& func) const { + // Assert that the number is no more than `newMax`. Otherwise, call `func`. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + if (KJ_UNLIKELY(value > newMax)) func(); + return Bounded(value, unsafe); + } + + template + inline Bounded subtractChecked( + const Bounded& other, ErrorFunc&& func) const { + // Subtract a number, calling func() if the result would underflow. + if (KJ_UNLIKELY(value < other.value)) func(); + return Bounded(value - other.value, unsafe); + } + + template + inline Bounded subtractChecked( + BoundedConst, ErrorFunc&& func) const { + // Subtract a number, calling func() if the result would underflow. + static_assert(otherValue <= maxN, "underflow detected"); + if (KJ_UNLIKELY(value < otherValue)) func(); + return Bounded(value - otherValue, unsafe); + } + + template + inline Maybe> trySubtract( + const Bounded& other) const { + // Subtract a number, calling func() if the result would underflow. + if (value < other.value) { + return nullptr; + } else { + return Bounded(value - other.value, unsafe); + } + } + + template + inline Maybe> trySubtract(BoundedConst) const { + // Subtract a number, calling func() if the result would underflow. + if (value < otherValue) { + return nullptr; + } else { + return Bounded(value - otherValue, unsafe); + } + } + + inline constexpr Bounded(T value, decltype(unsafe)): value(value) {} + template + inline constexpr Bounded(Bounded value, decltype(unsafe)) + : value(value.value) {} + // Mainly for internal use. + // + // Only use these as a last resort, with ample commentary on why you think it's safe. + +private: + T value; + + template + friend class Bounded; +}; + +template +inline constexpr Bounded bounded(Number value) { + return Bounded(value, unsafe); +} + +inline constexpr Bounded<1, uint8_t> bounded(bool value) { + return Bounded<1, uint8_t>(value, unsafe); +} + +template +inline constexpr Bounded(), Number> assumeBits(Number value) { + return Bounded(), Number>(value, unsafe); +} + +template +inline constexpr Bounded(), T> assumeBits(Bounded value) { + return Bounded(), T>(value, unsafe); +} + +template +inline constexpr auto assumeBits(Quantity value) + -> Quantity(value / unit>())), Unit> { + return Quantity(value / unit>())), Unit>( + assumeBits(value / unit>()), unsafe); +} + +template +inline constexpr Bounded assumeMax(Number value) { + return Bounded(value, unsafe); +} + +template +inline constexpr Bounded assumeMax(Bounded value) { + return Bounded(value, unsafe); +} + +template +inline constexpr auto assumeMax(Quantity value) + -> Quantity(value / unit>())), Unit> { + return Quantity(value / unit>())), Unit>( + assumeMax(value / unit>()), unsafe); +} + +template +inline constexpr Bounded assumeMax(BoundedConst, Number value) { + return assumeMax(value); +} + +template +inline constexpr Bounded assumeMax(BoundedConst, Bounded value) { + return assumeMax(value); +} + +template +inline constexpr auto assumeMax(Quantity, Unit>, Quantity value) + -> decltype(assumeMax(value)) { + return assumeMax(value); +} + +template +inline Bounded assertMax(Bounded value, ErrorFunc&& errorFunc) { + // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() + // if not. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + return value.template assertMax(kj::fwd(errorFunc)); +} + +template +inline Quantity, Unit> assertMax( + Quantity, Unit> value, ErrorFunc&& errorFunc) { + // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() + // if not. + static_assert(newMax < maxN, "this bounded size assertion is redundant"); + return (value / unit()).template assertMax( + kj::fwd(errorFunc)) * unit(); +} + +template +inline Bounded assertMax( + BoundedConst, Bounded value, ErrorFunc&& errorFunc) { + return assertMax(value, kj::mv(errorFunc)); +} + +template +inline Quantity, Unit> assertMax( + Quantity, Unit>, + Quantity, Unit> value, ErrorFunc&& errorFunc) { + return assertMax(value, kj::mv(errorFunc)); +} + +template +inline Bounded(), T> assertMaxBits( + Bounded value, ErrorFunc&& errorFunc = ErrorFunc()) { + // Assert that the bounded value requires no more than the given number of bits, calling + // errorFunc() if not. + return assertMax()>(value, kj::fwd(errorFunc)); +} + +template +inline Quantity(), T>, Unit> assertMaxBits( + Quantity, Unit> value, ErrorFunc&& errorFunc = ErrorFunc()) { + // Assert that the bounded value requires no more than the given number of bits, calling + // errorFunc() if not. + return assertMax()>(value, kj::fwd(errorFunc)); +} + +template +inline constexpr Bounded upgradeBound(Bounded value) { + return value; +} + +template +inline constexpr Quantity, Unit> upgradeBound( + Quantity, Unit> value) { + return value; +} + +template +inline auto subtractChecked(Bounded value, Other other, ErrorFunc&& errorFunc) + -> decltype(value.subtractChecked(other, kj::fwd(errorFunc))) { + return value.subtractChecked(other, kj::fwd(errorFunc)); +} + +template +inline auto subtractChecked(Quantity value, Quantity other, ErrorFunc&& errorFunc) + -> Quantity(errorFunc))), Unit> { + return subtractChecked(value / unit>(), + other / unit>(), + kj::fwd(errorFunc)) + * unit>(); +} + +template +inline auto trySubtract(Bounded value, Other other) + -> decltype(value.trySubtract(other)) { + return value.trySubtract(other); +} + +template +inline auto trySubtract(Quantity value, Quantity other) + -> Maybe> { + return trySubtract(value / unit>(), + other / unit>()) + .map([](decltype(subtractChecked(T(), U(), int())) x) { + return x * unit>(); + }); +} + +template +inline constexpr Bounded> +min(Bounded a, Bounded b) { + return Bounded>(kj::min(a.unwrap(), b.unwrap()), unsafe); +} +template +inline constexpr Bounded> +max(Bounded a, Bounded b) { + return Bounded>(kj::max(a.unwrap(), b.unwrap()), unsafe); +} +// We need to override min() and max() because: +// 1) WiderType<> might not choose the correct bounds. +// 2) One of the two sides of the ternary operator in the default implementation would fail to +// typecheck even though it is OK in practice. + +// ------------------------------------------------------------------- +// Operators between Bounded and BoundedConst + +#define OP(op, newMax) \ +template \ +inline constexpr Bounded<(newMax), decltype(T() op uint())> operator op( \ + Bounded value, BoundedConst) { \ + return Bounded<(newMax), decltype(T() op uint())>(value.unwrap() op cvalue, unsafe); \ +} + +#define REVERSE_OP(op, newMax) \ +template \ +inline constexpr Bounded<(newMax), decltype(uint() op T())> operator op( \ + BoundedConst, Bounded value) { \ + return Bounded<(newMax), decltype(uint() op T())>(cvalue op value.unwrap(), unsafe); \ +} + +#define COMPARE_OP(op) \ +template \ +inline constexpr bool operator op(Bounded value, BoundedConst) { \ + return value.unwrap() op cvalue; \ +} \ +template \ +inline constexpr bool operator op(BoundedConst, Bounded value) { \ + return cvalue op value.unwrap(); \ +} + +OP(+, (boundedAdd())) +REVERSE_OP(+, (boundedAdd())) + +OP(*, (boundedMul())) +REVERSE_OP(*, (boundedAdd())) + +OP(/, maxN / cvalue) +REVERSE_OP(/, cvalue) // denominator could be 1 + +OP(%, cvalue - 1) +REVERSE_OP(%, maxN - 1) + +OP(<<, (boundedLShift())) +REVERSE_OP(<<, (boundedLShift())) + +OP(>>, maxN >> cvalue) +REVERSE_OP(>>, cvalue >> maxN) + +OP(&, maxValueForBits()>() & cvalue) +REVERSE_OP(&, maxValueForBits()>() & cvalue) + +OP(|, maxN | cvalue) +REVERSE_OP(|, maxN | cvalue) + +COMPARE_OP(==) +COMPARE_OP(!=) +COMPARE_OP(< ) +COMPARE_OP(> ) +COMPARE_OP(<=) +COMPARE_OP(>=) + +#undef OP +#undef REVERSE_OP +#undef COMPARE_OP + +template +inline constexpr Bounded + operator-(BoundedConst, Bounded value) { + // We allow subtraction of a variable from a constant only if the constant is greater than or + // equal to the maximum possible value of the variable. Since the variable could be zero, the + // result can be as large as the constant. + // + // We do not allow subtraction of a constant from a variable because there's never a guarantee it + // won't underflow (unless the constant is zero, which is silly). + static_assert(cvalue >= maxN, "possible underflow detected"); + return Bounded(cvalue - value.unwrap(), unsafe); +} + +template +inline constexpr Bounded min(Bounded a, BoundedConst) { + return Bounded(kj::min(b, a.unwrap()), unsafe); +} +template +inline constexpr Bounded min(BoundedConst, Bounded a) { + return Bounded(kj::min(a.unwrap(), b), unsafe); +} +template +inline constexpr Bounded max(Bounded a, BoundedConst) { + return Bounded(kj::max(b, a.unwrap()), unsafe); +} +template +inline constexpr Bounded max(BoundedConst, Bounded a) { + return Bounded(kj::max(a.unwrap(), b), unsafe); +} +// We need to override min() between a Bounded and a constant since: +// 1) WiderType<> might choose BoundedConst over a 1-byte Bounded, which is wrong. +// 2) To clamp the bounds of the output type. +// 3) Same ternary operator typechecking issues. + +// ------------------------------------------------------------------- + +template +class SafeUnwrapper { +public: + inline explicit constexpr SafeUnwrapper(Bounded value): value(value.unwrap()) {} + + template ()>> + inline constexpr operator U() const { + static_assert(maxN <= U(maxValue), "possible truncation detected"); + return value; + } + + inline constexpr operator bool() const { + static_assert(maxN <= 1, "possible truncation detected"); + return value; + } + +private: + T value; +}; + +template +inline constexpr SafeUnwrapper unbound(Bounded bounded) { + // Unwraps the bounded value, returning a value that can be implicitly cast to any integer type. + // If this implicit cast could truncate, a compile-time error will be raised. + return SafeUnwrapper(bounded); +} + +template +class SafeConstUnwrapper { +public: + template ()>> + inline constexpr operator T() const { + static_assert(value <= T(maxValue), "this operation will truncate"); + return value; + } + + inline constexpr operator bool() const { + static_assert(value <= 1, "this operation will truncate"); + return value; + } +}; + +template +inline constexpr SafeConstUnwrapper unbound(BoundedConst) { + return SafeConstUnwrapper(); +} + +template +inline constexpr T unboundAs(U value) { + return unbound(value); +} + +template +inline constexpr T unboundMax(Bounded value) { + // Explicitly ungaurd expecting a value that is at most `maxN`. + static_assert(maxN <= requestedMax, "possible overflow detected"); + return value.unwrap(); +} + +template +inline constexpr uint unboundMax(BoundedConst) { + // Explicitly ungaurd expecting a value that is at most `maxN`. + static_assert(value <= requestedMax, "overflow detected"); + return value; +} + +template +inline constexpr auto unboundMaxBits(T value) -> + decltype(unboundMax()>(value)) { + // Explicitly ungaurd expecting a value that fits into `bits` bits. + return unboundMax()>(value); +} + +#define OP(op) \ +template \ +inline constexpr auto operator op(T a, SafeUnwrapper b) -> decltype(a op (T)b) { \ + return a op (AtLeastUInt)b; \ +} \ +template \ +inline constexpr auto operator op(SafeUnwrapper b, T a) -> decltype((T)b op a) { \ + return (AtLeastUInt)b op a; \ +} \ +template \ +inline constexpr auto operator op(T a, SafeConstUnwrapper b) -> decltype(a op (T)b) { \ + return a op (AtLeastUInt)b; \ +} \ +template \ +inline constexpr auto operator op(SafeConstUnwrapper b, T a) -> decltype((T)b op a) { \ + return (AtLeastUInt)b op a; \ +} + +OP(+) +OP(-) +OP(*) +OP(/) +OP(%) +OP(<<) +OP(>>) +OP(&) +OP(|) +OP(==) +OP(!=) +OP(<=) +OP(>=) +OP(<) +OP(>) + +#undef OP + +// ------------------------------------------------------------------- + +template +class Range> { +public: + inline constexpr Range(Bounded begin, Bounded end) + : inner(unbound(begin), unbound(end)) {} + inline explicit constexpr Range(Bounded end) + : inner(unbound(end)) {} + + class Iterator { + public: + Iterator() = default; + inline explicit Iterator(typename Range::Iterator inner): inner(inner) {} + + inline Bounded operator* () const { return Bounded(*inner, unsafe); } + inline Iterator& operator++() { ++inner; return *this; } + + inline bool operator==(const Iterator& other) const { return inner == other.inner; } + inline bool operator!=(const Iterator& other) const { return inner != other.inner; } + + private: + typename Range::Iterator inner; + }; + + inline Iterator begin() const { return Iterator(inner.begin()); } + inline Iterator end() const { return Iterator(inner.end()); } + +private: + Range inner; +}; + +template +class Range> { +public: + inline constexpr Range(Quantity begin, Quantity end) + : inner(begin / unit>(), end / unit>()) {} + inline explicit constexpr Range(Quantity end) + : inner(end / unit>()) {} + + class Iterator { + public: + Iterator() = default; + inline explicit Iterator(typename Range::Iterator inner): inner(inner) {} + + inline Quantity operator* () const { return *inner * unit>(); } + inline Iterator& operator++() { ++inner; return *this; } + + inline bool operator==(const Iterator& other) const { return inner == other.inner; } + inline bool operator!=(const Iterator& other) const { return inner != other.inner; } + + private: + typename Range::Iterator inner; + }; + + inline Iterator begin() const { return Iterator(inner.begin()); } + inline Iterator end() const { return Iterator(inner.end()); } + +private: + Range inner; +}; + +template +inline constexpr Range> zeroTo(BoundedConst end) { + return Range>(end); +} + +template +inline constexpr Range, Unit>> + zeroTo(Quantity, Unit> end) { + return Range, Unit>>(end); +} + +} // namespace kj + +#endif // KJ_UNITS_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/vector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/vector.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,144 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_VECTOR_H_ +#define KJ_VECTOR_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#include "array.h" + +namespace kj { + +template +class Vector { + // Similar to std::vector, but based on KJ framework. + // + // This implementation always uses move constructors when growing the backing array. If the + // move constructor throws, the Vector is left in an inconsistent state. This is acceptable + // under KJ exception theory which assumes that exceptions leave things in inconsistent states. + + // TODO(someday): Allow specifying a custom allocator. + +public: + inline Vector() = default; + inline explicit Vector(size_t capacity): builder(heapArrayBuilder(capacity)) {} + + inline operator ArrayPtr() { return builder; } + inline operator ArrayPtr() const { return builder; } + inline ArrayPtr asPtr() { return builder.asPtr(); } + inline ArrayPtr asPtr() const { return builder.asPtr(); } + + inline size_t size() const { return builder.size(); } + inline bool empty() const { return size() == 0; } + inline size_t capacity() const { return builder.capacity(); } + inline T& operator[](size_t index) const { return builder[index]; } + + inline const T* begin() const { return builder.begin(); } + inline const T* end() const { return builder.end(); } + inline const T& front() const { return builder.front(); } + inline const T& back() const { return builder.back(); } + inline T* begin() { return builder.begin(); } + inline T* end() { return builder.end(); } + inline T& front() { return builder.front(); } + inline T& back() { return builder.back(); } + + inline Array releaseAsArray() { + // TODO(perf): Avoid a copy/move by allowing Array to point to incomplete space? + if (!builder.isFull()) { + setCapacity(size()); + } + return builder.finish(); + } + + template + inline T& add(Params&&... params) { + if (builder.isFull()) grow(); + return builder.add(kj::fwd(params)...); + } + + template + inline void addAll(Iterator begin, Iterator end) { + size_t needed = builder.size() + (end - begin); + if (needed > builder.capacity()) grow(needed); + builder.addAll(begin, end); + } + + template + inline void addAll(Container&& container) { + addAll(container.begin(), container.end()); + } + + inline void removeLast() { + builder.removeLast(); + } + + inline void resize(size_t size) { + if (size > builder.capacity()) grow(size); + builder.resize(size); + } + + inline void operator=(decltype(nullptr)) { + builder = nullptr; + } + + inline void clear() { + while (builder.size() > 0) { + builder.removeLast(); + } + } + + inline void truncate(size_t size) { + builder.truncate(size); + } + + inline void reserve(size_t size) { + if (size > builder.capacity()) { + setCapacity(size); + } + } + +private: + ArrayBuilder builder; + + void grow(size_t minCapacity = 0) { + setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2)); + } + void setCapacity(size_t newSize) { + if (builder.size() > newSize) { + builder.truncate(newSize); + } + ArrayBuilder newBuilder = heapArrayBuilder(newSize); + newBuilder.addAll(kj::mv(builder)); + builder = kj::mv(newBuilder); + } +}; + +template +inline auto KJ_STRINGIFY(const Vector& v) -> decltype(toCharSequence(v.asPtr())) { + return toCharSequence(v.asPtr()); +} + +} // namespace kj + +#endif // KJ_VECTOR_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/c++/src/kj/windows-sanity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/c++/src/kj/windows-sanity.h Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,41 @@ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef KJ_WINDOWS_SANITY_H_ +#define KJ_WINDOWS_SANITY_H_ + +#if defined(__GNUC__) && !KJ_HEADER_WARNINGS +#pragma GCC system_header +#endif + +#ifndef _INC_WINDOWS +#error "windows.h needs to be included before kj/windows-sanity.h (or perhaps you don't need either?)" +#endif + +namespace win32 { + const auto ERROR_ = ERROR; +#undef ERROR + const auto ERROR = ERROR_; +} + +using win32::ERROR; + +#endif // KJ_WINDOWS_SANITY_H_ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/README.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,35 @@ +# Cap'n Proto Documentation + +This directory contains the "source code" for the Cap'n Proto web site. + +The site is built with [Jekyll](http://jekyllrb.com/), which depends on Ruby. +Start by installing ruby1.9.1-dev. On Debian-based operating systems: + + sudo apt-get install ruby-dev + +Then install Jekyll: + + sudo gem install jekyll pygments.rb + +Now install Pygments and SetupTools to be able to install the CapnProto lexer. +On Debian based operating systems: + + sudo apt-get install python-pygments python-setuptools + +Next, install the custom Pygments syntax highlighter: + + cd _plugins + sudo python capnp_lexer.py install + cd .. + +Now you can launch a local server: + + jekyll serve --watch + +Edit, test, commit. + +If you have permission, after you've pushed your changes back to github, you can make your changes live by running: + + ./push-site.sh + +Otherwise, send a pull request and let someone else actually push the new site. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_config.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_config.yml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,5 @@ +safe: true +permalink: /news/:year-:month-:day-:title.html +baseurl: / +is_next: false +highlighter: pygments diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_config_next.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_config_next.yml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,5 @@ +safe: true +permalink: /news/:year-:month-:day-:title.html +baseurl: /next/ +is_next: true +highlighter: pygments diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_includes/buttons.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_includes/buttons.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ + +
diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_includes/footer.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_includes/footer.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,26 @@ +
+ + + + + + + + + + + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_includes/header.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_includes/header.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,59 @@ + + + + + + + + + + + + Cap'n Proto: {{ page.title }} + + + + + + + +
+
+ +
+ +
+
+ Discuss on Groups + View on GitHub +
+ + {% if site.is_next %} +
+

PREVIEW

+

You are looking at the site as it will appear after the next release. This is a draft + version that may be incomplete, buggy, or not yet applicable. To look at the current + site, click here. +

+ {% endif %} + + +
+ + +
diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_layouts/page.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_layouts/page.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,4 @@ +{% include header.html %} +{{ content }} + +{% include footer.html %} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_layouts/post.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_layouts/post.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,19 @@ +{% include header.html %} + + + +

News

+ +

{{ page.title }}

+

+ {{ page.author }} + on {{ page.date | date_to_string }} +

+{{ content }} + +{% include footer.html %} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_plugins/capnp_lexer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_plugins/capnp_lexer.py Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,64 @@ +#! /usr/bin/env python + +from pygments.lexer import RegexLexer +from pygments.token import * + +class CapnpLexer(RegexLexer): + name = "Cap'n Proto lexer" + aliases = ['capnp'] + filenames = ['*.capnp'] + + tokens = { + 'root': [ + (r'#.*?$', Comment.Single), + (r'@[0-9a-zA-Z]*', Name.Decorator), + (r'=', Literal, 'expression'), + (r':', Name.Class, 'type'), + (r'\$', Name.Attribute, 'annotation'), + (r'(struct|enum|interface|union|import|using|const|annotation|extends|in|of|on|as|with|from|fixed)\b', + Token.Keyword), + (r'[a-zA-Z0-9_.]+', Token.Name), + (r'[^#@=:$a-zA-Z0-9_]+', Text), + ], + 'type': [ + (r'[^][=;,(){}$]+', Name.Class), + (r'[[(]', Name.Class, 'parentype'), + (r'', Name.Class, '#pop') + ], + 'parentype': [ + (r'[^][;()]+', Name.Class), + (r'[[(]', Name.Class, '#push'), + (r'[])]', Name.Class, '#pop'), + (r'', Name.Class, '#pop') + ], + 'expression': [ + (r'[^][;,(){}$]+', Literal), + (r'[[(]', Literal, 'parenexp'), + (r'', Literal, '#pop') + ], + 'parenexp': [ + (r'[^][;()]+', Literal), + (r'[[(]', Literal, '#push'), + (r'[])]', Literal, '#pop'), + (r'', Literal, '#pop') + ], + 'annotation': [ + (r'[^][;,(){}=:]+', Name.Attribute), + (r'[[(]', Name.Attribute, 'annexp'), + (r'', Name.Attribute, '#pop') + ], + 'annexp': [ + (r'[^][;()]+', Name.Attribute), + (r'[[(]', Name.Attribute, '#push'), + (r'[])]', Name.Attribute, '#pop'), + (r'', Name.Attribute, '#pop') + ], + } + +if __name__ == "__main__": + from setuptools import setup, find_packages + setup(name = "CapnpPygmentsLexer", + version = "0.1", + packages = find_packages(), + py_modules = [ 'capnp_lexer' ], + entry_points = {'pygments.lexers': 'capnp = capnp_lexer:CapnpLexer'}) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-04-01-announcing-capn-proto.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-04-01-announcing-capn-proto.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,15 @@ +--- +layout: post +title: Announcing Cap'n Proto +author: kentonv +--- + + + +So, uh... I have a confession to make. + +I may have rewritten Protocol Buffers. + +Again. + +[And it's infinity times faster.](https://capnproto.org) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-06-27-capn-proto-beta-release.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-06-27-capn-proto-beta-release.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,42 @@ +--- +layout: post +title: Cap'n Proto Beta Release +author: kentonv +--- + +It's been nearly three months since Cap'n Proto was originally announced, and by now you're +probably wondering what I've been up to. The answer is basically +[non-stop coding](https://github.com/kentonv/capnproto/commits/master). Features were implemented, +code was refactored, tests were written, and now Cap'n Proto is beginning to resemble something +like a real product. But as is so often the case with me, I've been so engrossed in coding that I +forgot to post updates! + +Well, that changes today, with the first official release of Cap'n Proto, v0.1. While not yet +"done", this release should be usable for Real Work. Feature-wise, for C++, the library is roughly +on par with [Google's Protocol Buffers](http://protobuf.googlecode.com) (which, as you know, I used +to maintain). Features include: + +* Types: numbers, bytes, text, enums, lists, structs, and unions. +* Code generation from schema definition files. +* Reading from and writing to file descriptors (or other streams). +* Text-format output (e.g. for debugging). +* Reflection, for writing generic code that dynamically walks over message contents. +* Dynamic schema loading (to manipulate types not known at compile time). +* Code generator plugins for extending the compiler to support new languages. +* Tested on Linux and Mac OSX with GCC and Clang. + +Notably missing from this list is RPC (something Protocol Buffers never provided either). The RPC +system is still in the design phase, but will be implemented over the coming weeks. + +Also missing is support for languages other than C++. However, I'm happy to report that a number +of awesome contributors have stepped up and are working on +[implementations in C, Go, Python]({{ site.baseurl }}otherlang.html), and a few others not yet +announced. None of these are "ready" just yet, but watch this space. (Would you like to work on +an implementation in your favorite language? +[Let us know!](https://groups.google.com/group/capnproto)) + +Going forward, Cap'n Proto releases will occur more frequently, perhaps every 2-4 weeks. +Consider [signing up for release announcements](https://groups.google.com/group/capnproto-announce). + +In any case, go [download the release]({{ site.baseurl }}install.html) and +[tell us your thoughts](https://groups.google.com/group/capnproto). diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-08-12-capnproto-0.2-no-more-haskell.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-08-12-capnproto-0.2-no-more-haskell.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,144 @@ +--- +layout: post +title: "Cap'n Proto v0.2: Compiler rewritten Haskell -> C++" +author: kentonv +--- + +Today I am releasing version 0.2 of Cap'n Proto. The most notable change: the compiler / code +generator, which was previously written in Haskell, has been rewritten in C++11. There are a few +other changes as well, but before I talk about those, let me try to calm the angry mob that is +not doubt reaching for their pitchforks as we speak. There are a few reasons for this change, +some practical, some ideological. I'll start with the practical. + +**The practical: Supporting dynamic languages** + +Say you are trying to implement Cap'n Proto in an interpreted language like Python. One of the big +draws of such a language is that you can edit your code and then run it without an intervening +compile step, allowing you to iterate faster. But if the Python Cap'n Proto implementation worked +like the C++ one (or like Protobufs), you lose some of that: whenever you change your Cap'n Proto +schema files, you must run a command to regenerate the Python code from them. That sucks. + +What you really want to do is parse the schemas at start-up -- the same time that the Python code +itself is parsed. But writing a proper schema parser is harder than it looks; you really should +reuse the existing implementation. If it is written in Haskell, that's going to be problematic. +You either need to invoke the schema parser as a sub-process or you need to call Haskell code from +Python via an FFI. Either approach is going to be a huge hack with lots of problems, not the least +of which is having a runtime dependency on an entire platform that your end users may not otherwise +want. + +But with the schema parser written in C++, things become much simpler. Python code calls into +C/C++ all the time. Everyone already has the necessary libraries installed. There's no need to +generate code, even; the parsed schema can be fed into the Cap'n Proto C++ runtime's dynamic API, +and Python bindings can trivially be implemented on top of that in just a few hundred lines of +code. Everyone wins. + +**The ideological: I'm an object-oriented programmer** + +I really wanted to like Haskell. I used to be a strong proponent of functional programming, and +I actually once wrote a complete web server and CMS in a purely-functional toy language of my own +creation. I love strong static typing, and I find a lot of the constructs in Haskell really +powerful and beautiful. Even monads. _Especially_ monads. + +But when it comes down to it, I am an object-oriented programmer, and Haskell is not an +object-oriented language. Yes, you can do object-oriented style if you want to, just like you +can do objects in C. But it's just too painful. I want to write `object.methodName`, not +`ModuleName.objectTypeMethodName object`. I want to be able to write lots of small classes that +encapsulate complex functionality in simple interfaces -- _without_ having to place each one in +a whole separate module and ending up with thousands of source files. I want to be able to build +a list of objects of varying types that implement the same interface without having to re-invent +virtual tables every time I do it (type classes don't quite solve the problem). + +And as it turns out, even aside from the lack of object-orientation, I don't actually like +functional programming as much as I thought. Yes, writing my parser was super-easy (my first +commit message was +"[Day 1: Learn Haskell, write a parser](https://github.com/kentonv/capnproto/commit/6bb49ca775501a9b2c7306992fd0de53c5ee4e95)"). +But everything beyond that seemed to require increasing amounts of brain bending. For instance, to +actually encode a Cap'n Proto message, I couldn't just allocate a buffer of zeros and then go +through each field and set its value. Instead, I had to compute all the field values first, sort +them by position, then concatenate the results. + +Of course, I'm sure it's the case that if I spent years writing Haskell code, I'd eventually become +as proficient with it as I am with C++. Perhaps I could un-learn object-oriented style and learn +something else that works just as well or better. Basically, though, I decided that this was +going to take a lot longer than it at first appeared, and that this wasn't a good use of my +limited resources. So, I'm cutting my losses. + +I still think Haskell is a very interesting language, and if works for you, by all means, use it. +I would love to see someone write at actual Cap'n Proto runtime implementation in Haskell. But +the compiler is now C++. + +**Parser Combinators in C++** + +A side effect (so to speak) of the compiler rewrite is that Cap'n Proto's companion utility +library, KJ, now includes a parser combinator framework based on C++11 templates and lambdas. +Here's a sample: + +{% highlight c++ %} +// Construct a parser that parses a number. +auto number = transform( + sequence( + oneOrMore(charRange('0', '9')), + optional(sequence( + exactChar<'.'>(), + many(charRange('0', '9'))))), + [](Array whole, Maybe> maybeFraction) + -> Number* { + KJ_IF_MAYBE(fraction, maybeFraction) { + return new RealNumber(whole, *fraction); + } else { + return new WholeNumber(whole); + } + }); +{% endhighlight %} + +An interesting fact about the above code is that constructing the parser itself does not allocate +anything on the heap. The variable `number` in this case ends up being one 96-byte flat object, +most of which is composed of tables for character matching. The whole thing could even be +declared `constexpr`... if the C++ standard allowed empty-capture lambdas to be `constexpr`, which +unfortunately it doesn't (yet). + +Unfortunately, KJ is largely undocumented at the moment, since people who just want to use +Cap'n Proto generally don't need to know about it. + +**Other New Features** + +There are a couple other notable changes in this release, aside from the compiler: + +* Cygwin has been added as a supported platform, meaning you can now use Cap'n Proto on Windows. + I am considering supporting MinGW as well. Unfortunately, MSVC is unlikely to be supported any + time soon as its C++11 support is + [woefully lacking](http://blogs.msdn.com/b/somasegar/archive/2013/06/28/cpp-conformance-roadmap.aspx). + +* The new compiler binary -- now called `capnp` rather than `capnpc` -- is more of a multi-tool. + It includes the ability to decode binary messages to text as a debugging aid. Type + `capnp help decode` for more information. + +* The new [Orphan]({{ site.baseurl }}/cxx.html#orphans) class lets you detach objects from a + message tree and re-attach them elsewhere. + +* Various contributors have declared their intentions to implement + [Ruby](https://github.com/cstrahan/capnp-ruby), + [Rust](https://github.com/dwrensha/capnproto-rust), C#, Java, Erlang, and Delphi bindings. These + are still works in progress, but exciting nonetheless! + +**Backwards-compatibility Note** + +Cap'n Proto v0.2 contains an obscure wire format incompatibility with v0.1. If you are using +unions containing multiple primitive-type fields of varying sizes, it's possible that the new +compiler will position those fields differently. A work-around to get back to the old layout +exists; if you believe you could be affected, please [send me](mailto:temporal@gmail.com) your +schema and I'll tell you what to do. [Gory details.](https://groups.google.com/d/msg/capnproto/NIYbD0haP38/pH5LildInwIJ) + +**Road Map** + +v0.3 will come in a couple weeks and will include several new features and clean-ups that can now +be implemented more easily given the new compiler. This will also hopefully be the first release +that officially supports a language other than C++. + +The following release, v0.4, will hopefully be the first release implementing RPC. + +_PS. If you are wondering, compared to the Haskell version, the new compiler is about 50% more +lines of code and about 4x faster. The speed increase should be taken with a grain of salt, +though, as my Haskell code did all kinds of horribly slow things. The code size is, I think, not +bad, considering that Haskell specializes in concision -- but, again, I'm sure a Haskell expert +could have written shorter code._ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-08-19-capnproto-0.2.1.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-08-19-capnproto-0.2.1.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,10 @@ +--- +layout: post +title: "Cap'n Proto v0.2.1: Minor bug fixes" +author: kentonv +--- + +Cap'n Proto was just bumped to v0.2.1. This release contains a couple bug fixes, including +a work-around for [a GCC bug](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58192). If you were +observing any odd memory corruption or crashes in 0.2.0 -- especially if you are compiling with +GCC with optimization enabled but without `-DNDEBUG` -- you should upgrade. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-09-04-capnproto-0.3-python-tools-features.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-09-04-capnproto-0.3-python-tools-features.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,96 @@ +--- +layout: post +title: "Cap'n Proto v0.3: Python, tools, new features" +author: kentonv +--- + +The first release of Cap'n Proto came three months after the project was announced. The second +release came six weeks after that. And the third release is three weeks later. If the pattern +holds, there will be an infinite number of releases before the end of this month. + +Version 0.3 is not a paradigm-shifting release, but rather a slew of new features largely made +possible by building on the rewritten compiler from the last release. Let's go through the +list... + +### Python Support! + +Thanks to the tireless efforts of contributor [Jason Paryani](https://github.com/jparyani), I can +now comfortably claim that Cap'n Proto supports multiple languages. [His Python +implementation](http://jparyani.github.io/pycapnp/) wraps the C++ library and exposes +most of its features in a nice, easy-to-use way. + +And I have to say, it's _way_ better than the old Python Protobuf implementation that I helped put +together at Google. Here's why: + +* Jason's implementation parses Cap'n Proto schema files at runtime. There is no need to run a + compiler to generate code every time you update your schema, as with protobufs. So, you get + to use Python the way Python was intended to be used. In fact, he's hooked into the Python + import mechanism, so you can basically import a `.capnp` schema file as if it were a `.py` + module. It's even convenient to load schema files and play with Cap'n Proto messages from the + interactive interpreter prompt. +* It's _fast_. Whereas the Python Protobuf implementation -- which we made the mistake of + implementing in pure-Python -- is _slow_. And while technically there is an experimental + C-extension-based Python Protobuf implementation (which isn't enabled by default due to various + obscure problems), Jason's Cap'n Proto implementation is faster than that, too. + +Go [check it out](http://jparyani.github.io/pycapnp/)! + +By the way, there is also a budding [Erlang implementation](http://ecapnp.astekk.se/) +(by Andreas Stenius), and work +continues on [Rust](https://github.com/dwrensha/capnproto-rust) (David Renshaw) and +[Ruby](https://github.com/cstrahan/capnp-ruby) (Charles Strahan) implementations. + +### Tools: Cap'n Proto on the Command Line + +The `capnp` command-line tool previously served mostly to generate code, via the `capnp compile` +command. It now additionally supports converting encoded Cap'n Proto messages to a human-readable +text format via `capnp decode`, and converting that format back to binary with `capnp encode`. +These tools are, of course, critical for debugging. + +You can also use the new `capnp eval` command to do something interesting: given a schema file and +the name of a constant defined therein, it will print out the value of that constant, or optionally +encode it to binary. This is more interesting than it sounds because the schema language supports +variable substitution in the definitions of these constants. This means you can build a large +structure by importing smaller bits from many different files. This may make it convenient to +use Cap'n Proto schemas as a config format: define your service configuration as a constant in +a schema file, importing bits specific to each client from other files that those clients submit +to you. Use `capnp eval` to "compile" the whole thing to binary for deployment. (This has always +been a common use case for Protobuf text format, which doesn't even support variable substitution +or imports.) + +Anyway, check out the [full documentation]({{ site.baseurl }}capnp-tool.html) for +more. + +### New Features + +The core product has been updated as well: + +* Support for unnamed [unions]({{ site.baseurl }}language.html#unions) reduces the + need for noise-words, improving code readability. Additionally, the syntax for unions has been + simplified by removing the unnecessary ordinal number. +* [Groups]({{ site.baseurl }}language.html#groups) pair nicely with unions. +* [Constants]({{ site.baseurl }}language.html#constants) are now + [implemented in C++]({{ site.baseurl }}cxx.html#constants). Additionally, they + can now be defined in terms of other constants (variable substitution), as described earlier. +* The schema API and `schema.capnp` have been radically refactored, in particular to take advantage + of the new union and group features, making the code more readable. +* More and better tests, bug fixes, etc. + +### Users! + +Some news originating outside of the project itself: + +* [Debian Unstable (sid)](http://www.debian.org/releases/sid/) now features + [a Cap'n Proto package](http://packages.debian.org/sid/capnproto), thanks to + [Tom Lee](https://github.com/thomaslee). Of course, since package updates take some time, this + package is still v0.2.1 as of this writing, but it will be updated to v0.3 soon enough. +* Popular OSX-based text editor [TextMate](http://macromates.com/) now + [uses Cap'n Proto internally](https://github.com/textmate/textmate/commit/5c02b4ff5cc0c7c319d3d4f127c8ee19b81f80b7), + and the developer's feedback lead directly to several usability improvements included in this + release. +* Many people using Cap'n Proto _haven't bothered to tell us about it_! Please, if you use it, + [let us know](https://groups.google.com/group/capnproto) about your experience, both what you like + and especially what you don't like. This is the critical time where the system is usable but + can still be changed if it's not right, so your feedback is critical to our long-term success. +* I have revenue! A whopping [$1.25 per week](https://www.gittip.com/kentonv/)! >_> It's + totally worth it; I love this project. (But thanks for the tips!) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-12-12-capnproto-0.4-time-travel.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-12-12-capnproto-0.4-time-travel.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,89 @@ +--- +layout: post +title: "Cap'n Proto v0.4: Time Traveling RPC" +author: kentonv +--- + +Well, [Hofstadter](http://en.wikipedia.org/wiki/Hofstadter's_law) kicked in and this release took +way too long. But, after three long months, I'm happy to announce: + +### Time-Traveling RPC _(Promise Pipelining)_ + + + +v0.4 finally introduces the long-promised [RPC system]({{ site.baseurl }}rpc.html). Traditionally, +RPC is plagued by the fact that networks have latency, and pretending that latency doesn't exist by +hiding it behind what looks like a normal function call only makes the problem worse. +Cap'n Proto has a simple solution to this problem: send call results _back in time_, so they +arrive at the client at the point in time when the call was originally made! + +Curious how Cap'n Proto bypasses the laws of physics? +[Check out the docs!]({{ site.baseurl }}rpc.html) + +_UPDATE: There has been some confusion about what I'm claiming. I am NOT saying that using +promises alone (i.e. being asynchronous) constitutes "time travel". Cap'n Proto implements a +technique called Promise Pipelining which allows a new request to be formed based on the content +of a previous result (in part or in whole) before that previous result is returned. Notice in the +diagram that the result of foo() is being passed to bar(). Please +[see the docs]({{ site.baseurl }}rpc.html) or +[check out the calculator example](https://github.com/kentonv/capnproto/blob/master/c++/samples) +for more._ + +### Promises in C++ + +_UPDATE: More confusion. This section is **not** about pipelining ("time travel"). This section +is just talking about implementing a promise API in C++. Pipelining is another feature on top of +that. Please [see the RPC page]({{ site.baseurl }}rpc.html) if you want to know more about +pipelining._ + +If you do a lot of serious Javascript programming, you've probably heard of +[Promises/A+](http://promisesaplus.com/) and similar proposals. Cap'n Proto RPC introduces a +similar construct in C++. In fact, the API is nearly identical, and its semantics are nearly +identical. Compare with +[Domenic Denicola's Javascript example](http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/): + +{% highlight c++ %} +// C++ version of Domenic's Javascript promises example. +getTweetsFor("domenic") // returns a promise + .then([](vector tweets) { + auto shortUrls = parseTweetsForUrls(tweets); + auto mostRecentShortUrl = shortUrls[0]; + // expandUrlUsingTwitterApi returns a promise + return expandUrlUsingTwitterApi(mostRecentShortUrl); + }) + .then(httpGet) // promise-returning function + .then( + [](string responseBody) { + cout << "Most recent link text:" << responseBody << endl; + }, + [](kj::Exception&& error) { + cerr << "Error with the twitterverse:" << error << endl; + } + ); +{% endhighlight %} + +This is C++, but it is no more lines -- nor otherwise more complex -- than the equivalent +Javascript. We're doing several I/O operations, we're doing them asynchronously, and we don't +have a huge unreadable mess of callback functions. Promises are based on event loop concurrency, +which means you can perform concurrent operations with shared state without worrying about mutex +locking -- i.e., the Javascript model. (Of course, if you really want threads, you can run +multiple event loops in multiple threads and make inter-thread RPC calls between them.) + +[More on C++ promises.]({{ site.baseurl }}cxxrpc.html#kj_concurrency_framework) + +### Python too + +[Jason](https://github.com/jparyani) has been diligently keeping his +[Python bindings](http://jparyani.github.io/pycapnp/) up to date, so you can already use RPC there +as well. The Python interactive interpreter makes a great debugging tool for calling C++ servers. + +### Up Next + +Cap'n Proto is far from done, but working on it in a bubble will not produce ideal results. +Starting after the holidays, I will be refocusing some of my time into an adjacent project which +will be a heavy user of Cap'n Proto. I hope this experience will help me discover first hand +the pain points in the current interface and keep development going in the right direction. + +This does, however, mean that core Cap'n Proto development will slow somewhat (unless contributors +pick up the slack! ;) ). I am extremely excited about this next project, though, and I think you +will be too. Stay tuned! diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2013-12-13-promise-pipelining-capnproto-vs-ice.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2013-12-13-promise-pipelining-capnproto-vs-ice.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,76 @@ +--- +layout: post +title: "Promise Pipelining and Dependent Calls: Cap'n Proto vs. Thrift vs. Ice" +author: kentonv +--- + +_UPDATED: Added Thrift to the comparison._ + +So, I totally botched the 0.4 release announcement yesterday. I was excited about promise +pipelining, but I wasn't sure how to describe it in headline form. I decided to be a bit +silly and call it "time travel", tongue-in-cheek. My hope was that people would then be +curious, read the docs, find out that this is actually a really cool feature, and start doing +stuff with it. + +Unfortunately, [my post](2013-12-12-capnproto-0.4-time-travel.html) only contained a link to +the full explanation and then confusingly followed the "time travel" section with a separate section +describing the fact that I had implemented a promise API in C++. Half the readers clicked through +to the documentation and understood. The other half thought I was claiming that promises alone +constituted "time travel", and thought I was ridiculously over-hyping an already-well-known +technique. My HN post was subsequently flagged into oblivion. + +Let me be clear: + +**Promises alone are _not_ what I meant by "time travel"!** + + + +So what did I mean? Perhaps [this benchmark](https://github.com/kentonv/capnp-vs-ice) will +make things clearer. Here, I've defined a server that exports a simple four-function calculator +interface, with `add()`, `sub()`, `mult()`, and `div()` calls, each taking two integers and\ +returning a result. + +You are probably already thinking: That's a ridiculously bad way to define an RPC interface! +You want to have _one_ method `eval()` that takes an expression tree (or graph, even), otherwise +you will have ridiculous latency. But this is exactly the point. **With promise pipelining, simple, +composable methods work fine.** + +To prove the point, I've implemented servers in Cap'n Proto, [Apache Thrift](http://thrift.apache.org/), +and [ZeroC Ice](http://www.zeroc.com/). I then implemented clients against each one, where the +client attempts to evaluate the expression: + + ((5 * 2) + ((7 - 3) * 10)) / (6 - 4) + +All three frameworks support asynchronous calls with a promise/future-like interface, and all of my +clients use these interfaces to parallelize calls. However, notice that even with parallelization, +it takes four steps to compute the result: + + # Even with parallelization, this takes four steps! + ((5 * 2) + ((7 - 3) * 10)) / (6 - 4) + (10 + ( 4 * 10)) / 2 # 1 + (10 + 40) / 2 # 2 + 50 / 2 # 3 + 25 # 4 + +As such, the Thrift and Ice clients take four network round trips. Cap'n Proto, however, takes +only one. + +Cap'n Proto, you see, sends all six calls from the client to the server at one time. For the +latter calls, it simply tells the server to substitute the former calls' results into the new +requests, once those dependency calls finish. Typical RPC systems can only send three calls to +start, then must wait for some to finish before it can continue with the remaining calls. Over +a high-latency connection, this means they take 4x longer than Cap'n Proto to do their work in +this test. + +So, does this matter outside of a contrived example case? Yes, it does, because it allows you to +write cleaner interfaces with simple, composable methods, rather than monster do-everything-at-once +methods. The four-method calculator interface is much simpler than one involving sending an +expression graph to the server in one batch. Moreover, pipelining allows you to define +object-oriented interfaces where you might otherwise be tempted to settle for singletons. See +[my extended argument]({{ site.baseurl }}rpc.html#introduction) (this is what I was trying to get +people to click on yesterday :) ). + +Hopefully now it is clearer what I was trying to illustrate with this diagram, and what I meant +by "time travel"! + + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2014-03-11-capnproto-0.4.1-bugfixes.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2014-03-11-capnproto-0.4.1-bugfixes.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,30 @@ +--- +layout: post +title: "Cap'n Proto 0.4.1: Bugfix Release" +author: kentonv +--- + +Today I'm releasing [version 0.4.1 of Cap'n Proto](https://capnproto.org/capnproto-c++-0.4.1.tar.gz). +As hinted by the version number, this is a bugfix and tweak release, with no big new features. + +You may be wondering: If there are no big new features, what has been happening over the +last three months? Most of my time lately has been spent laying the groundwork for an +interesting project built on Cap'n Proto which should launch by the end of this month. +Stay tuned! And don't worry -- this new project is going to need many of the upcoming +features on [the roadmap]({{ site.baseurl }}roadmap.html), so work on version 0.5 will be +proceeding soon. + +In the meantime, though, there have been some major updates from the community: + + * The folks at [CloudFlare](https://www.cloudflare.com/) have produced a + [Lua port](https://github.com/cloudflare/lua-capnproto) which they are + [using successfully in production](http://blog.cloudflare.com/introducing-lua-capnproto-better-serialization-in-lua) + along with the existing [Go port](https://github.com/jmckaskill/go-capnproto). + * [The Rust port of Cap'n Proto](https://github.com/dwrensha/capnproto-rust) now has + preliminary RPC support, making it the third language to support Cap'n Proto RPC (after + C++ and Python), and the second language to implement it from the ground up (Python just + wraps the C++ implementation). Check out author [David Renshaw](https://github.com/dwrensha)'s + [talk at Mozilla](https://air.mozilla.org/rust-meetup-february-2014/). + * A [Javascript port](https://github.com/jscheid/capnproto-js) has appeared, but it needs help + to keep going! + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2014-06-17-capnproto-flatbuffers-sbe.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2014-06-17-capnproto-flatbuffers-sbe.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,206 @@ +--- +layout: post +title: Cap'n Proto, FlatBuffers, and SBE +author: kentonv +--- + +**Update Jun 18, 2014:** I have made [some corrections](https://github.com/kentonv/capnproto/commit/e4e6c9076ae16804c07968cd3bdf6107155df7ee) since the original version of this post. + +**Update Dec 15, 2014:** Updated to reflect that Cap'n Proto 0.5 now supports Visual Studio and that +Java is now well-supported. + +Yesterday, some engineers at Google released [FlatBuffers](http://google-opensource.blogspot.com/2014/06/flatbuffers-memory-efficient.html), a new serialization protocol and library with similar design principles to Cap'n Proto. Also, a few months back, Real Logic released [Simple Binary Encoding](http://mechanical-sympathy.blogspot.com/2014/05/simple-binary-encoding.html), another protocol and library of this nature. + +It seems we now have some friendly rivalry. :) + +It's great to see that the concept of `mmap()`-able, zero-copy serialization formats are catching on, and it's wonderful that all are open source under liberal licenses. But as a user, you might be left wondering how all these systems compare. You have a vague idea that all these encodings are "fast", particularly compared to Protobufs or other more-traditional formats. But there is more to a serialization protocol than speed, and you may be wondering what else you should be considering. + +The goal of this blog post is to highlight some of the main _qualitative_ differences between these libraries as I see them. Obviously, I am biased, and you should consider that as you read. Hopefully, though, this provides a good starting point for your own investigation of the alternatives. + +### Feature Matrix + +The following are a set of considerations I think are important. See something I missed? Please [let me know](mailto:kenton@sandstorm.io) and I'll add it. I'd like in particular to invite the SBE and FlatBuffers authors to suggest advantages of their libraries that I may have missed. + +I will go into more detail on each item below. + +Note: For features which are properties of the implementation rather than the protocol or project, unless otherwise stated, I am judging the C++ implementations. + + + + + + + + + + + + + + + + + + + + + + +
FeatureProtobufCap'n ProtoSBEFlatBuffers
Schema evolutionyesyescaveatsyes
Zero-copynoyesyesyes
Random-access readsnoyesnoyes
Safe against malicious inputyesyesyesopt-in upfront
Reflection / generic algorithmsyesyesyesyes
Initialization orderanyanypreorderbottom-up
Unknown field retentionremoved
in proto3
yesnono
Object-capability RPC systemnoyesnono
Schema languagecustomcustomXMLcustom
Usable as mutable stateyesnonono
Padding takes space on wire?nooptionalyesyes
Unset fields take space on wire?noyesyesno
Pointers take space on wire?noyesnoyes
C++yesyes (C++11)*yesyes
Javayesyes*yesyes
C#yesyes*yesyes*
Goyesyesnoyes*
Other languageslots!6+ others*nono
Authors' preferred use casedistributed
computing
platforms /
sandboxing
financial
trading
games
+ +\* Updated Dec 15, 2014 (Cap'n Proto 0.5.0). + +**Schema Evolution** + +All four protocols allow you to add new fields to a schema over time, without breaking backwards-compatibility. New fields will be ignored by old binaries, and new binaries will fill in a default value when reading old data. + +SBE, however, as far as I can tell from reading the code, does not allow you to add new variable-width fields inside of a sub-object (group), as it is the application's responsibility to explicitly iterate over every variable-width field when reading. When an old app not knowing about the new nested field fails to cover it, its buffer pointer will get out-of-sync. Variable-width fields can be added to the topmost object since they'll end up at the end of the message, so there's no need for old code to traverse past them. + +**Zero-copy** + +The central thesis of all three competitors is that data should be structured the same way in-memory and on the wire, thus avoiding costly encode/decode steps. + +Protobufs represents the old way of thinking. + +**Random-access reads** + +Can you traverse the message content in an arbitrary order? Relatedly, can you `mmap()` in a large (say, 2GB) file -- where the entire file is one enormous serialized message -- then traverse to and read one particular field without causing the entire file to be paged in from disk? + +Protobufs does not allow this because the entire file must be parsed upfront before any of the content can be used. Even with a streaming Protobuf parser (which most libraries don't provide), you would at least need to parse all data appearing before the bit you want. The Protobuf documentation recommends splitting large files up into many small pieces and implementing some other framing format that allows seeking between them, but this is left entirely up to the app. + +SBE does not allow random access because the message tree is written in preorder with no information that would allow one to skip over an entire sub-tree. While the primitive fields within a single object can be accessed in random order, sub-objects must be traversed strictly in preorder. SBE apparently chose to design around this restriction because sequential memory access is faster than random access, therefore this forces application code to be ordered to be as fast as possible. Similar to Protobufs, SBE recommends using some other framing format for large files. + +Cap'n Proto permits random access via the use of pointers, exactly as in-memory data structures in C normally do. These pointers are not quite native pointers -- they are relative rather than absolute, to allow the message to be loaded at an arbitrary memory location. + +FlatBuffers permits random access by having each record store a table of offsets to all of the field positions, and by using pointers between objects like Cap'n Proto does. + +**Safe against malicious input** + +Protobufs is carefully designed to be resiliant in the face of all kinds of malicious input, and has undergone a security review by Google's world-class security team. Not only is the Protobuf implementation secure, but the API is explicitly designed to discourage security mistakes in application code. It is considered a security flaw in Protobufs if the interface makes client apps likely to write insecure code. + +Cap'n Proto inherits Protocol Buffers' security stance, and is believed to be similarly secure. However, it has not yet undergone security review. + +SBE's C++ library does bounds checking as of the resolution of [this bug](https://github.com/real-logic/simple-binary-encoding/issues/130). + +*Update July 12, 2014:* FlatBuffers [now supports](https://github.com/google/flatbuffers/commit/a0b6ffc25b9a3c726a21e52d6453779265186dbd) performing an optional upfront verification pass over a message to ensure that all pointers are in-bounds. You must explicitly call the verifier, otherwise no bounds checking is performed. The verifier performs a pass over the entire message; it should be very fast, but it is O(n), so you lose the "random access" advantage if you are mmap()ing in a very large file. FlatBuffers is primarily designed for use as a format for static, trusted data files, not network messages. + +**Reflection / generic algorithms** + +_Update: I originally failed to discover that SBE and FlatBuffers do in fact have reflection APIs. Sorry!_ + +Protobuf provides a "reflection" interface which allows dynamically iterating over all the fields of a message, getting their names and other metadata, and reading and modifying their values in a particular instance. Cap'n Proto also supports this, calling it the "Dynamic API". SBE provides the "OTF decoder" API with the usual SBE restriction that you can only iterate over the content in order. FlatBuffers has the `Parser` API in `idl.h`. + +Having a reflection/dynamic API opens up a wide range of use cases. You can write reflection-based code which converts the message to/from another format such as JSON -- useful not just for interoperability, but for debugging, because it is human-readable. Another popular use of reflection is writing bindings for scripting languages. For example, Python's Cap'n Proto implementation is simply a wrapper around the C++ dynamic API. Note that you can do all these things with types that are not even known at compile time, by parsing the schemas at runtime. + +The down side of reflection is that it is generally very slow (compared to generated code) and can lead to code bloat. Cap'n Proto is designed such that the reflection APIs need not be linked into your app if you do not use them, although this requires statically linking the library to get the benefit. + +**Initialization order** + +When building a message, depending on how your code is organized, it may be convenient to have flexibility in the order in which you fill in the data. If that flexibility is missing, you may find you have to do extra bookkeeping to store data off to the side until its time comes to be added to the message. + +Protocol Buffers is natually completely flexible in terms of initialization order because the mesasge is being built on the heap. There is no reason to impose restrictions. (Although, the C++ Protobuf library heavily encourages top-down building.) + +All the zero-copy systems, though, have to use some form of arena allocation to make sure that the message is built in a contiguous block of memory that can be written out all at once. So, things get more complicated. + +SBE specifically requires the message tree to be written in preorder (though, as with reads, the primitive fields within a single object can be initialized in arbitrary order). + +FlatBuffers requires that you completely finish one object before you can start building the next, because the size of an object depends on its content so the amount of space needed isn't known until it is finalized. This also implies that FlatBuffer messages must be built bottom-up, starting from the leaves. + +Cap'n Proto imposes no ordering constraints. The size of an object is known when it is allocated, so more objects can be allocated immediately. Messages are normally built top-down, but bottom-up ordering is supported through the "orphans" API. + +**Unknown field retention?** + +Say you read in a message, then copy one sub-object of that message over to a sub-object of a new message, then write out the new message. Say that the copied object was created using a newer version of the schema than you have, and so contains fields you don't know about. Do those fields get copied over? + +This question is extremely important for any kind of service that acts as a proxy or broker, forwarding messages on to others. It can be inconvenient if you have to update these middlemen every time a particular backend protocol changes, when the middlemen often don't care about the protocol details anyway. + +When Protobufs sees an unknown field tag on the wire, it stores the value into the message's `UnknownFieldSet`, which can be copied and written back out later. (UPDATE: Apparently, version 3 of Protocol Buffers, aka "proto3", removes this feature. I honestly don't know what they're thinking. This feature has been absolutely essential in many of Google's internal systems.) + +Cap'n Proto's wire format was very carefully designed to contain just enough information to make it possible to recursively copy its target from one message to another without knowing the object's schema. This is why Cap'n Proto pointers contain bits to indicate if they point to a struct or a list and how big it is -- seemingly redundant information. + +SBE and FlatBuffers do not store any such type information on the wire, and thus it is not possible to copy an object without its schema. (Note that, however, if you are willing to require that the sender sends its full schema on the wire, you can always use reflection-based code to effectively make all fields known. This takes some work, though.) + +**Object-capability RPC system** + +Cap'n Proto features an object-capability RPC system. While this article is not intended to discuss RPC features, there is an important effect on the serialization format: in an object-capability RPC system, references to remote objects must be a first-class type. That is, a struct field's type can be "reference to remote object implementing RPC interface Foo". + +Protobufs, SBC, and FlatBuffers do not support this type. Note that it is _not_ sufficient to simply store a string URL, or define some custom struct to represent a reference, because a proper capability-based RPC system must be aware of all references embedded in any message it sends. There are many reasons for this requirement, the most obvious of which is that the system must export the reference or change its permissions to make it available to the receiver. + +**Schema language** + +Protobufs, Cap'n Proto, and FlatBuffers have custom, concise schema languages. + +SBE uses XML schemas, which are verbose. + +**Usable as mutable state** + +Protobuf generated classes have often been (ab)used as a convenient way to store an application's mutable internal state. There's mostly no problem with modifying a message gradually over time and then serializing it when needed. + +This usage pattern does not work well with any zero-copy serialization format because these formats must use arena-style allocation to make sure the message is built in contiguous memory. Arena allocation has the property that you cannot free any object unless you free the entire arena. Therefore, when objects are discarded, the memory ends up leaked until the message as a whole is destroyed. A long-lived message that is modified many times will thus leak memory. + +**Padding takes space on wire?** + +Does the protocol tend to write a lot of zero-valued padding bytes to the wire? + +This is a problem with zero-copy protocols: fixed-width integers tend to have a lot of zeros in the high-order bits, and padding sometimes needs to be inserted for alignment. This padding can easily double or triple the size of a message. + +Protocol Buffers avoids padding by encoding integers using variable widths, which is only possible given a separate encoding/decoding step. + +SBE and FlatBuffers leave the padding in to achieve zero-copy. + +Cap'n Proto normally leaves the padding in, but comes with a built-in option to apply a very fast compression algorithm called "packing" which aims only to deflate zeros. This algorithm tends to achieve similar sizes to Protobufs while still being faster (and _much_ faster than general-purpose compression). In this mode, however, Cap'n Proto is no longer zero-copy. + +Note that Cap'n Proto's packing algorithm would be appropriate for SBE and FlatBuffers as well. Feel free to steal it. :) + +**Unset fields take space on wire?** + +If a field has not been explicitly assigned a value, will it take any space on the wire? + +Protobuf encodes tag-value pairs, so it simply skips pairs that have not been set. + +Cap'n Proto and SBE position fields at fixed offsets from the start of the struct. The struct is always allocated large enough for all known fields according to the schema. So, unused fields waste space. (But Cap'n Proto's optional packing will tend to compress away this space.) + +FlatBuffers uses a separate table of offsets (the vtable) to indicate the position of each field, with zero meaning the field isn't present. So, unset fields take no space on the wire -- although they do take space in the vtable. vtables can apparently be shared between instances where the offsets are all the same, amortizing this cost. + +Of course, all this applies to primitive fields and pointer values, not the sub-objects to which those pointers point. All of these formats elide sub-objects that haven't been initialized. + +**Pointers take space on wire?** + +Do non-primitive fields require storing a pointer? + +Protobufs uses tag-length-value for variable-width fields. + +Cap'n Proto uses pointers for variable-width fields, so that the size of the parent object is independent of the size of any children. These pointers take some space on the wire. + +SBE requires variable-width fields to be embedded in preorder, which means pointers aren't necessary. + +FlatBuffers also uses pointers, even though most objects are variable-width, possibly because the vtables only store 16-bit offsets, limiting the size of any one object. However, note that FlatBuffers' "structs" (which are fixed-width and not extensible) are stored inline (what Cap'n Proto calls a "struct', FlatBuffer calls a "table"). + +**Platform Support** + +As of Dec 15, 2014, Cap'n Proto supports a superset of the languages supported by FlatBuffers and +SBE, but is still far behind Protocol Buffers. + +While Cap'n Proto C++ is well-supported on POSIX platforms using GCC or Clang as their compiler, +Cap'n Proto has only limited support for Visual C++: the basic serialization library works, but +reflection and RPC do not yet work. Support will be expanded once Visual Studio's C++ compiler +completes support for C++11. + +In comparison, SBE and FlatBuffers have reflection interfaces that work in Visual C++, though +neither one has built-in RPC. Reflection is critical for certain use cases, but the majority of +users won't need it. + +(This section has been updated. When originally written, Cap'n Proto did not support MSVC at all.) + +### Benchmarks? + +I do not provide benchmarks. I did not provide them when I launched Protobufs, nor when I launched Cap'n Proto, even though I had some with nice numbers (which you can find in git). And I don't see any reason to start now. + +Why? Because they would tell you nothing. I could easily construct a benchmark to make any given library "win", by exploiting the relative tradeoffs each one makes. I can even construct one where Protobufs -- supposedly infinitely slower than the others -- wins. + +The fact of the matter is that the relative performance of these libraries depends deeply on the use case. To know which one will be fastest for _your_ project, you really need to benchmark them in _your_ project, end-to-end. No contrived benchmark will give you the answer. + +With that said, my intuition is that SBE will probably edge Cap'n Proto and FlatBuffers on performance in the average case, due to its decision to forgo support for random access. Between Cap'n Proto and FlatBuffers, it's harder to say. FlatBuffers' vtable approach seems like it would make access more expensive, though its simpler pointer format may be cheaper to follow. FlatBuffers also appears to do a lot of bookkeeping at encoding time which could get costly (such as de-duping vtables), but I don't know how costly. + +For most people, the performance difference is probably small enough that qualitative (feature) differences in the libraries matter more. + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2014-12-15-capnproto-0.5-generics-msvc-java-csharp.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2014-12-15-capnproto-0.5-generics-msvc-java-csharp.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,116 @@ +--- +layout: post +title: "Cap'n Proto 0.5: Generics, Visual C++, Java, C#, Sandstorm.io" +author: kentonv +--- + +Today we're releasing Cap'n Proto 0.5. We've added lots of goodies! + +### Finally: Visual Studio + +Microsoft Visual Studio 2015 (currently in "preview") finally supports enough C++11 to get Cap'n +Proto working, and we've duly added official support for it! + +Not all features are supported yet. The core serialization functionality sufficient for 90% of users +is available, but reflection and RPC APIs are not. We will turn on these APIs as soon as Visual C++ +is ready (the main blocker is incomplete `constexpr` support). + +As part of this, we now support CMake as a build system, and it can be used on Unix as well. + +In related news, for Windows users not interested in C++ but who need the Cap'n Proto tools for +other languages, we now provide precompiled Windows binaries. See +[the installation page]({{site.baseurl}}install.html). + +I'd like to thank [Bryan Boreham](https://github.com/bboreham), +[Joshua Warner](https://github.com/joshuawarner32), and [Phillip Quinn](https://github.com/pqu) for +their help in getting this working. + +### C#, Java + +While not strictly part of this release, our two biggest missing languages recently gained support +for Cap'n Proto: + +* [Marc Gravell](https://github.com/mgravell) -- the man responsible for the most popular C# + implementation of Protobufs -- has now implemented + [Cap'n Proto in C#](https://github.com/mgravell/capnproto-net). +* [David Renshaw](https://github.com/dwrensha), author of our existing Rust implementation and + [Sandstorm.io](https://sandstorm.io) core developer, has implemented + [Cap'n Proto in Java](https://github.com/dwrensha/capnproto-java). + +### Generics + +Cap'n Proto now supports [generics]({{site.baseurl}}language.html#generic-types), +in the sense of Java generics or C++ templates. While working on +[Sandstorm.io](https://sandstorm.io) we frequently found that we wanted this, and it turned out +to be easy to support. + +This is a feature which Protocol Buffers does not support and likely never will. Cap'n Proto has a +much easier time supporting exotic language features because the generated code is so simple. In +C++, nearly all Cap'n Proto generated code is inline accessor methods, which can easily become +templates. Protocol Buffers, in contrast, has generated parse and serialize functions and a host +of other auxiliary stuff, which is too complex to inline and thus would need to be adapted to +generics without using C++ templates. This would get ugly fast. + +Generics are not yet supported by all Cap'n Proto language implementations, but where they are not +supported, things degrade gracefully: all type parameters simply become `AnyPointer`. You can still +use generics in your schemas as documentation. Meanwhile, at least our C++, Java, and Python +implementations have already been updated to support generics, and other implementations that +wrap the C++ reflection API are likely to work too. + +### Canonicalization + +0.5 introduces a (backwards-compatible) change in +[the way struct lists should be encoded]({{site.baseurl}}encoding.html#lists), in +order to support [canonicalization]({{site.baseurl}}encoding.html#canonicalization). +We believe this will make Cap'n Proto more appropriate for use in cryptographic protocols. If +you've implemented Cap'n Proto in another language, please update your code! + +### Sandstorm and Capability Systems + +[Sandstorm.io](https://sandstorm.io) is Cap'n Proto's parent project: a platform for personal +servers that is radically easier and more secure. + +Cap'n Proto RPC is the underlying communications layer powering Sandstorm. Sandstorm is a +[capability system](http://www.erights.org/elib/capability/overview.html): applications can send +each other object references and address messages to those objects. Messages can themselves contain +new object references, and the recipient implicitly gains permission to use any object reference +they receive. Essentially, Sandstorm allows the interfaces between two apps, or between and app +and the platform, to be designed using the same vocabulary as interfaces between objects or +libraries in an object-oriented programming language (but +[without the mistakes of CORBA or DCOM]({{site.baseurl}}rpc.html#distributed-objects)). +Cap'n Proto RPC is at the core of this. + +This has powerful implications: Consider the case of service discovery. On Sandstorm, all +applications start out isolated from each other in secure containers. However, applications can +(or, will be able to) publish Cap'n Proto object references to the system representing APIs they +support. Then, another app can make a request to the system, saying "I need an object that +implements interface Foo". At this point, the system can display a picker UI to the user, +presenting all objects the user owns that satisfy the requirement. However, the requesting app only +ever receives a reference to the object the user chooses; all others remain hidden. Thus, security +becomes "automatic". The user does not have to edit an ACL on the providing app, nor copy around +credentials, nor even answer any security question at all; it all derives automatically and +naturally from the user's choices. We call this interface "The Powerbox". + +Moreover, because Sandstorm is fully aware of the object references held by every app, it will +be able to display a visualization of these connections, allowing a user to quickly see which of +their apps have access to each other and even revoke connections that are no longer desired with +a mouse click. + +Cap'n Proto 0.5 introduces primitives to support "persistent" capabilities -- that is, the ability +to "save" an object reference to disk and then restore it later, on a different connection. +Obviously, the features described above totally depend on this feature. + +The next release of Cap'n Proto is likely to include another feature essential for Sandstorm: the +ability to pass capabilities from machine to machine and have Cap'n Proto automatically form direct +connections when you do. This allows servers running on different machines to interact with each +other in a completely object-oriented way. Instead of passing around URLs (which necessitate a +global namespace, lifetime management, firewall traversal, and all sorts of other obstacles), you +can pass around capabilities and not worry about it. This will be central to Sandstorm's strategies +for federation and cluster management. + +### Other notes + +* The C++ RPC code now uses `epoll` on Linux. +* We now test Cap'n Proto on Android and MinGW, in addition to Linux, Mac OSX, Cygwin, and Visual + Studio. (iOS and FreeBSD are also reported to work, though are not yet part of our testing + process.) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2015-01-23-capnproto-0.5.1-bugfixes.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2015-01-23-capnproto-0.5.1-bugfixes.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,16 @@ +--- +layout: post +title: "Cap'n Proto 0.5.1: Bugfixes" +author: kentonv +--- + +Cap'n Proto 0.5.1 has just been released with some bug fixes: + +* On Windows, the `capnp` tool would crash when it tried to generate an ID, e.g. when using `capnp id` or when compiling a file that was missing the file ID, because it tried to get random bytes from `/dev/urandom`, which of course doesn't exist on Windows. Oops. Now it uses `CryptGenRandom()`. +* Declaring a generic method (with method-specific type parameters) inside a generic interface generated code that didn't compile. +* `joinPromises()` didn't work on an array of `Promise`. +* Unnecessary error messages were being printed to the console when RPC clients disconnected. + +Sorry about the bugs. + +In other news, as you can see, the Cap'n Proto web site now lives at `capnproto.org`. Additionally, the Github repo has been moved to the [Sandstorm.io organization](https://github.com/sandstorm-io). Both moves have left behind redirects so that old links / repository references should continue to work. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2015-03-02-security-advisory-and-integer-overflow-protection.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2015-03-02-security-advisory-and-integer-overflow-protection.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,134 @@ +--- +layout: post +title: "Security Advisory -- And how to catch integer overflows with template metaprogramming" +author: kentonv +--- + +As the installation page has always stated, I do not yet recommend using Cap'n Proto's C++ library for handling possibly-malicious input, and will not recommend it until it undergoes a formal security review. That said, security is obviously a high priority for the project. The security of Cap'n Proto is in fact essential to the security of [Sandstorm.io](https://sandstorm.io), Cap'n Proto's parent project, in which sandboxed apps communicate with each other and the platform via Cap'n Proto RPC. + +A few days ago, the first major security bugs were found in Cap'n Proto C++ -- two by security guru [Ben Laurie](http://en.wikipedia.org/wiki/Ben_Laurie) and one by myself during subsequent review (see below). You can read details about each bug in our new [security advisories directory](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories): + +* [Integer overflow in pointer validation.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md) +* [Integer underflow in pointer validation.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-1-c++-integer-underflow.md) +* [CPU usage amplification attack.](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-2-all-cpu-amplification.md) + +I have backported the fixes to the last two release branches -- 0.5 and 0.4: + +- Release 0.5.1.1: [source](https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz), [win32](https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip) +- Release 0.4.1.1: [source](https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz) + +Note that we added a "nano" component to the version number (rather than use 0.5.2/0.4.2) to indicate that this release is ABI-compatible with the previous release. If you are linking Cap'n Proto as a shared library, you only need to update the library, not re-compile your app. + +To be clear, the first two bugs affect only the C++ implementation of Cap'n Proto; implementations in other languages are likely safe. The third bug probably affects all languages, and as of this writing only the C++ implementation (and wrappers around it) is fixed. However, this third bug is not as serious as the other two. + +### Preventative Measures + +It is our policy that any time a security problem is found, we will not only fix the problem, but also implement new measures to prevent the class of problems from occurring again. To that end, here's what we're doing doing to avoid problems like these in the future: + +1. A fuzz test of each pointer type has been added to the standard unit test + suite. +2. We will additionally add fuzz testing with American Fuzzy Lop to our + extended test suite. +3. In parallel, we will extend our use of template metaprogramming for + compile-time unit analysis (kj::Quantity in kj/units.h) to also cover + overflow detection (by tracking the maximum size of an integer value across + arithmetic expressions and raising an error when it overflows). More on this + below. +4. We will continue to require that all tests (including the new fuzz test) run + cleanly under Valgrind before each release. +5. We will commission a professional security review before any 1.0 release. + Until that time, we continue to recommend against using Cap'n Proto to + interpret data from potentially-malicious sources. + +I am pleased to report that measures 1, 2, and 3 all detected both integer overflow/underflow problems, and AFL additionally detected the CPU amplification problem. + +### Integer Overflow is Hard + +Integer overflow is a nasty problem. + +In the past, C and C++ code has been plagued by buffer overrun bugs, but these days, systems engineers have mostly learned to avoid them by simply never using static-sized buffers for dynamically-sized content. If we don't see proof that a buffer is the size of the content we're putting in it, our "spidey sense" kicks in. + +But developing a similar sense for integer overflow is hard. We do arithmetic in code all the time, and the vast majority of it isn't an issue. The few places where overflow can happen all too easily go unnoticed. + +And by the way, integer overflow affects many memory-safe languages too! Java and C# don't protect against overflow. Python does, using slow arbitrary-precision integers. Javascript doesn't use integers, and is instead succeptible to loss-of-precision bugs, which can have similar (but more subtle) consequences. + +While writing Cap'n Proto, I made sure to think carefully about overflow and managed to correct for it most of the time. On learning that I missed a case, I immediately feared that I might have missed many more, and wondered how I might go about systematically finding them. + +Fuzz testing -- e.g. using [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/) -- is one approach, and is indeed how Ben found the two bugs he reported. As mentioned above, we will make AFL part of our release process in the future. However, AFL cannot really _prove_ anything -- it can only try lots of possibilities. I want my compiler to refuse to compile arithmetic which might overflow. + +### Proving Safety Through Template Metaprogramming + +C++ Template Metaprogramming is powerful -- many would say _too_ powerful. As it turns out, it's powerful enough to do what we want. + +I defined a new type: + +{% highlight C++ %} +template +class Guarded { + // Wraps T (a basic integer type) and statically guarantees + // that the value can be no more than `maxN` and no less than + // zero. + + static_assert(maxN <= T(kj::maxValue), "possible overflow detected"); + // If maxN is not representable in type T, we can no longer + // guarantee no overflows. + +public: + // ... + + template + inline constexpr Guarded(const Guarded& other) + : value(other.value) { + // You cannot construct a Guarded from another Guarded + // with a higher maximum. + static_assert(otherMax <= maxN, "possible overflow detected"); + } + + // ... + + template + inline constexpr Guarded(), + decltype(T() + otherT())> + operator+(const Guarded& other) const { + // Addition operator also computes the new maximum. + // (`guardedAdd` is a constexpr template that adds two + // constants while detecting overflow.) + return Guarded(), + decltype(T() + otherT())>( + value + other.value, unsafe); + } + + // ... + +private: + T value; +}; +{% endhighlight %} + +So, a `Guarded<10, int>` represents a `int` which is statically guaranteed to hold a non-negative value no greater than 10. If you add a `Guarded<10, int>` to `Guarded<15, int>`, the result is a `Guarded<25, int>`. If you try to initialize a `Guarded<10, int>` from a `Guarded<25, int>`, you'll trigger a `static_assert` -- the compiler will complain. You can, however, initialize a `Guarded<25, int>` from a `Guarded<10, int>` with no problem. + +Moreover, because all of `Guarded`'s operators are inline and `constexpr`, a good optimizing compiler will be able to optimize `Guarded` down to the underlying primitive integer type. So, in theory, using `Guarded` has no runtime overhead. (I have not yet verified that real compilers get this right, but I suspect they do.) + +Of course, the full implementation is considerably more complicated than this. The code has not been merged into the Cap'n Proto tree yet as we need to do more analysis to make sure it has no negative impact. For now, you can find it in the [overflow-safe](https://github.com/sandstorm-io/capnproto/tree/overflow-safe) branch, specifically in the second half of [kj/units.h](https://github.com/sandstorm-io/capnproto/blob/overflow-safe/c++/src/kj/units.h). (This header also contains metaprogramming for compile-time unit analysis, which Cap'n Proto has been using since its first release.) + +### Results + +I switched Cap'n Proto's core pointer validation code (`capnp/layout.c++`) over to `Guarded`. In the process, I found: + +* Several overflows that could be triggered by the application calling methods with invalid parameters, but not by a remote attacker providing invalid message data. We will change the code to check these in the future, but they are not critical security problems. +* The overflow that Ben had already reported ([2015-03-02-0](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md)). I had intentionally left this unfixed during my analysis to verify that `Guarded` would catch it. +* One otherwise-undiscovered integer underflow ([2015-03-02-1](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-1-c++-integer-underflow.md)). + +Based on these results, I conclude that `Guarded` is in fact effective at finding overflow bugs, and that such bugs are thankfully _not_ endemic in Cap'n Proto's code. + +With that said, it does not seem practical to change every integer throughout the Cap'n Proto codebase to use `Guarded` -- using it in the API would create too much confusion and cognitive overhead for users, and would force application code to be more verbose. Therefore, this approach unfortunately will not be able to find all integer overflows throughout the entire library, but fortunately the most sensitive parts are covered in `layout.c++`. + +### Why don't programming languages do this? + +Anything that can be implemented in C++ templates can obviously be implemented by the compiler directly. So, why have so many languages settled for either modular arithmetic or slow arbitrary-precision integers? + +Languages could even do something which my templates cannot: allow me to declare relations between variables. For example, I would like to be able to declare an integer whose value is less than the size of some array. Then I know that the integer is a safe index for the array, without any run-time check. + +Obviously, I'm not the first to think of this. "Dependent types" have been researched for decades, but we have yet to see a practical language supporting them. Apparently, something about them is complicated, even though the rules look like they should be simple enough from where I'm standing. + +Some day, I would like to design a language that gets this right. But for the moment, I remain focused on [Sandstorm.io](https://sandstorm.io). Hopefully someone will beat me to it. Hint hint. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2015-03-05-another-cpu-amplification.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2015-03-05-another-cpu-amplification.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,16 @@ +--- +layout: post +title: "Another security advisory -- Additional CPU amplification case" +author: kentonv +--- + +Unfortunately, it turns out that our fix for one of [the security advisories issued on Monday](2015-03-02-security-advisory-and-integer-overflow-protection.html) was not complete. + +Fortunately, the incomplete fix is for the non-critical vulnerability. The worst case is that an attacker could consume excessive CPU time. + +Nevertheless, we've issued [a new advisory](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-05-0-c++-addl-cpu-amplification.md) and pushed a new release: + +- Release 0.5.1.2: [source](https://capnproto.org/capnproto-c++-0.5.1.2.tar.gz), [win32](https://capnproto.org/capnproto-c++-win32-0.5.1.2.zip) +- Release 0.4.1.2: [source](https://capnproto.org/capnproto-c++-0.4.1.2.tar.gz) + +Sorry for the rapid repeated releases, but we don't like sitting on security bugs. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/_posts/2017-05-01-capnproto-0.6-msvc-json-http-more.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/_posts/2017-05-01-capnproto-0.6-msvc-json-http-more.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,72 @@ +--- +layout: post +title: "Cap'n Proto 0.6 Released: Two and a half years of improvements" +author: kentonv +--- + + + +Today we're releasing Cap'n Proto 0.6, the first major Cap'n Proto release in nearly 2.5 years. + +Cap'n Proto has been under active development the entire time, as part of its parent project, [Sandstorm.io](https://sandstorm.io). The lack of releases did not indicate a lack of development, but rather a lack of keeping the code running on every platform it supports -- especially Windows. Without a working Windows build, we couldn't do a release. But as Sandstorm didn't need Windows, it was hard to prioritize -- that is, until contributors stepped up! + +Note that this release encompasses the core tools and the C++ reference implementation. Implementations in other languages have their own release schedules, but it's likely that several will be updated soon to integrate new language features. + +### Brought to you by Cloudflare + +[As announced on the Sandstorm blog](https://sandstorm.io/news/2017-03-13-joining-cloudflare), most of the Sandstorm team (including myself) now work for [Cloudflare](https://cloudflare.com). Cloudflare is one of the largest users of Cap'n Proto, [as described in this talk by John-Graham Cumming](https://youtu.be/LA-gNoxSLCE?t=12m47s), and as such maintaining Cap'n Proto is part of my job at Cloudflare. + + + +### What's New? + +#### Full Windows / Visual Studio Support + +With this release, all of Cap'n Proto's functionality now works on Windows with Visual Studio 2015 and 2017. That includes the serialization, dynamic API, schema parser, async I/O framework (using I/O completion ports), RPC, and tools. This is a huge step up from 0.5, in which Cap'n Proto could only be built in "lite mode", which supported only basic serialization. + +Most of the work to make this happen was contributed by [**Harris Hancock**](https://github.com/harrishancock) (with some help from [Gordon McShane](https://github.com/gordonmcshane), [Mark Grimes](https://github.com/mark-grimes), myself, and others). It was no small feat: Visual Studio's C++ compiler is still quite buggy, so lots of work-arounds were needed. Meanwhile, the Cap'n Proto developers working on Linux were continuously introducing new issues with their changes. Harris sorted it all out and delivered a beautiful series of patches. He also helped get us set up with [continuous integration on AppVeyor](https://ci.appveyor.com/project/kentonv/capnproto), so that we can stay on top of these issues going forward. + +#### Security Hardening + +The 0.6 release includes a number of measures designed to harden Cap'n Proto's C++ implementation against possible security bugs. These include: + +* The core pointer validation code has been refactored to detect possible integer overflows at compile time using C++ template metaprogramming, as [described in this old blog post](https://capnproto.org/news/2015-03-02-security-advisory-and-integer-overflow-protection.html). +* The core test suite -- which runs when you type `make check` -- now includes a targeted fuzz test of the pointer validation code. +* We additionally tested this release using American Fuzzy Lop, running several different test cases for over three days each. + +#### JSON converter + +Cap'n Proto messages can now be converted to and from JSON using `libcapnp-json`. This makes it easy to integrate your JSON front-end API with your Cap'n Proto back-end. + +See the capnp/compat/json.h header for API details. + +This library was primarily built by [**Kamal Marhubi**](https://github.com/kamalmarhubi) and [**Branislav Katreniak**](https://github.com/katreniak), using Cap'n Proto's [dynamic API]({{site.baseurl}}cxx.html#dynamic-reflection). + +#### HTTP library + +KJ (the C++ framework library bundled with Cap'n Proto) now ships with a minimalist HTTP library, `libkj-http`. The library is based on the KJ asynchronous I/O framework and covers both client-side and server-side use cases. Although functional and used in production today, the library should be considered a work in progress -- expect improvements in future releases, such as client connection pooling and TLS support. + +See the kj/compat/http.h header for API details. + +#### Smaller things + +With two years of development, there are far too many changes to list, but here are some more things: + +* KJ now offers its own unit test framework under `kj/test.h`, as well as a compatibility shim with Google Test under `kj/compat/gtest.h`. The KJ and Cap'n Proto tests no longer depend on Google Test. +* New API `capnp::TextCodec` in `capnp/serialize-text.h` provides direct access to parse text-format Cap'n Proto messages (requires `libcapnpc`, the schema parser library). (Contributed by: [**Philip Quinn**](https://github.com/pqu)) +* It is possible to compare Cap'n Proto messages for equality (with correct handling of unknown fields, something Protocol Buffers struggled with) using APIs in `capnp/any.h`. (Contributed by: [**Joshua Warner**](https://github.com/joshuawarner32)) +* A function `capnp::canonicalize()` has been added which returns the canonical serialization of a given struct. (Contributed by: [**Matthew Maurer**](https://github.com/maurer)) +* `AnyPointer` fields can now be assigned in constant values, by referencing another named constant (which itself is defined with a specific type). +* In addition to `AnyPointer`, the types `AnyStruct`, `AnyList`, and `Capability` can now be used in schemas. +* New class `capnp::CapabilityServerSet` in `capnp/capability.h` allows an RPC server to detect when capabilities to its own local objects are passed back to it and allows it to "unwrap" them to get at the underlying native object. +* A membrane framework library was added (header `capnp/membrane.h`). This makes it easy to set up a MITM layer between RPC actors, e.g. to implement revocability, transformations, and many other useful capability patterns. +* Basic flow control can now be applied to an RPC connection, preventing new messages from being accepted if outstanding calls exceed a certain watermark, which helps prevent excessive buffering / malicious resource exhaustion. See `RpcSystem::setFlowLimit()`. +* KJ's networking API now includes datagram protocols (UDP). +* In `.capnp` syntax, all comma-delimited lists can now have a trailing comma. (Contributed by: [**Drew Fisher**](https://github.com/zarvox)) +* Hundreds more small feature additions and bug fixes. + + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/capnp-tool.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/capnp-tool.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,81 @@ +--- +layout: page +title: The capnp Tool +--- + +# The `capnp` Tool + +Cap'n Proto comes with a command-line tool called `capnp` intended to aid development and +debugging. This tool can be used to: + +* Compile Cap'n Proto schemas to produce source code in multiple languages. +* Generate unique type IDs. +* Decode Cap'n Proto messages to human-readable text. +* Encode text representations of Cap'n Proto messages to binary. +* Evaluate and extract constants defined in Cap'n Proto schemas. + +This page summarizes the functionality. A complete reference on the command's usage can be +found by typing: + + capnp help + +## Compiling Schemas + + capnp compile -oc++ myschema.capnp + +This generates files `myschema.capnp.h` and `myschema.capnp.c++` which contain C++ source code +corresponding to the types defined in `myschema.capnp`. Options exist to control output location +and import paths. + +The above example generates C++ code, but the tool is able to generate output in any language +for which a plugin is available. Compiler plugins are just regular programs named +`capnpc-language`. For example, the above command runs `capnpc-c++`. [More on how to write +compiler plugins](otherlang.html#how-to-write-compiler-plugins). + +Note that some Cap'n Proto implementations (especially for interpreted languages) do not require +generating source code. + +## Decoding Messages + + capnp decode myschema.capnp MyType < message.bin > message.txt + +`capnp decode` reads a binary Cap'n Proto message from standard input and decodes it to a +human-readable text format (specifically, the format used for specifying constants and default +values in [the schema language](language.html)). By default it +expects an unpacked message, but you can decode a +[packed](encoding.html#packing) message with the `--packed` flag. + +## Encoding Messages + + capnp encode myschema.capnp MyType < message.txt > message.bin + +`capnp encode` is the opposite of `capnp decode`: it takes a text-format message on stdin and +encodes it to binary (possibly [packed](encoding.html#packing), +with the `--packed` flag). + +This is mainly useful for debugging purposes, to build test data or to apply tweaks to data +decoded with `capnp decode`. You should not rely on `capnp encode` for encoding data written +and maintained in text format long-term -- instead, use `capnp eval`, which is much more powerful. + +## Evaluating Constants + + capnp eval myschema.capnp myConstant + +This prints the value of `myConstant`, a [const](language.html#constants) declaration, after +applying variable substitution. It can also output the value in binary format (`--binary` or +`--packed`). + +At first glance, this may seem no more interesting that `capnp encode`: the syntax used to define +constants in schema files is the same as the format accepted by `capnp encode`, right? There is, +however, a big difference: constants in schema files may be defined in terms of other constants, +which may even be imported from other files. + +As a result, `capnp eval` is a great basis for implementing config files. For example, a large +company might maintain a production server that serves dozens of clients and needs configuration +information about each one. Rather than maintaining the config as one enormous file, it can be +written as several separate files with a master file that imports the rest. + +Such a configuration should be compiled to binary format using `capnp eval` before deployment, +in order to verify that there are no errors and to make deployment easier and faster. While you +could technically ship the text configs to production and have the servers parse them directly +(e.g. with `capnp::SchemaParser`), encoding before deployment is more efficient and robust. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/cxx.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/cxx.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,919 @@ +--- +layout: page +title: C++ Serialization +--- + +# C++ Serialization + +The Cap'n Proto C++ runtime implementation provides an easy-to-use interface for manipulating +messages backed by fast pointer arithmetic. This page discusses the serialization layer of +the runtime; see [C++ RPC](cxxrpc.html) for information about the RPC layer. + +## Example Usage + +For the Cap'n Proto definition: + +{% highlight capnp %} +struct Person { + id @0 :UInt32; + name @1 :Text; + email @2 :Text; + phones @3 :List(PhoneNumber); + + struct PhoneNumber { + number @0 :Text; + type @1 :Type; + + enum Type { + mobile @0; + home @1; + work @2; + } + } + + employment :union { + unemployed @4 :Void; + employer @5 :Text; + school @6 :Text; + selfEmployed @7 :Void; + # We assume that a person is only one of these. + } +} + +struct AddressBook { + people @0 :List(Person); +} +{% endhighlight %} + +You might write code like: + +{% highlight c++ %} +#include "addressbook.capnp.h" +#include +#include +#include + +void writeAddressBook(int fd) { + ::capnp::MallocMessageBuilder message; + + AddressBook::Builder addressBook = message.initRoot(); + ::capnp::List::Builder people = addressBook.initPeople(2); + + Person::Builder alice = people[0]; + alice.setId(123); + alice.setName("Alice"); + alice.setEmail("alice@example.com"); + // Type shown for explanation purposes; normally you'd use auto. + ::capnp::List::Builder alicePhones = + alice.initPhones(1); + alicePhones[0].setNumber("555-1212"); + alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE); + alice.getEmployment().setSchool("MIT"); + + Person::Builder bob = people[1]; + bob.setId(456); + bob.setName("Bob"); + bob.setEmail("bob@example.com"); + auto bobPhones = bob.initPhones(2); + bobPhones[0].setNumber("555-4567"); + bobPhones[0].setType(Person::PhoneNumber::Type::HOME); + bobPhones[1].setNumber("555-7654"); + bobPhones[1].setType(Person::PhoneNumber::Type::WORK); + bob.getEmployment().setUnemployed(); + + writePackedMessageToFd(fd, message); +} + +void printAddressBook(int fd) { + ::capnp::PackedFdMessageReader message(fd); + + AddressBook::Reader addressBook = message.getRoot(); + + for (Person::Reader person : addressBook.getPeople()) { + std::cout << person.getName().cStr() << ": " + << person.getEmail().cStr() << std::endl; + for (Person::PhoneNumber::Reader phone: person.getPhones()) { + const char* typeName = "UNKNOWN"; + switch (phone.getType()) { + case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break; + case Person::PhoneNumber::Type::HOME: typeName = "home"; break; + case Person::PhoneNumber::Type::WORK: typeName = "work"; break; + } + std::cout << " " << typeName << " phone: " + << phone.getNumber().cStr() << std::endl; + } + Person::Employment::Reader employment = person.getEmployment(); + switch (employment.which()) { + case Person::Employment::UNEMPLOYED: + std::cout << " unemployed" << std::endl; + break; + case Person::Employment::EMPLOYER: + std::cout << " employer: " + << employment.getEmployer().cStr() << std::endl; + break; + case Person::Employment::SCHOOL: + std::cout << " student at: " + << employment.getSchool().cStr() << std::endl; + break; + case Person::Employment::SELF_EMPLOYED: + std::cout << " self-employed" << std::endl; + break; + } + } +} +{% endhighlight %} + +## C++ Feature Usage: C++11, Exceptions + +This implementation makes use of C++11 features. If you are using GCC, you will need at least +version 4.7 to compile Cap'n Proto. If you are using Clang, you will need at least version 3.2. +These compilers required the flag `-std=c++11` to enable C++11 features -- your code which +`#include`s Cap'n Proto headers will need to be compiled with this flag. Other compilers have not +been tested at this time. + +This implementation prefers to handle errors using exceptions. Exceptions are only used in +circumstances that should never occur in normal operation. For example, exceptions are thrown +on assertion failures (indicating bugs in the code), network failures, and invalid input. +Exceptions thrown by Cap'n Proto are never part of the interface and never need to be caught in +correct usage. The purpose of throwing exceptions is to allow higher-level code a chance to +recover from unexpected circumstances without disrupting other work happening in the same process. +For example, a server that handles requests from multiple clients should, on exception, return an +error to the client that caused the exception and close that connection, but should continue +handling other connections normally. + +When Cap'n Proto code might throw an exception from a destructor, it first checks +`std::uncaught_exception()` to ensure that this is safe. If another exception is already active, +the new exception is assumed to be a side-effect of the main exception, and is either silently +swallowed or reported on a side channel. + +In recognition of the fact that some teams prefer not to use exceptions, and that even enabling +exceptions in the compiler introduces overhead, Cap'n Proto allows you to disable them entirely +by registering your own exception callback. The callback will be called in place of throwing an +exception. The callback may abort the process, and is required to do so in certain circumstances +(when a fatal bug is detected). If the callback returns normally, Cap'n Proto will attempt +to continue by inventing "safe" values. This will lead to garbage output, but at least the program +will not crash. Your exception callback should set some sort of a flag indicating that an error +occurred, and somewhere up the stack you should check for that flag and cancel the operation. +See the header `kj/exception.h` for details on how to register an exception callback. + +## KJ Library + +Cap'n Proto is built on top of a basic utility library called KJ. The two were actually developed +together -- KJ is simply the stuff which is not specific to Cap'n Proto serialization, and may be +useful to others independently of Cap'n Proto. For now, the the two are distributed together. The +name "KJ" has no particular meaning; it was chosen to be short and easy-to-type. + +As of v0.3, KJ is distributed with Cap'n Proto but built as a separate library. You may need +to explicitly link against libraries: `-lcapnp -lkj` + +## Generating Code + +To generate C++ code from your `.capnp` [interface definition](language.html), run: + + capnp compile -oc++ myproto.capnp + +This will create `myproto.capnp.h` and `myproto.capnp.c++` in the same directory as `myproto.capnp`. + +To use this code in your app, you must link against both `libcapnp` and `libkj`. If you use +`pkg-config`, Cap'n Proto provides the `capnp` module to simplify discovery of compiler and linker +flags. + +If you use [RPC](cxxrpc.html) (i.e., your schema defines [interfaces](language.html#interfaces)), +then you will additionally nead to link against `libcapnp-rpc` and `libkj-async`, or use the +`capnp-rpc` `pkg-config` module. + +### Setting a Namespace + +You probably want your generated types to live in a C++ namespace. You will need to import +`/capnp/c++.capnp` and use the `namespace` annotation it defines: + +{% highlight capnp %} +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("foo::bar::baz"); +{% endhighlight %} + +Note that `capnp/c++.capnp` is installed in `$PREFIX/include` (`/usr/local/include` by default) +when you install the C++ runtime. The `capnp` tool automatically searches `/usr/include` and +`/usr/local/include` for imports that start with a `/`, so it should "just work". If you installed +somewhere else, you may need to add it to the search path with the `-I` flag to `capnp compile`, +which works much like the compiler flag of the same name. + +## Types + +### Primitive Types + +Primitive types map to the obvious C++ types: + +* `Bool` -> `bool` +* `IntNN` -> `intNN_t` +* `UIntNN` -> `uintNN_t` +* `Float32` -> `float` +* `Float64` -> `double` +* `Void` -> `::capnp::Void` (An empty struct; its only value is `::capnp::VOID`) + +### Structs + +For each struct `Foo` in your interface, a C++ type named `Foo` generated. This type itself is +really just a namespace; it contains two important inner classes: `Reader` and `Builder`. + +`Reader` represents a read-only instance of `Foo` while `Builder` represents a writable instance +(usually, one that you are building). Both classes behave like pointers, in that you can pass them +by value and they do not own the underlying data that they operate on. In other words, +`Foo::Builder` is like a pointer to a `Foo` while `Foo::Reader` is like a const pointer to a `Foo`. + +For every field `bar` defined in `Foo`, `Foo::Reader` has a method `getBar()`. For primitive types, +`get` just returns the type, but for structs, lists, and blobs, it returns a `Reader` for the +type. + +{% highlight c++ %} +// Example Reader methods: + +// myPrimitiveField @0 :Int32; +int32_t getMyPrimitiveField(); + +// myTextField @1 :Text; +::capnp::Text::Reader getMyTextField(); +// (Note that Text::Reader may be implicitly cast to const char* and +// std::string.) + +// myStructField @2 :MyStruct; +MyStruct::Reader getMyStructField(); + +// myListField @3 :List(Float64); +::capnp::List getMyListField(); +{% endhighlight %} + +`Foo::Builder`, meanwhile, has several methods for each field `bar`: + +* `getBar()`: For primitives, returns the value. For composites, returns a Builder for the + composite. If a composite field has not been initialized (i.e. this is the first time it has + been accessed), it will be initialized to a copy of the field's default value before returning. +* `setBar(x)`: For primitives, sets the value to x. For composites, sets the value to a deep copy + of x, which must be a Reader for the type. +* `initBar(n)`: Only for lists and blobs. Sets the field to a newly-allocated list or blob + of size n and returns a Builder for it. The elements of the list are initialized to their empty + state (zero for numbers, default values for structs). +* `initBar()`: Only for structs. Sets the field to a newly-allocated struct and returns a + Builder for it. Note that the newly-allocated struct is initialized to the default value for + the struct's _type_ (i.e., all-zero) rather than the default value for the field `bar` (if it + has one). +* `hasBar()`: Only for pointer fields (e.g. structs, lists, blobs). Returns true if the pointer + has been initialized (non-null). (This method is also available on readers.) +* `adoptBar(x)`: Only for pointer fields. Adopts the orphaned object x, linking it into the field + `bar` without copying. See the section on orphans. +* `disownBar()`: Disowns the value pointed to by `bar`, setting the pointer to null and returning + its previous value as an orphan. See the section on orphans. + +{% highlight c++ %} +// Example Builder methods: + +// myPrimitiveField @0 :Int32; +int32_t getMyPrimitiveField(); +void setMyPrimitiveField(int32_t value); + +// myTextField @1 :Text; +::capnp::Text::Builder getMyTextField(); +void setMyTextField(::capnp::Text::Reader value); +::capnp::Text::Builder initMyTextField(size_t size); +// (Note that Text::Reader is implicitly constructable from const char* +// and std::string, and Text::Builder can be implicitly cast to +// these types.) + +// myStructField @2 :MyStruct; +MyStruct::Builder getMyStructField(); +void setMyStructField(MyStruct::Reader value); +MyStruct::Builder initMyStructField(); + +// myListField @3 :List(Float64); +::capnp::List::Builder getMyListField(); +void setMyListField(::capnp::List::Reader value); +::capnp::List::Builder initMyListField(size_t size); +{% endhighlight %} + +### Groups + +Groups look a lot like a combination of a nested type and a field of that type, except that you +cannot set, adopt, or disown a group -- you can only get and init it. + +### Unions + +A named union (as opposed to an unnamed one) works just like a group, except with some additions: + +* For each field `foo`, the union reader and builder have a method `isFoo()` which returns true + if `foo` is the currently-set field in the union. +* The union reader and builder also have a method `which()` that returns an enum value indicating + which field is currently set. +* Calling the set, init, or adopt accessors for a field makes it the currently-set field. +* Calling the get or disown accessors on a field that isn't currently set will throw an + exception in debug mode or return garbage when `NDEBUG` is defined. + +Unnamed unions differ from named unions only in that the accessor methods from the union's members +are added directly to the containing type's reader and builder, rather than generating a nested +type. + +See the [example](#example-usage) at the top of the page for an example of unions. + +### Lists + +Lists are represented by the type `capnp::List`, where `T` is any of the primitive types, +any Cap'n Proto user-defined type, `capnp::Text`, `capnp::Data`, or `capnp::List` +(to form a list of lists). + +The type `List` itself is not instantiatable, but has two inner classes: `Reader` and `Builder`. +As with structs, these types behave like pointers to read-only and read-write data, respectively. + +Both `Reader` and `Builder` implement `size()`, `operator[]`, `begin()`, and `end()`, as good C++ +containers should. Note, though, that `operator[]` is read-only -- you cannot use it to assign +the element, because that would require returning a reference, which is impossible because the +underlying data may not be in your CPU's native format (e.g., wrong byte order). Instead, to +assign an element of a list, you must use `builder.set(index, value)`. + +For `List` where `Foo` is a non-primitive type, the type returned by `operator[]` and +`iterator::operator*()` is `Foo::Reader` (for `List::Reader`) or `Foo::Builder` +(for `List::Builder`). The builder's `set` method takes a `Foo::Reader` as its second +parameter. + +For lists of lists or lists of blobs, the builder also has a method `init(index, size)` which sets +the element at the given index to a newly-allocated value with the given size and returns a builder +for it. Struct lists do not have an `init` method because all elements are initialized to empty +values when the list is created. + +### Enums + +Cap'n Proto enums become C++11 "enum classes". That means they behave like any other enum, but +the enum's values are scoped within the type. E.g. for an enum `Foo` with value `bar`, you must +refer to the value as `Foo::BAR`. + +To match prevaling C++ style, an enum's value names are converted to UPPERCASE_WITH_UNDERSCORES +(whereas in the schema language you'd write them in camelCase). + +Keep in mind when writing `switch` blocks that an enum read off the wire may have a numeric +value that is not listed in its definition. This may be the case if the sender is using a newer +version of the protocol, or if the message is corrupt or malicious. In C++11, enums are allowed +to have any value that is within the range of their base type, which for Cap'n Proto enums is +`uint16_t`. + +### Blobs (Text and Data) + +Blobs are manipulated using the classes `capnp::Text` and `capnp::Data`. These classes are, +again, just containers for inner classes `Reader` and `Builder`. These classes are iterable and +implement `size()` and `operator[]` methods. `Builder::operator[]` even returns a reference +(unlike with `List`). `Text::Reader` additionally has a method `cStr()` which returns a +NUL-terminated `const char*`. + +As a special convenience, if you are using GCC 4.8+ or Clang, `Text::Reader` (and its underlying +type, `kj::StringPtr`) can be implicitly converted to and from `std::string` format. This is +accomplished without actually `#include`ing ``, since some clients do not want to rely +on this rather-bulky header. In fact, any class which defines a `.c_str()` method will be +implicitly convertible in this way. Unfortunately, this trick doesn't work on GCC 4.7. + +### Interfaces + +[Interfaces (RPC) have their own page.](cxxrpc.html) + +### Generics + +[Generic types](language.html#generic-types) become templates in C++. The outer type (the one whose +name matches the schema declaration's name) is templatized; the inner `Reader` and `Builder` types +are not, because they inherit the parameters from the outer type. Similarly, template parameters +should refer to outer types, not `Reader` or `Builder` types. + +For example, given: + +{% highlight capnp %} +struct Map(Key, Value) { + entries @0 :List(Entry); + struct Entry { + key @0 :Key; + value @1 :Value; + } +} + +struct People { + byName @0 :Map(Text, Person); + # Maps names to Person instances. +} +{% endhighlight %} + +You might write code like: + +{% highlight c++ %} +void processPeople(People::Reader people) { + Map::Reader reader = people.getByName(); + capnp::List::Entry>::Reader entries = + reader.getEntries() + for (auto entry: entries) { + processPerson(entry); + } +} +{% endhighlight %} + +Note that all template parameters will be specified with a default value of `AnyPointer`. +Therefore, the type `Map<>` is equivalent to `Map`. + +### Constants + +Constants are exposed with their names converted to UPPERCASE_WITH_UNDERSCORES naming style +(whereas in the schema language you’d write them in camelCase). Primitive constants are just +`constexpr` values. Pointer-type constants (e.g. structs, lists, and blobs) are represented +using a proxy object that can be converted to the relevant `Reader` type, either implicitly or +using the unary `*` or `->` operators. + +## Messages and I/O + +To create a new message, you must start by creating a `capnp::MessageBuilder` +(`capnp/message.h`). This is an abstract type which you can implement yourself, but most users +will want to use `capnp::MallocMessageBuilder`. Once your message is constructed, write it to +a file descriptor with `capnp::writeMessageToFd(fd, builder)` (`capnp/serialize.h`) or +`capnp::writePackedMessageToFd(fd, builder)` (`capnp/serialize-packed.h`). + +To read a message, you must create a `capnp::MessageReader`, which is another abstract type. +Implementations are specific to the data source. You can use `capnp::StreamFdMessageReader` +(`capnp/serialize.h`) or `capnp::PackedFdMessageReader` (`capnp/serialize-packed.h`) +to read from file descriptors; both take the file descriptor as a constructor argument. + +Note that if your stream contains additional data after the message, `PackedFdMessageReader` may +accidentally read some of that data, since it does buffered I/O. To make this work correctly, you +will need to set up a multi-use buffered stream. Buffered I/O may also be a good idea with +`StreamFdMessageReader` and also when writing, for performance reasons. See `capnp/io.h` for +details. + +There is an [example](#example-usage) of all this at the beginning of this page. + +### Using mmap + +Cap'n Proto can be used together with `mmap()` (or Win32's `MapViewOfFile()`) for extremely fast +reads, especially when you only need to use a subset of the data in the file. Currently, +Cap'n Proto is not well-suited for _writing_ via `mmap()`, only reading, but this is only because +we have not yet invented a mutable segment framing format -- the underlying design should +eventually work for both. + +To take advantage of `mmap()` at read time, write your file in regular serialized (but NOT packed) +format -- that is, use `writeMessageToFd()`, _not_ `writePackedMessageToFd()`. Now, `mmap()` in +the entire file, and then pass the mapped memory to the constructor of +`capnp::FlatArrayMessageReader` (defined in `capnp/serialize.h`). That's it. You can use the +reader just like a normal `StreamFdMessageReader`. The operating system will automatically page +in data from disk as you read it. + +`mmap()` works best when reading from flash media, or when the file is already hot in cache. +It works less well with slow rotating disks. Here, disk seeks make random access relatively +expensive. Also, if I/O throughput is your bottleneck, then the fact that mmaped data cannot +be packed or compressed may hurt you. However, it all depends on what fraction of the file you're +actually reading -- if you only pull one field out of one deeply-nested struct in a huge tree, it +may still be a win. The only way to know for sure is to do benchmarks! (But be careful to make +sure your benchmark is actually interacting with disk and not cache.) + +## Dynamic Reflection + +Sometimes you want to write generic code that operates on arbitrary types, iterating over the +fields or looking them up by name. For example, you might want to write code that encodes +arbitrary Cap'n Proto types in JSON format. This requires something like "reflection", but C++ +does not offer reflection. Also, you might even want to operate on types that aren't compiled +into the binary at all, but only discovered at runtime. + +The C++ API supports inspecting schemas at runtime via the interface defined in +`capnp/schema.h`, and dynamically reading and writing instances of arbitrary types via +`capnp/dynamic.h`. Here's the example from the beginning of this file rewritten in terms +of the dynamic API: + +{% highlight c++ %} +#include "addressbook.capnp.h" +#include +#include +#include +#include +#include + +using ::capnp::DynamicValue; +using ::capnp::DynamicStruct; +using ::capnp::DynamicEnum; +using ::capnp::DynamicList; +using ::capnp::List; +using ::capnp::Schema; +using ::capnp::StructSchema; +using ::capnp::EnumSchema; + +using ::capnp::Void; +using ::capnp::Text; +using ::capnp::MallocMessageBuilder; +using ::capnp::PackedFdMessageReader; + +void dynamicWriteAddressBook(int fd, StructSchema schema) { + // Write a message using the dynamic API to set each + // field by text name. This isn't something you'd + // normally want to do; it's just for illustration. + + MallocMessageBuilder message; + + // Types shown for explanation purposes; normally you'd + // use auto. + DynamicStruct::Builder addressBook = + message.initRoot(schema); + + DynamicList::Builder people = + addressBook.init("people", 2).as(); + + DynamicStruct::Builder alice = + people[0].as(); + alice.set("id", 123); + alice.set("name", "Alice"); + alice.set("email", "alice@example.com"); + auto alicePhones = alice.init("phones", 1).as(); + auto phone0 = alicePhones[0].as(); + phone0.set("number", "555-1212"); + phone0.set("type", "mobile"); + alice.get("employment").as() + .set("school", "MIT"); + + auto bob = people[1].as(); + bob.set("id", 456); + bob.set("name", "Bob"); + bob.set("email", "bob@example.com"); + + // Some magic: We can convert a dynamic sub-value back to + // the native type with as()! + List::Builder bobPhones = + bob.init("phones", 2).as>(); + bobPhones[0].setNumber("555-4567"); + bobPhones[0].setType(Person::PhoneNumber::Type::HOME); + bobPhones[1].setNumber("555-7654"); + bobPhones[1].setType(Person::PhoneNumber::Type::WORK); + bob.get("employment").as() + .set("unemployed", ::capnp::VOID); + + writePackedMessageToFd(fd, message); +} + +void dynamicPrintValue(DynamicValue::Reader value) { + // Print an arbitrary message via the dynamic API by + // iterating over the schema. Look at the handling + // of STRUCT in particular. + + switch (value.getType()) { + case DynamicValue::VOID: + std::cout << ""; + break; + case DynamicValue::BOOL: + std::cout << (value.as() ? "true" : "false"); + break; + case DynamicValue::INT: + std::cout << value.as(); + break; + case DynamicValue::UINT: + std::cout << value.as(); + break; + case DynamicValue::FLOAT: + std::cout << value.as(); + break; + case DynamicValue::TEXT: + std::cout << '\"' << value.as().cStr() << '\"'; + break; + case DynamicValue::LIST: { + std::cout << "["; + bool first = true; + for (auto element: value.as()) { + if (first) { + first = false; + } else { + std::cout << ", "; + } + dynamicPrintValue(element); + } + std::cout << "]"; + break; + } + case DynamicValue::ENUM: { + auto enumValue = value.as(); + KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) { + std::cout << + enumerant->getProto().getName().cStr(); + } else { + // Unknown enum value; output raw number. + std::cout << enumValue.getRaw(); + } + break; + } + case DynamicValue::STRUCT: { + std::cout << "("; + auto structValue = value.as(); + bool first = true; + for (auto field: structValue.getSchema().getFields()) { + if (!structValue.has(field)) continue; + if (first) { + first = false; + } else { + std::cout << ", "; + } + std::cout << field.getProto().getName().cStr() + << " = "; + dynamicPrintValue(structValue.get(field)); + } + std::cout << ")"; + break; + } + default: + // There are other types, we aren't handling them. + std::cout << "?"; + break; + } +} + +void dynamicPrintMessage(int fd, StructSchema schema) { + PackedFdMessageReader message(fd); + dynamicPrintValue(message.getRoot(schema)); + std::cout << std::endl; +} +{% endhighlight %} + +Notes about the dynamic API: + +* You can implicitly cast any compiled Cap'n Proto struct reader/builder type directly to + `DynamicStruct::Reader`/`DynamicStruct::Builder`. Similarly with `List` and `DynamicList`, + and even enum types and `DynamicEnum`. Finally, all valid Cap'n Proto field types may be + implicitly converted to `DynamicValue`. + +* You can load schemas dynamically at runtime using `SchemaLoader` (`capnp/schema-loader.h`) and + use the Dynamic API to manipulate objects of these types. `MessageBuilder` and `MessageReader` + have methods for accessing the message root using a dynamic schema. + +* While `SchemaLoader` loads binary schemas, you can also parse directly from text using + `SchemaParser` (`capnp/schema-parser.h`). However, this requires linking against `libcapnpc` + (in addition to `libcapnp` and `libkj`) -- this code is bulky and not terribly efficient. If + you can arrange to use only binary schemas at runtime, you'll be better off. + +* Unlike with Protobufs, there is no "global registry" of compiled-in types. To get the schema + for a compiled-in type, use `capnp::Schema::from()`. + +* Unlike with Protobufs, the overhead of supporting reflection is small. Generated `.capnp.c++` + files contain only some embedded const data structures describing the schema, no code at all, + and the runtime library support code is relatively small. Moreover, if you do not use the + dynamic API or the schema API, you do not even need to link their implementations into your + executable. + +* The dynamic API performs type checks at runtime. In case of error, it will throw an exception. + If you compile with `-fno-exceptions`, it will crash instead. Correct usage of the API should + never throw, but bugs happen. Enabling and catching exceptions will make your code more robust. + +* Loading user-provided schemas has security implications: it greatly increases the attack + surface of the Cap'n Proto library. In particular, it is easy for an attacker to trigger + exceptions. To protect yourself, you are strongly advised to enable exceptions and catch them. + +## Orphans + +An "orphan" is a Cap'n Proto object that is disconnected from the message structure. That is, +it is not the root of a message, and there is no other Cap'n Proto object holding a pointer to it. +Thus, it has no parents. Orphans are an advanced feature that can help avoid copies and make it +easier to use Cap'n Proto objects as part of your application's internal state. Typical +applications probably won't use orphans. + +The class `capnp::Orphan` (defined in ``) represents a pointer to an orphaned +object of type `T`. `T` can be any struct type, `List`, `Text`, or `Data`. E.g. +`capnp::Orphan` would be an orphaned `Person` structure. `Orphan` is a move-only class, +similar to `std::unique_ptr`. This prevents two different objects from adopting the same +orphan, which would result in an invalid message. + +An orphan can be "adopted" by another object to link it into the message structure. Conversely, +an object can "disown" one of its pointers, causing the pointed-to object to become an orphan. +Every pointer-typed field `foo` provides builder methods `adoptFoo()` and `disownFoo()` for these +purposes. Again, these methods use C++11 move semantics. To use them, you will need to be +familiar with `std::move()` (or the equivalent but shorter-named `kj::mv()`). + +Even though an orphan is unlinked from the message tree, it still resides inside memory allocated +for a particular message (i.e. a particular `MessageBuilder`). An orphan can only be adopted by +objects that live in the same message. To move objects between messages, you must perform a copy. +If the message is serialized while an `Orphan` living within it still exists, the orphan's +content will be part of the serialized message, but the only way the receiver could find it is by +investigating the raw message; the Cap'n Proto API provides no way to detect or read it. + +To construct an orphan from scratch (without having some other object disown it), you need an +`Orphanage`, which is essentially an orphan factory associated with some message. You can get one +by calling the `MessageBuilder`'s `getOrphanage()` method, or by calling the static method +`Orphanage::getForMessageContaining(builder)` and passing it any struct or list builder. + +Note that when an `Orphan` goes out-of-scope without being adopted, the underlying memory that +it occupied is overwritten with zeros. If you use packed serialization, these zeros will take very +little bandwidth on the wire, but will still waste memory on the sending and receiving ends. +Generally, you should avoid allocating message objects that won't be used, or if you cannot avoid +it, arrange to copy the entire message over to a new `MessageBuilder` before serializing, since +only the reachable objects will be copied. + +## Reference + +The runtime library contains lots of useful features not described on this page. For now, the +best reference is the header files. See: + + capnp/list.h + capnp/blob.h + capnp/message.h + capnp/serialize.h + capnp/serialize-packed.h + capnp/schema.h + capnp/schema-loader.h + capnp/dynamic.h + +## Tips and Best Practices + +Here are some tips for using the C++ Cap'n Proto runtime most effectively: + +* Accessor methods for primitive (non-pointer) fields are fast and inline. They should be just + as fast as accessing a struct field through a pointer. + +* Accessor methods for pointer fields, on the other hand, are not inline, as they need to validate + the pointer. If you intend to access the same pointer multiple times, it is a good idea to + save the value to a local variable to avoid repeating this work. This is generally not a + problem given C++11's `auto`. + + Example: + + // BAD + frob(foo.getBar().getBaz(), + foo.getBar().getQux(), + foo.getBar().getCorge()); + + // GOOD + auto bar = foo.getBar(); + frob(bar.getBaz(), bar.getQux(), bar.getCorge()); + + It is especially important to use this style when reading messages, for another reason: as + described under the "security tips" section, below, every time you `get` a pointer, Cap'n Proto + increments a counter by the size of the target object. If that counter hits a pre-defined limit, + an exception is thrown (or a default value is returned, if exceptions are disabled), to prevent + a malicious client from sending your server into an infinite loop with a specially-crafted + message. If you repeatedly `get` the same object, you are repeatedly counting the same bytes, + and so you may hit the limit prematurely. (Since Cap'n Proto readers are backed directly by + the underlying message buffer and do not have anywhere else to store per-object information, it + is impossible to remember whether you've seen a particular object already.) + +* Internally, all pointer fields start out "null", even if they have default values. When you have + a pointer field `foo` and you call `getFoo()` on the containing struct's `Reader`, if the field + is "null", you will receive a reader for that field's default value. This reader is backed by + read-only memory; nothing is allocated. However, when you call `get` on a _builder_, and the + field is null, then the implementation must make a _copy_ of the default value to return to you. + Thus, you've caused the field to become non-null, just by "reading" it. On the other hand, if + you call `init` on that field, you are explicitly replacing whatever value is already there + (null or not) with a newly-allocated instance, and that newly-allocated instance is _not_ a + copy of the field's default value, but just a completely-uninitialized instance of the + appropriate type. + +* It is possible to receive a struct value constructed from a newer version of the protocol than + the one your binary was built with, and that struct might have extra fields that you don't know + about. The Cap'n Proto implementation tries to avoid discarding this extra data. If you copy + the struct from one message to another (e.g. by calling a set() method on a parent object), the + extra fields will be preserved. This makes it possible to build proxies that receive messages + and forward them on without having to rebuild the proxy every time a new field is added. You + must be careful, however: in some cases, it's not possible to retain the extra fields, because + they need to be copied into a space that is allocated before the expected content is known. + In particular, lists of structs are represented as a flat array, not as an array of pointers. + Therefore, all memory for all structs in the list must be allocated upfront. Hence, copying + a struct value from another message into an element of a list will truncate the value. Because + of this, the setter method for struct lists is called `setWithCaveats()` rather than just `set()`. + +* Messages are built in "arena" or "region" style: each object is allocated sequentially in + memory, until there is no more room in the segment, in which case a new segment is allocated, + and objects continue to be allocated sequentially in that segment. This design is what makes + Cap'n Proto possible at all, and it is very fast compared to other allocation strategies. + However, it has the disadvantage that if you allocate an object and then discard it, that memory + is lost. In fact, the empty space will still become part of the serialized message, even though + it is unreachable. The implementation will try to zero it out, so at least it should pack well, + but it's still better to avoid this situation. Some ways that this can happen include: + * If you `init` a field that is already initialized, the previous value is discarded. + * If you create an orphan that is never adopted into the message tree. + * If you use `adoptWithCaveats` to adopt an orphaned struct into a struct list, then a shallow + copy is necessary, since the struct list requires that its elements are sequential in memory. + The previous copy of the struct is discarded (although child objects are transferred properly). + * If you copy a struct value from another message using a `set` method, the copy will have the + same size as the original. However, the original could have been built with an older version + of the protocol which lacked some fields compared to the version your program was built with. + If you subsequently `get` that struct, the implementation will be forced to allocate a new + (shallow) copy which is large enough to hold all known fields, and the old copy will be + discarded. Child objects will be transferred over without being copied -- though they might + suffer from the same problem if you `get` them later on. + Sometimes, avoiding these problems is too inconvenient. Fortunately, it's also possible to + clean up the mess after-the-fact: if you copy the whole message tree into a fresh + `MessageBuilder`, only the reachable objects will be copied, leaving out all of the unreachable + dead space. + + In the future, Cap'n Proto may be improved such that it can re-use dead space in a message. + However, this will only improve things, not fix them entirely: fragementation could still leave + dead space. + +### Build Tips + +* If you are worried about the binary footprint of the Cap'n Proto library, consider statically + linking with the `--gc-sections` linker flag. This will allow the linker to drop pieces of the + library that you do not actually use. For example, many users do not use the dynamic schema and + reflection APIs, which contribute a large fraction of the Cap'n Proto library's overall + footprint. Keep in mind that if you ever stringify a Cap'n Proto type, the stringification code + depends on the dynamic API; consider only using stringification in debug builds. + + If you are dynamically linking against the system's shared copy of `libcapnp`, don't worry about + its binary size. Remember that only the code which you actually use will be paged into RAM, and + those pages are shared with other applications on the system. + + Also remember to strip your binary. In particular, `libcapnpc` (the schema parser) has + excessively large symbol names caused by its use of template-based parser combinators. Stripping + the binary greatly reduces its size. + +* The Cap'n Proto library has lots of debug-only asserts that are removed if you `#define NDEBUG`, + including in headers. If you care at all about performance, you should compile your production + binaries with the `-DNDEBUG` compiler flag. In fact, if Cap'n Proto detects that you have + optimization enabled but have not defined `NDEBUG`, it will define it for you (with a warning), + unless you define `DEBUG` or `KJ_DEBUG` to explicitly request debugging. + +### Security Tips + +Cap'n Proto has not yet undergone security review. It most likely has some vulnerabilities. You +should not attempt to decode Cap'n Proto messages from sources you don't trust at this time. + +However, assuming the Cap'n Proto implementation hardens up eventually, then the following security +tips will apply. + +* It is highly recommended that you enable exceptions. When compiled with `-fno-exceptions`, + Cap'n Proto categorizes exceptions into "fatal" and "recoverable" varieties. Fatal exceptions + cause the server to crash, while recoverable exceptions are handled by logging an error and + returning a "safe" garbage value. Fatal is preferred in cases where it's unclear what kind of + garbage value would constitute "safe". The more of the library you use, the higher the chance + that you will leave yourself open to the possibility that an attacker could trigger a fatal + exception somewhere. If you enable exceptions, then you can catch the exception instead of + crashing, and return an error just to the attacker rather than to everyone using your server. + + Basic parsing of Cap'n Proto messages shouldn't ever trigger fatal exceptions (assuming the + implementation is not buggy). However, the dynamic API -- especially if you are loading schemas + controlled by the attacker -- is much more exception-happy. If you cannot use exceptions, then + you are advised to avoid the dynamic API when dealing with untrusted data. + +* If you need to process schemas from untrusted sources, take them in binary format, not text. + The text parser is a much larger attack surface and not designed to be secure. For instance, + as of this writing, it is trivial to deadlock the parser by simply writing a constant whose value + depends on itself. + +* Cap'n Proto automatically applies two artificial limits on messages for security reasons: + a limit on nesting dept, and a limit on total bytes traversed. + + * The nesting depth limit is designed to prevent stack overflow when handling a deeply-nested + recursive type, and defaults to 64. If your types aren't recursive, it is highly unlikely + that you would ever hit this limit, and even if they are recursive, it's still unlikely. + + * The traversal limit is designed to defend against maliciously-crafted messages which use + pointer cycles or overlapping objects to make a message appear much larger than it looks off + the wire. While cycles and overlapping objects are illegal, they are hard to detect reliably. + Instead, Cap'n Proto places a limit on how many bytes worth of objects you can _dereference_ + before it throws an exception. This limit is assessed every time you follow a pointer. By + default, the limit is 64MiB (this may change in the future). `StreamFdMessageReader` will + actually reject upfront any message which is larger than the traversal limit, even before you + start reading it. + + If you need to write your code in such a way that you might frequently re-read the same + pointers, instead of increasing the traversal limit to the point where it is no longer useful, + consider simply copying the message into a new `MallocMessageBuilder` before starting. Then, + the traversal limit will be enforced only during the copy. There is no traversal limit on + objects once they live in a `MessageBuilder`, even if you use `.asReader()` to convert a + particular object's builder to the corresponding reader type. + + Both limits may be increased using `capnp::ReaderOptions`, defined in `capnp/message.h`. + +* Remember that enums on the wire may have a numeric value that does not match any value defined + in the schema. Your `switch()` statements must always have a safe default case. + +## Lessons Learned from Protocol Buffers + +The author of Cap'n Proto's C++ implementation also wrote (in the past) verison 2 of Google's +Protocol Buffers. As a result, Cap'n Proto's implementation benefits from a number of lessons +learned the hard way: + +* Protobuf generated code is enormous due to the parsing and serializing code generated for every + class. This actually poses a significant problem in practice -- there exist server binaries + containing literally hundreds of megabytes of compiled protobuf code. Cap'n Proto generated code, + on the other hand, is almost entirely inlined accessors. The only things that go into `.capnp.o` + files are default values for pointer fields (if needed, which is rare) and the encoded schema + (just the raw bytes of a Cap'n-Proto-encoded schema structure). The latter could even be removed + if you don't use dynamic reflection. + +* The C++ Protobuf implementation used lots of dynamic initialization code (that runs before + `main()`) to do things like register types in global tables. This proved problematic for + programs which linked in lots of protocols but needed to start up quickly. Cap'n Proto does not + use any dynamic initializers anywhere, period. + +* The C++ Protobuf implementation makes heavy use of STL in its interface and implementation. + The proliferation of template instantiations gives the Protobuf runtime library a large footprint, + and using STL in the interface can lead to weird ABI problems and slow compiles. Cap'n Proto + does not use any STL containers in its interface and makes sparing use in its implementation. + As a result, the Cap'n Proto runtime library is smaller, and code that uses it compiles quickly. + +* The in-memory representation of messages in Protobuf-C++ involves many heap objects. Each + message (struct) is an object, each non-primitive repeated field allocates an array of pointers + to more objects, and each string may actually add two heap objects. Cap'n Proto by its nature + uses arena allocation, so the entire message is allocated in a few contiguous segments. This + means Cap'n Proto spends very little time allocating memory, stores messages more compactly, and + avoids memory fragmentation. + +* Related to the last point, Protobuf-C++ relies heavily on object reuse for performance. + Building or parsing into a newly-allocated Protobuf object is significantly slower than using + an existing one. However, the memory usage of a Protobuf object will tend to grow the more times + it is reused, particularly if it is used to parse messages of many different "shapes", so the + objects need to be deleted and re-allocated from time to time. All this makes tuning Protobufs + fairly tedious. In contrast, enabling memory reuse with Cap'n Proto is as simple as providing + a byte buffer to use as scratch space when you build or read in a message. Provide enough scratch + space to hold the entire message and Cap'n Proto won't allocate any memory. Or don't -- since + Cap'n Proto doesn't do much allocation in the first place, the benefits of scratch space are + small. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/cxxrpc.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/cxxrpc.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,442 @@ +--- +layout: page +title: C++ RPC +--- + +# C++ RPC + +The Cap'n Proto C++ RPC layer sits on top of the [serialization layer](cxx.html) and implements +the [RPC protocol](rpc.html). + +## Current Status + +As of version 0.4, Cap'n Proto's C++ RPC implementation is a [Level 1](rpc.html#protocol-features) +implementation. Persistent capabilities, three-way introductions, and distributed equality are +not yet implemented. + +## Sample Code + +The [Calculator example](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples) implements +a fully-functional Cap'n Proto client and server. + +## KJ Concurrency Framework + +RPC naturally requires a notion of concurrency. Unfortunately, +[all concurrency models suck](https://plus.google.com/u/0/+KentonVarda/posts/D95XKtB5DhK). + +Cap'n Proto's RPC is based on the [KJ library](cxx.html#kj-library)'s event-driven concurrency +framework. The core of the KJ asynchronous framework (events, promises, callbacks) is defined in +`kj/async.h`, with I/O interfaces (streams, sockets, networks) defined in `kj/async-io.h`. + +### Event Loop Concurrency + +KJ's concurrency model is based on event loops. While multiple threads are allowed, each thread +must have its own event loop. KJ discourages fine-grained interaction between threads as +synchronization is expensive and error-prone. Instead, threads are encouraged to communicate +through Cap'n Proto RPC. + +KJ's event loop model bears a lot of similarity to the Javascript concurrency model. Experienced +Javascript hackers -- especially node.js hackers -- will feel right at home. + +_As of version 0.4, the only supported way to communicate between threads is over pipes or +socketpairs. This will be improved in future versions. For now, just set up an RPC connection +over that socketpair. :)_ + +### Promises + +Function calls that do I/O must do so asynchronously, and must return a "promise" for the +result. Promises -- also known as "futures" in some systems -- are placeholders for the results +of operations that have not yet completed. When the operation completes, we say that the promise +"resolves" to a value, or is "fulfilled". A promise can also be "rejected", which means an +exception occurred. + +{% highlight c++ %} +// Example promise-based interfaces. + +kj::Promise fetchHttp(kj::StringPtr url); +// Asynchronously fetches an HTTP document and returns +// the content as a string. + +kj::Promise sendEmail(kj::StringPtr address, + kj::StringPtr title, kj::StringPtr body); +// Sends an e-mail to the given address with the given title +// and body. The returned promise resolves (to nothing) when +// the message has been successfully sent. +{% endhighlight %} + +As you will see, KJ promises are very similar to the evolving Javascript promise standard, and +much of the [wisdom around it](https://www.google.com/search?q=javascript+promises) can be directly +applied to KJ promises. + +### Callbacks + +If you want to do something with the result of a promise, you must first wait for it to complete. +This is normally done by registering a callback to execute on completion. Luckily, C++11 just +introduced lambdas, which makes this far more pleasant than it would have been a few years ago! + +{% highlight c++ %} +kj::Promise contentPromise = + fetchHttp("http://example.com"); + +kj::Promise lineCountPromise = + contentPromise.then([](kj::String&& content) { + return countChars(content, '\n'); +}); +{% endhighlight %} + +The callback passed to `then()` takes the promised result as its parameter and returns a new value. +`then()` itself returns a new promise for that value which the callback will eventually return. +If the callback itself returns a promise, then `then()` actually returns a promise for the +resolution of the latter promise -- that is, `Promise>` is automatically reduced to +`Promise`. + +Note that `then()` consumes the original promise: you can only call `then()` once. This is true +of all of the methods of `Promise`. The only way to consume a promise in multiple places is to +first "fork" it with the `fork()` method, which we don't get into here. Relatedly, promises +are linear types, which means they have move constructors but not copy constructors. + +### Error Propagation + +`then()` takes an optional second parameter for handling errors. Think of this like a `catch` +block. + +{% highlight c++ %} +kj::Promise lineCountPromise = + promise.then([](kj::String&& content) { + return countChars(content, '\n'); +}, [](kj::Exception&& exception) { + // Error! Pretend the document was empty. + return 0; +}); +{% endhighlight %} + +Note that the KJ framework coerces all exceptions to `kj::Exception` -- the exception's description +(as returned by `what()`) will be retained, but any type-specific information is lost. Under KJ +exception philosophy, exceptions always represent an error that should not occur under normal +operation, and the only purpose of exceptions is to make software fault-tolerant. In particular, +the only reasonable ways to handle an exception are to try again, tell a human, and/or propagate +to the caller. To that end, `kj::Exception` contains information useful for reporting purposes +and to help decide if trying again is reasonable, but typed exception hierarchies are not useful +and not supported. + +It is recommended that Cap'n Proto code use the assertion macros in `kj/debug.h` to throw +exceptions rather than use the C++ `throw` keyword. These macros make it easy to add useful +debug information to an exception and generally play nicely with the KJ framework. In fact, you +can even use these macros -- and propagate exceptions through promises -- if you compile your code +with exceptions disabled. See the headers for more information. + +### Waiting + +It is illegal for code running in an event callback to wait, since this would stall the event loop. +However, if you are the one responsible for starting the event loop in the first place, then KJ +makes it easy to say "run the event loop until this promise resolves, then return the result". + +{% highlight c++ %} +kj::EventLoop loop; +kj::WaitScope waitScope(loop); + +kj::Promise contentPromise = + fetchHttp("http://example.com"); + +kj::String content = contentPromise.wait(waitScope); + +int lineCount = countChars(content, '\n'); +{% endhighlight %} + +Using `wait()` is common in high-level client-side code. On the other hand, it is almost never +used in servers. + +### Cancellation + +If you discard a `Promise` without calling any of its methods, the operation it was waiting for +is canceled, because the `Promise` itself owns that operation. This means than any pending +callbacks simply won't be executed. If you need explicit notification when a promise is canceled, +you can use its `attach()` method to attach an object with a destructor -- the destructor will be +called when the promise either completes or is canceled. + +### Lazy Execution + +Callbacks registered with `.then()` which aren't themselves asynchronous (i.e. they return a value, +not a promise) by default won't execute unless the result is actually used -- they are executed +"lazily". This allows the runtime to optimize by combining a series of .then() callbacks into one. + +To force a `.then()` callback to execute as soon as its input is available, do one of the +following: + +* Add it to a `kj::TaskSet` -- this is usually the best choice. You can cancel all tasks in the set + by destroying the `TaskSet`. +* `.wait()` on it -- but this only works in a top-level wait scope, typically your program's main + function. +* Call `.eagerlyEvaluate()` on it. This returns a new `Promise`. You can cancel the task by + destroying this `Promise` (without otherwise consuming it). +* `.detach()` it. **WARNING:** `.detach()` is dangerous because there is no way to cancel a promise + once it has been detached. This can make it impossible to safely tear down the execution + environment, e.g. if the callback has captured references to other objects. It is therefore + recommended to avoid `.detach()` except in carefully-controlled circumstances. + +### Other Features + +KJ supports a number of primitive operations that can be performed on promises. The complete API +is documented directly in the `kj/async.h` header. Additionally, see the `kj/async-io.h` header +for APIs for performing basic network I/O -- although Cap'n Proto RPC users typically won't need +to use these APIs directly. + +## Generated Code + +Imagine the following interface: + +{% highlight capnp %} +interface Directory { + create @0 (name :Text) -> (file :File); + open @1 (name :Text) -> (file :File); + remove @2 (name :Text); +} +{% endhighlight %} + +`capnp compile` will generate code that looks like this (edited for readability): + +{% highlight c++ %} +struct Directory { + Directory() = delete; + + class Client; + class Server; + + struct CreateParams; + struct CreateResults; + struct OpenParams; + struct OpenResults; + struct RemoveParams; + struct RemoveResults; + // Each of these is equivalent to what would be generated for + // a Cap'n Proto struct with one field for each parameter / + // result. +}; + +class Directory::Client + : public virtual capnp::Capability::Client { +public: + Client(std::nullptr_t); + Client(kj::Own server); + Client(kj::Promise promise); + Client(kj::Exception exception); + + capnp::Request createRequest(); + capnp::Request openRequest(); + capnp::Request removeRequest(); +}; + +class Directory::Server + : public virtual capnp::Capability::Server { +protected: + typedef capnp::CallContext CreateContext; + typedef capnp::CallContext OpenContext; + typedef capnp::CallContext RemoveContext; + // Convenience typedefs. + + virtual kj::Promise create(CreateContext context); + virtual kj::Promise open(OpenContext context); + virtual kj::Promise remove(RemoveContext context); + // Methods for you to implement. +}; +{% endhighlight %} + +### Clients + +The generated `Client` type represents a reference to a remote `Server`. `Client`s are +pass-by-value types that use reference counting under the hood. (Warning: For performance +reasons, the reference counting used by `Client`s is not thread-safe, so you must not copy a +`Client` to another thread, unless you do it by means of an inter-thread RPC.) + +A `Client` can be implicitly constructed from any of: + +* A `kj::Own`, which takes ownership of the server object and creates a client that + calls it. (You can get a `kj::Own` to a newly-allocated heap object using + `kj::heap(constructorParams)`; see `kj/memory.h`.) +* A `kj::Promise`, which creates a client whose methods first wait for the promise to + resolve, then forward the call to the resulting client. +* A `kj::Exception`, which creates a client whose methods always throw that exception. +* `nullptr`, which creates a client whose methods always throw. This is meant to be used to + initialize variables that will be initialized to a real value later on. + +For each interface method `foo()`, the `Client` has a method `fooRequest()` which creates a new +request to call `foo()`. The returned `capnp::Request` object has methods equivalent to a +`Builder` for the parameter struct (`FooParams`), with the addition of a method `send()`. +`send()` sends the RPC and returns a `capnp::RemotePromise`. + +This `RemotePromise` is equivalent to `kj::Promise>`, but also has +methods that allow pipelining. Namely: + +* For each interface-typed result, it has a getter method which returns a `Client` of that type. + Calling this client will send a pipelined call to the server. +* For each struct-typed result, it has a getter method which returns an object containing pipeline + getters for that struct's fields. + +In other words, the `RemotePromise` effectively implements a subset of the eventual results' +`Reader` interface -- one that only allows access to interfaces and sub-structs. + +The `RemotePromise` eventually resolves to `capnp::Response`, which behaves like a +`Reader` for the result struct except that it also owns the result message. + +{% highlight c++ %} +Directory::Client dir = ...; + +// Create a new request for the `open()` method. +auto request = dir.openRequest(); +request.setName("foo"); + +// Send the request. +auto promise = request.send(); + +// Make a pipelined request. +auto promise2 = promise.getFile().getSizeRequest().send(); + +// Wait for the full results. +auto promise3 = promise2.then( + [](capnp::Response&& response) { + cout << "File size is: " << response.getSize() << endl; +}); +{% endhighlight %} + +For [generic methods](language.html#generic-methods), the `fooRequest()` method will be a template; +you must explicitly specify type parameters. + +### Servers + +The generated `Server` type is an abstract interface which may be subclassed to implement a +capability. Each method takes a `context` argument and returns a `kj::Promise` which +resolves when the call is finished. The parameter and result structures are accessed through the +context -- `context.getParams()` returns a `Reader` for the parameters, and `context.getResults()` +returns a `Builder` for the results. The context also has methods for controlling RPC logistics, +such as cancellation -- see `capnp::CallContext` in `capnp/capability.h` for details. + +Accessing the results through the context (rather than by returning them) is unintuitive, but +necessary because the underlying RPC transport needs to have control over where the results are +allocated. For example, a zero-copy shared memory transport would need to allocate the results in +the shared memory segment. Hence, the method implementation cannot just create its own +`MessageBuilder`. + +{% highlight c++ %} +class DirectoryImpl final: public Directory::Server { +public: + kj::Promise open(OpenContext context) override { + auto iter = files.find(context.getParams().getName()); + + // Throw an exception if not found. + KJ_REQUIRE(iter != files.end(), "File not found."); + + context.getResults().setFile(iter->second); + + return kj::READY_NOW; + } + + // Any method which we don't implement will simply throw + // an exception by default. + +private: + std::map files; +}; +{% endhighlight %} + +On the server side, [generic methods](language.html#generic-methods) are NOT templates. Instead, +the generated code is exactly as if all of the generic parameters were bound to `AnyPointer`. The +server generally does not get to know exactly what type the client requested; it must be designed +to be correct for any parameterization. + +## Initializing RPC + +Cap'n Proto makes it easy to start up an RPC client or server using the "EZ RPC" classes, +defined in `capnp/ez-rpc.h`. These classes get you up and running quickly, but they hide a lot +of details that power users will likely want to manipulate. Check out the comments in `ez-rpc.h` +to understand exactly what you get and what you miss. For the purpose of this overview, we'll +show you how to use EZ RPC to get started. + +### Starting a client + +A client should typically look like this: + +{% highlight c++ %} +#include +#include "my-interface.capnp.h" +#include + +int main(int argc, const char* argv[]) { + // We expect one argument specifying the server address. + if (argc != 2) { + std::cerr << "usage: " << argv[0] << " HOST[:PORT]" << std::endl; + return 1; + } + + // Set up the EzRpcClient, connecting to the server on port + // 5923 unless a different port was specified by the user. + capnp::EzRpcClient client(argv[1], 5923); + auto& waitScope = client.getWaitScope(); + + // Request the bootstrap capability from the server. + MyInterface::Client cap = client.getMain(); + + // Make a call to the capability. + auto request = cap.fooRequest(); + request.setParam(123); + auto promise = request.send(); + + // Wait for the result. This is the only line that blocks. + auto response = promise.wait(waitScope); + + // All done. + std::cout << response.getResult() << std::endl; + return 0; +} +{% endhighlight %} + +Note that for the connect address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6 +addresses. Additionally, a Unix domain socket can be specified as `unix:` followed by a path name. + +For a more complete example, see the +[calculator client sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-client.c++). + +### Starting a server + +A server might look something like this: + +{% highlight c++ %} +#include +#include "my-interface-impl.h" +#include + +int main(int argc, const char* argv[]) { + // We expect one argument specifying the address to which + // to bind and accept connections. + if (argc != 2) { + std::cerr << "usage: " << argv[0] << " ADDRESS[:PORT]" + << std::endl; + return 1; + } + + // Set up the EzRpcServer, binding to port 5923 unless a + // different port was specified by the user. Note that the + // first parameter here can be any "Client" object or anything + // that can implicitly cast to a "Client" object. You can even + // re-export a capability imported from another server. + capnp::EzRpcServer server(kj::heap(), argv[1], 5923); + auto& waitScope = server.getWaitScope(); + + // Run forever, accepting connections and handling requests. + kj::NEVER_DONE.wait(waitScope); +} +{% endhighlight %} + +Note that for the bind address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6 +addresses. The special address `*` can be used to bind to the same port on all local IPv4 and +IPv6 interfaces. Additionally, a Unix domain socket can be specified as `unix:` followed by a +path name. + +For a more complete example, see the +[calculator server sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-server.c++). + +## Debugging + +If you've written a server and you want to connect to it to issue some calls for debugging, perhaps +interactively, the easiest way to do it is to use [pycapnp](http://jparyani.github.io/pycapnp/). +We have decided not to add RPC functionality to the `capnp` command-line tool because pycapnp is +better than anything we might provide. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/encoding.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/encoding.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,400 @@ +--- +layout: page +title: Encoding Spec +--- + +# Encoding Spec + +## Organization + +### 64-bit Words + +For the purpose of Cap'n Proto, a "word" is defined as 8 bytes, or 64 bits. Since alignment of +data is important, all objects (structs, lists, and blobs) are aligned to word boundaries, and +sizes are usually expressed in terms of words. (Primitive values are aligned to a multiple of +their size within a struct or list.) + +### Messages + +The unit of communication in Cap'n Proto is a "message". A message is a tree of objects, with +the root always being a struct. + +Physically, messages may be split into several "segments", each of which is a flat blob of bytes. +Typically, a segment must be loaded into a contiguous block of memory before it can be accessed, +so that the relative pointers within the segment can be followed quickly. However, when a message +has multiple segments, it does not matter where those segments are located in memory relative to +each other; inter-segment pointers are encoded differently, as we'll see later. + +Ideally, every message would have only one segment. However, there are a few reasons why splitting +a message into multiple segments may be convenient: + +* It can be difficult to predict how large a message might be until you start writing it, and you + can't start writing it until you have a segment to write to. If it turns out the segment you + allocated isn't big enough, you can allocate additional segments without the need to relocate the + data you've already written. +* Allocating excessively large blocks of memory can make life difficult for memory allocators, + especially on 32-bit systems with limited address space. + +The first word of the first segment of the message is always a pointer pointing to the message's +root struct. + +### Objects + +Each segment in a message contains a series of objects. For the purpose of Cap'n Proto, an "object" +is any value which may have a pointer pointing to it. Pointers can only point to the beginning of +objects, not into the middle, and no more than one pointer can point at each object. Thus, objects +and the pointers connecting them form a tree, not a graph. An object is itself composed of +primitive data values and pointers, in a layout that depends on the kind of object. + +At the moment, there are three kinds of objects: structs, lists, and far-pointer landing pads. +Blobs might also be considered to be a kind of object, but are encoded identically to lists of +bytes. + +## Value Encoding + +### Primitive Values + +The built-in primitive types are encoded as follows: + +* `Void`: Not encoded at all. It has only one possible value thus carries no information. +* `Bool`: One bit. 1 = true, 0 = false. +* Integers: Encoded in little-endian format. Signed integers use two's complement. +* Floating-points: Encoded in little-endian IEEE-754 format. + +Primitive types must always be aligned to a multiple of their size. Note that since the size of +a `Bool` is one bit, this means eight `Bool` values can be encoded in a single byte -- this differs +from C++, where the `bool` type takes a whole byte. + +### Enums + +Enums are encoded the same as `UInt16`. + +## Object Encoding + +### Blobs + +The built-in blob types are encoded as follows: + +* `Data`: Encoded as a pointer, identical to `List(UInt8)`. +* `Text`: Like `Data`, but the content must be valid UTF-8, and the last byte of the content must + be zero. The encoding allows bytes other than the last to be zero, but some applications + (especially ones written in languages that use NUL-terminated strings) may truncate at the first + zero. If a particular text field is explicitly intended to support zero bytes, it should + document this, but otherwise senders should assume that zero bytes are not allowed to be safe. + Note that the NUL terminator is included in the size sent on the wire, but the runtime library + should not count it in any size reported to the application. + +### Structs + +A struct value is encoded as a pointer to its content. The content is split into two sections: +data and pointers, with the pointer section appearing immediately after the data section. This +split allows structs to be traversed (e.g., copied) without knowing their type. + +A struct pointer looks like this: + + lsb struct pointer msb + +-+-----------------------------+---------------+---------------+ + |A| B | C | D | + +-+-----------------------------+---------------+---------------+ + + A (2 bits) = 0, to indicate that this is a struct pointer. + B (30 bits) = Offset, in words, from the end of the pointer to the + start of the struct's data section. Signed. + C (16 bits) = Size of the struct's data section, in words. + D (16 bits) = Size of the struct's pointer section, in words. + +Fields are positioned within the struct according to an algorithm with the following principles: + +* The position of each field depends only on its definition and the definitions of lower-numbered + fields, never on the definitions of higher-numbered fields. This ensures backwards-compatibility + when new fields are added. +* Due to alignment requirements, fields in the data section may be separated by padding. However, + later-numbered fields may be positioned into the padding left between earlier-numbered fields. + Because of this, a struct will never contain more than 63 bits of padding. Since objects are + rounded up to a whole number of words anyway, padding never ends up wasting space. +* Unions and groups need not occupy contiguous memory. Indeed, they may have to be split into + multiple slots if new fields are added later on. + +Field offsets are computed by the Cap'n Proto compiler. The precise algorithm is too complicated +to describe here, but you need not implement it yourself, as the compiler can produce a compiled +schema format which includes offset information. + +### Lists + +A list value is encoded as a pointer to a flat array of values. + + lsb list pointer msb + +-+-----------------------------+--+----------------------------+ + |A| B |C | D | + +-+-----------------------------+--+----------------------------+ + + A (2 bits) = 1, to indicate that this is a list pointer. + B (30 bits) = Offset, in words, from the end of the pointer to the + start of the first element of the list. Signed. + C (3 bits) = Size of each element: + 0 = 0 (e.g. List(Void)) + 1 = 1 bit + 2 = 1 byte + 3 = 2 bytes + 4 = 4 bytes + 5 = 8 bytes (non-pointer) + 6 = 8 bytes (pointer) + 7 = composite (see below) + D (29 bits) = Number of elements in the list, except when C is 7 + (see below). + +The pointed-to values are tightly-packed. In particular, `Bool`s are packed bit-by-bit in +little-endian order (the first bit is the least-significant bit of the first byte). + +When C = 7, the elements of the list are fixed-width composite values -- usually, structs. In +this case, the list content is prefixed by a "tag" word that describes each individual element. +The tag has the same layout as a struct pointer, except that the pointer offset (B) instead +indicates the number of elements in the list. Meanwhile, section (D) of the list pointer -- which +normally would store this element count -- instead stores the total number of _words_ in the list +(not counting the tag word). The reason we store a word count in the pointer rather than an element +count is to ensure that the extents of the list's location can always be determined by inspecting +the pointer alone, without having to look at the tag; this may allow more-efficient prefetching in +some use cases. The reason we don't store struct lists as a list of pointers is because doing so +would take significantly more space (an extra pointer per element) and may be less cache-friendly. + +In the future, we could consider implementing matrixes using the "composite" element type, with the +elements being fixed-size lists rather than structs. In this case, the tag would look like a list +pointer rather than a struct pointer. As of this writing, no such feature has been implemented. + +A struct list must always be written using C = 7. However, a list of any element size (except +C = 1, i.e. 1-bit) may be *decoded* as a struct list, with each element being interpreted as being +a prefix of the struct data. For instance, a list of 2-byte values (C = 3) can be decoded as a +struct list where each struct has 2 bytes in their "data" section (and an empty pointer section). A +list of pointer values (C = 6) can be decoded as a struct list where each struct has a pointer +section with one pointer (and an empty data section). The purpose of this rule is to make it +possible to upgrade a list of primitives to a list of structs, as described under the +[protocol evolution rules](language.html#evolving-your-protocol). +(We make a special exception that boolean lists cannot be upgraded in this way due to the +unreasonable implementation burden.) Note that even though struct lists can be decoded from any +element size (except C = 1), it is NOT permitted to encode a struct list using any type other than +C = 7 because doing so would interfere with the [canonicalization algorithm](#canonicalization). + +#### Default Values + +A default struct is always all-zeros. To achieve this, fields in the data section are stored xor'd +with their defined default values. An all-zero pointer is considered "null" (such a pointer would +otherwise point to a zero-size struct, which might as well be considered null); accessor methods +for pointer fields check for null and return a pointer to their default value in this case. + +There are several reasons why this is desirable: + +* Cap'n Proto messages are often "packed" with a simple compression algorithm that deflates + zero-value bytes. +* Newly-allocated structs only need to be zero-initialized, which is fast and requires no knowledge + of the struct type except its size. +* If a newly-added field is placed in space that was previously padding, messages written by old + binaries that do not know about this field will still have its default value set correctly -- + because it is always zero. + +### Inter-Segment Pointers + +When a pointer needs to point to a different segment, offsets no longer work. We instead encode +the pointer as a "far pointer", which looks like this: + + lsb far pointer msb + +-+-+---------------------------+-------------------------------+ + |A|B| C | D | + +-+-+---------------------------+-------------------------------+ + + A (2 bits) = 2, to indicate that this is a far pointer. + B (1 bit) = 0 if the landing pad is one word, 1 if it is two words. + See explanation below. + C (29 bits) = Offset, in words, from the start of the target segment + to the location of the far-pointer landing-pad within that + segment. Unsigned. + D (32 bits) = ID of the target segment. (Segments are numbered + sequentially starting from zero.) + +If B == 0, then the "landing pad" of a far pointer is normally just another pointer, which in turn +points to the actual object. + +If B == 1, then the "landing pad" is itself another far pointer that is interpreted differently: +This far pointer (which always has B = 0) points to the start of the object's _content_, located in +some other segment. The landing pad is itself immediately followed by a tag word. The tag word +looks exactly like an intra-segment pointer to the target object would look, except that the offset +is always zero. + +The reason for the convoluted double-far convention is to make it possible to form a new pointer +to an object in a segment that is full. If you can't allocate even one word in the segment where +the target resides, then you will need to allocate a landing pad in some other segment, and use +this double-far approach. This should be exceedingly rare in practice since pointers are normally +set to point to new objects, not existing ones. + +### Capabilities (Interfaces) + +When using Cap'n Proto for [RPC](rpc.html), every message has an associated "capability table" +which is a flat list of all capabilities present in the message body. The details of what this +table contains and where it is stored are the responsibility of the RPC system; in some cases, the +table may not even be part of the message content. + +A capability pointer, then, simply contains an index into the separate capability table. + + lsb capability pointer msb + +-+-----------------------------+-------------------------------+ + |A| B | C | + +-+-----------------------------+-------------------------------+ + + A (2 bits) = 3, to indicate that this is an "other" pointer. + B (30 bits) = 0, to indicate that this is a capability pointer. + (All other values are reserved for future use.) + C (32 bits) = Index of the capability in the message's capability + table. + +In [rpc.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c++/src/capnp/rpc.capnp), the +capability table is encoded as a list of `CapDescriptors`, appearing along-side the message content +in the `Payload` struct. However, some use cases may call for different approaches. A message +that is built and consumed within the same process need not encode the capability table at all +(it can just keep the table as a separate array). A message that is going to be stored to disk +would need to store a table of `SturdyRef`s instead of `CapDescriptor`s. + +## Serialization Over a Stream + +When transmitting a message, the segments must be framed in some way, i.e. to communicate the +number of segments and their sizes before communicating the actual data. The best framing approach +may differ depending on the medium -- for example, messages read via `mmap` or shared memory may +call for a different approach than messages sent over a socket or a pipe. Cap'n Proto does not +attempt to specify a framing format for every situation. However, since byte streams are by far +the most common transmission medium, Cap'n Proto does define and implement a recommended framing +format for them. + +When transmitting over a stream, the following should be sent. All integers are unsigned and +little-endian. + +* (4 bytes) The number of segments, minus one (since there is always at least one segment). +* (N * 4 bytes) The size of each segment, in words. +* (0 or 4 bytes) Padding up to the next word boundary. +* The content of each segment, in order. + +### Packing + +For cases where bandwidth usage matters, Cap'n Proto defines a simple compression scheme called +"packing". This scheme is based on the observation that Cap'n Proto messages contain lots of +zero bytes: padding bytes, unset fields, and high-order bytes of small-valued integers. + +In packed format, each word of the message is reduced to a tag byte followed by zero to eight +content bytes. The bits of the tag byte correspond to the bytes of the unpacked word, with the +least-significant bit corresponding to the first byte. Each zero bit indicates that the +corresponding byte is zero. The non-zero bytes are packed following the tag. + +For example, here is some typical Cap'n Proto data (a struct pointer (offset = 2, data size = 3, +pointer count = 2) followed by a text pointer (offset = 6, length = 53)) and its packed form: + + unpacked (hex): 08 00 00 00 03 00 02 00 19 00 00 00 aa 01 00 00 + packed (hex): 51 08 03 02 31 19 aa 01 + +In addition to the above, there are two tag values which are treated specially: 0x00 and 0xff. + +* 0x00: The tag is followed by a single byte which indicates a count of consecutive zero-valued + words, minus 1. E.g. if the tag 0x00 is followed by 0x05, the sequence unpacks to 6 words of + zero. + + Or, put another way: the tag is first decoded as if it were not special. Since none of the bits + are set, it is followed by no bytes and expands to a word full of zeros. After that, the next + byte is interpreted as a count of _additional_ words that are also all-zero. + +* 0xff: The tag is followed by the bytes of the word (as if it weren't special), but after those + bytes is another byte with value N. Following that byte is N unpacked words that should be copied + directly. These unpacked words may or may not contain zeros -- it is up to the compressor to + decide when to end the unpacked span and return to packing each word. The purpose of this rule + is to minimize the impact of packing on data that doesn't contain any zeros -- in particular, + long text blobs. Because of this rule, the worst-case space overhead of packing is 2 bytes per + 2 KiB of input (256 words = 2KiB). + +Examples: + + unpacked (hex): 00 (x 32 bytes) + packed (hex): 00 03 + + unpacked (hex): 8a (x 32 bytes) + packed (hex): ff 8a (x 8 bytes) 03 8a (x 24 bytes) + +Notice that both of the special cases begin by treating the tag as if it weren't special. This +is intentionally designed to make encoding faster: you can compute the tag value and encode the +bytes in a single pass through the input word. Only after you've finished with that word do you +need to check whether the tag ended up being 0x00 or 0xff. + +It is possible to write both an encoder and a decoder which only branch at the end of each word, +and only to handle the two special tags. It is not necessary to branch on every byte. See the +C++ reference implementation for an example. + +Packing is normally applied on top of the standard stream framing described in the previous +section. + +### Compression + +When Cap'n Proto messages may contain repetitive data (especially, large text blobs), it makes sense +to apply a standard compression algorithm in addition to packing. When CPU time is scarce, we +recommend [LZ4 compression](https://code.google.com/p/lz4/). Otherwise, [zlib](http://www.zlib.net) +is slower but will compress more. + +## Canonicalization + +Cap'n Proto messages have a well-defined canonical form. Cap'n Proto encoders are NOT required to +output messages in canonical form, and in fact they will almost never do so by default. However, +it is possible to write code which canonicalizes a Cap'n Proto message without knowing its schema. + +A canonical Cap'n Proto message must adhere to the following rules: + +* The object tree must be encoded in preorder (with respect to the order of the pointers within + each object). +* The message must be encoded as a single segment. (When signing or hashing a canonical Cap'n Proto + message, the segment table shall not be included, because it would be redundant.) +* Trailing zero-valued words in a struct's data or pointer segments must be truncated. Since zero + represents a default value, this does not change the struct's meaning. This rule is important + to ensure that adding a new field to a struct does not affect the canonical encoding of messages + that do not set that field. +* Similarly, for a struct list, if a trailing word in a section of all structs in the list is zero, + then it must be truncated from all structs in the list. (All structs in a struct list must have + equal sizes, hence a trailing zero can only be removed if it is zero in all elements.) +* Canonical messages are not packed. However, packing can still be applied for transmission + purposes; the message must simply be unpacked before checking signatures. + +Note that Cap'n Proto 0.5 introduced the rule that struct lists must always be encoded using +C = 7 in the [list pointer](#lists). Prior versions of Cap'n Proto allowed struct lists to be +encoded using any element size, so that small structs could be compacted to take less than a word +per element, and many encoders in fact implemented this. Unfortunately, this "optimization" made +canonicalization impossible without knowing the schema, which is a significant obstacle. Therefore, +the rules have been changed in 0.5, but data written by previous versions may not be possible to +canonicalize. + +## Security Considerations + +A naive implementation of a Cap'n Proto reader may be vulnerable to attacks based on various kinds +of malicious input. Implementations MUST guard against these. + +### Pointer Validation + +Cap'n Proto readers must validate pointers, e.g. to check that the target object is within the +bounds of its segment. To avoid an upfront scan of the message (which would defeat Cap'n Proto's +O(1) parsing performance), validation should occur lazily when the getter method for a pointer is +called, throwing an exception or returning a default value if the pointer is invalid. + +### Amplification attack + +A message containing cyclic (or even just overlapping) pointers can cause the reader to go into +an infinite loop while traversing the content. + +To defend against this, as the application traverses the message, each time a pointer is +dereferenced, a counter should be incremented by the size of the data to which it points. If this +counter goes over some limit, an error should be raised, and/or default values should be returned. We call this limit the "traversal limit" (or, sometimes, the "read limit"). + +The C++ implementation currently defaults to a limit of 64MiB, but allows the caller to set a +different limit if desired. Another reasonable strategy is to set the limit to some multiple of +the original message size; however, most applications should place limits on overall message sizes +anyway, so it makes sense to have one check cover both. + +**List amplification:** A list of `Void` values or zero-size structs can have a very large element count while taking constant space on the wire. If the receiving application expects a list of structs, it will see these zero-sized elements as valid structs set to their default values. If it iterates through the list processing each element, it could spend a large amount of CPU time or other resources despite the message being small. To defend against this, the "traversal limit" should count a list of zero-sized elements as if each element were one word instead. This rule was introduced in the C++ implementation in [commit 1048706](https://github.com/sandstorm-io/capnproto/commit/104870608fde3c698483fdef6b97f093fc15685d). + +### Stack overflow DoS attack + +A message with deeply-nested objects can cause a stack overflow in typical code which processes +messages recursively. + +To defend against this, as the application traverses the message, the pointer depth should be +tracked. If it goes over some limit, an error should be raised. The C++ implementation currently +defaults to a limit of 64 pointers, but allows the caller to set a different limit. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/faq.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/faq.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,211 @@ +--- +layout: page +title: FAQ +--- + +# FAQ + +## Design + +### Isn't I/O bandwidth more important than CPU usage? Is Cap'n Proto barking up the wrong tree? + +It depends. What is your use case? + +Are you communicating between two processes on the same machine? If so, you have unlimited +bandwidth, and you should be entirely concerned with CPU. + +Are you communicating between two machines within the same datacenter? If so, it's unlikely that +you will saturate your network connection before your CPU. Possible, but unlikely. + +Are you communicating across the general internet? In that case, bandwidth is probably your main +concern. Luckily, Cap'n Proto lets you choose to enable "packing" in this case, achieving similar +encoding size to Protocol Buffers while still being faster. And you can always add extra +compression on top of that. + +### Have you considered building the RPC system on ZeroMQ? + +ZeroMQ (and its successor, Nanomsg) is a powerful technology for distributed computing. Its +design focuses on scenarios involving lots of stateless, fault-tolerant worker processes +communicating via various patterns, such as request/response, produce/consume, and +publish/subscribe. For big data processing where armies of stateless nodes make sense, pairing +Cap'n Proto with ZeroMQ would be an excellent choice -- and this is easy to do today, as ZeroMQ +is entirely serialization-agnostic. + +That said, Cap'n Proto RPC takes a very different approach. Cap'n Proto's model focuses on +stateful servers interacting in complex, object-oriented ways. The model is better suited to +tasks involving applications with many heterogeneous components and interactions between +mutually-distrusting parties. Requests and responses can go in any direction. Objects have +state and so two calls to the same object had best go to the same machine. Load balancing and +fault tolerance is pushed up the stack, because without a large pool of homogeneous work there's +just no way to make them transparent at a low level. + +Put concretely, you might build a search engine indexing pipeline on ZeroMQ, but an online +interactive spreadsheet editor would be better built on Cap'n Proto RPC. + +(Actually, a distributed programming framework providing similar features to ZeroMQ could itself be +built on top of Cap'n Proto RPC.) + +### Aren't messages that contain pointers a huge security problem? + +Not at all. Cap'n Proto bounds-checks each pointer when it is read and throws an exception or +returns a safe dummy value (your choice) if the pointer is out-of-bounds. + +### So it's not that you've eliminated parsing, you've just moved it to happen lazily? + +No. Compared to Protobuf decoding, the time spent validating pointers while traversing a Cap'n +Proto message is negligible. + +### I think I heard somewhere that capability-based security doesn't work? + +This was a popular myth in security circles way back in the 80's and 90's, based on an incomplete +understanding of what capabilities are and how to use them effectively. Read +[Capability Myths Demolished](http://zesty.ca/capmyths/usenix.pdf). (No really, read it; +it's awesome.) + +## Usage + +### How do I make a field "required", like in Protocol Buffers? + +You don't. You may find this surprising, but the "required" keyword in Protocol Buffers turned +out to be a horrible mistake. + +For background, in protocol buffers, a field could be marked "required" to indicate that parsing +should fail if the sender forgot to set the field before sending the message. Required fields were +encoded exactly the same as optional ones; the only difference was the extra validation. + +The problem with this is, validation is sometimes more subtle than that. Sometimes, different +applications -- or different parts of the same application, or different versions of the same +application -- place different requirements on the same protocol. An application may want to +pass around partially-complete messages internally. A particular field that used to be required +might become optional. A new use case might call for almost exactly the same message type, minus +one field, at which point it may make more sense to reuse the type than to define a new one. + +A field declared required, unfortunately, is required everywhere. The validation is baked into +the parser, and there's nothing you can do about it. Nothing, that is, except change the field +from "required" to "optional". But that's where the _real_ problems start. + +Imagine a production environment in which two servers, Alice and Bob, exchange messages through a +message bus infrastructure running on a big corporate network. The message bus parses each message +just to examine the envelope and decide how to route it, without paying attention to any other +content. Often, messages from various applications are batched together and then split up again +downstream. + +Now, at some point, Alice's developers decide that one of the fields in a deeply-nested message +commonly sent to Bob has become obsolete. To clean things up, they decide to remove it, so they +change the field from "required" to "optional". The developers aren't idiots, so they realize that +Bob needs to be updated as well. They make the changes to Bob, and just to be thorough they +run an integration test with Alice and Bob running in a test environment. The test environment +is always running the latest build of the message bus, but that's irrelevant anyway because the +message bus doesn't actually care about message contents; it only does routing. Protocols are +modified all the time without updating the message bus. + +Satisfied with their testing, the devs push a new version of Alice to prod. Immediately, +everything breaks. And by "everything" I don't just mean Alice and Bob. Completely unrelated +servers are getting strange errors or failing to receive messages. The whole data center has +ground to a halt and the sysadmins are running around with their hair on fire. + +What happened? Well, the message bus running in prod was still an older build from before the +protocol change. And even though the message bus doesn't care about message content, it _does_ +need to parse every message just to read the envelope. And the protobuf parser checks the _entire_ +message for missing required fields. So when Alice stopped sending that newly-optional field, the +whole message failed to parse, envelope and all. And to make matters worse, any other messages +that happened to be in the same batch _also_ failed to parse, causing errors in seemingly-unrelated +systems that share the bus. + +Things like this have actually happened. At Google. Many times. + +The right answer is for applications to do validation as-needed in application-level code. If you +want to detect when a client fails to set a particular field, give the field an invalid default +value and then check for that value on the server. Low-level infrastructure that doesn't care +about message content should not validate it at all. + +Oh, and also, Cap'n Proto doesn't have any parsing step during which to check for required +fields. :) + +### How do I make a field optional? + +Cap'n Proto has no notion of "optional" fields. + +A primitive field always takes space on the wire whether you set it or not (although default-valued +fields will be compressed away if you enable packing). Such a field can be made semantically +optional by placing it in a union with a `Void` field: + +{% highlight capnp %} +union { + age @0 :Int32; + ageUnknown @1 :Void; +} +{% endhighlight %} + +However, this field still takes space on the wire, and in fact takes an extra 16 bits of space +for the union tag. A better approach may be to give the field a bogus default value and interpret +that value to mean "not present". + +Pointer fields are a bit different. They start out "null", and you can check for nullness using +the `hasFoo()` accessor. You could use a null pointer to mean "not present". Note, though, that +calling `getFoo()` on a null pointer returns the default value, which is indistinguishable from a +legitimate value, so checking `hasFoo()` is in fact the _only_ way to detect nullness. + +### How do I resize a list? + +Unfortunately, you can't. You have to know the size of your list upfront, before you initialize +any of the elements. This is an annoying side effect of arena allocation, which is a fundamental +part of Cap'n Proto's design: in order to avoid making a copy later, all of the pieces of the +message must be allocated in a tightly-packed segment of memory, with each new piece being added +to the end. If a previously-allocated piece is discarded, it leaves a hole, which wastes space. +Since Cap'n Proto lists are flat arrays, the only way to resize a list would be to discard the +existing list and allocate a new one, which would thus necessarily waste space. + +In theory, a more complicated memory allocation algorithm could attempt to reuse the "holes" left +behind by discarded message pieces. However, it would be hard to make sure any new data inserted +into the space is exactly the right size. Fragmentation would result. And the allocator would +have to do a lot of extra bookkeeping that could be expensive. This would be sad, as arena +allocation is supposed to be cheap! + +The only solution is to temporarily place your data into some other data structure (an +`std::vector`, perhaps) until you know how many elements you have, then allocate the list and copy. +On the bright side, you probably aren't losing much performance this way -- using vectors already +involves making copies every time the backing array grows. It's just annoying to code. + +Keep in mind that you can use [orphans](cxx.html#orphans) to allocate sub-objects before you have +a place to put them. But, also note that you cannot allocate elements of a struct list as orphans +and then put them together as a list later, because struct lists are encoded as a flat array of +struct values, not an array of pointers to struct values. You can, however, allocate any inner +objects embedded within those structs as orphans. + +## Security + +### Is Cap'n Proto secure? + +What is your threat model? + +### Sorry. Can Cap'n Proto be used to deserialize malicious messages? + +Cap'n Proto's serialization layer is designed to be safe against malicious input. The Cap'n Proto implementation should never segfault, corrupt memory, leak secrets, execute attacker-specified code, consume excessive resources, etc. as a result of any sequence of input bytes. Moreover, the API is carefully designed to avoid putting app developers into situations where it is easy to write insecure code -- we consider it a bug in Cap'n Proto if apps commonly misuse it in a way that is a security problem. + +With all that said, Cap'n Proto's C++ reference implementation has not yet undergone a formal security review. It may have bugs. + +### Is it safe to use Cap'n Proto RPC with a malicious peer? + +Cap'n Proto's RPC layer is explicitly designed to be useful for interactions between mutually-distrusting parties. Its capability-based security model makes it easy to express complex interactions securely. + +At this time, the RPC layer is not robust against resource exhaustion attacks, possibly allowing denials of service. + +### Is Cap'n Proto encrypted? + +Cap'n Proto may be layered on top of an existing encrypted transport, such as TLS, but at this time it is the application's responsibility to add this layer. We plan to integrate this into the Cap'n Proto library proper in the future. + +### How do I report security bugs? + +Please email [security@sandstorm.io](mailto:security@sandstorm.io). + +## Sandstorm + +### How does Cap'n Proto relate to Sandstorm.io? + +[Sandstorm.io](https://sandstorm.io) is an Open Source project and startup founded by Kenton, the author of Cap'n Proto. Cap'n Proto is owned and developed by Sandstorm the company and heavily used in Sandstorm the project. + +### How does Sandstorm use Cap'n Proto? + +See [this Sandstorm blog post](https://blog.sandstorm.io/news/2014-12-15-capnproto-0.5.html). + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/feed.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/feed.xml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,22 @@ +--- +layout: none +--- + + + + + Cap'n Proto News + Latest updates on Cap'n Proto + https://capnproto.org + + {% for post in site.posts limit:10 %} + + {{ post.title | xml_escape }} + {{ post.content | xml_escape }} + {{ post.date | date: "%a, %d %b %Y %H:%M:%S %z" }} + {{ site.baseurl }}{{ post.url }} + {{ site.baseurl }}{{ post.url }} + + {% endfor %} + + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/bg_hr.png Binary file src/capnproto-0.6.0/doc/images/bg_hr.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/blacktocat.png Binary file src/capnproto-0.6.0/doc/images/blacktocat.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/capnp-vs-ice.png Binary file src/capnproto-0.6.0/doc/images/capnp-vs-ice.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/capnp-vs-thrift-vs-ice.png Binary file src/capnproto-0.6.0/doc/images/capnp-vs-thrift-vs-ice.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/gittip.png Binary file src/capnproto-0.6.0/doc/images/gittip.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/gittip15.png Binary file src/capnproto-0.6.0/doc/images/gittip15.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/groups-logo.png Binary file src/capnproto-0.6.0/doc/images/groups-logo.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/icon_download.png Binary file src/capnproto-0.6.0/doc/images/icon_download.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/infinitely_faster.png Binary file src/capnproto-0.6.0/doc/images/infinitely_faster.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/infinity-times-faster.png Binary file src/capnproto-0.6.0/doc/images/infinity-times-faster.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/logo.png Binary file src/capnproto-0.6.0/doc/images/logo.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/sprite_download.png Binary file src/capnproto-0.6.0/doc/images/sprite_download.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/time-travel.png Binary file src/capnproto-0.6.0/doc/images/time-travel.png has changed diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/images/twitter.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/images/twitter.svg Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,51 @@ + + +image/svg+xml + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/index.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/index.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,103 @@ +--- +layout: page +title: Introduction +--- + +# Introduction + + + +Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think +JSON, except binary. Or think [Protocol Buffers](http://protobuf.googlecode.com), except faster. +In fact, in benchmarks, Cap'n Proto is INFINITY TIMES faster than Protocol Buffers. + +This benchmark is, of course, unfair. It is only measuring the time to encode and decode a message +in memory. Cap'n Proto gets a perfect score because _there is no encoding/decoding step_. The Cap'n +Proto encoding is appropriate both as a data interchange format and an in-memory representation, so +once your structure is built, you can simply write the bytes straight out to disk! + +**_But doesn't that mean the encoding is platform-specific?_** + +NO! The encoding is defined byte-for-byte independent of any platform. However, it is designed to +be efficiently manipulated on common modern CPUs. Data is arranged like a compiler would arrange a +struct -- with fixed widths, fixed offsets, and proper alignment. Variable-sized elements are +embedded as pointers. Pointers are offset-based rather than absolute so that messages are +position-independent. Integers use little-endian byte order because most CPUs are little-endian, +and even big-endian CPUs usually have instructions for reading little-endian data. + +**_Doesn't that make backwards-compatibility hard?_** + +Not at all! New fields are always added to the end of a struct (or replace padding space), so +existing field positions are unchanged. The recipient simply needs to do a bounds check when +reading each field. Fields are numbered in the order in which they were added, so Cap'n Proto +always knows how to arrange them for backwards-compatibility. + +**_Won't fixed-width integers, unset optional fields, and padding waste space on the wire?_** + +Yes. However, since all these extra bytes are zeros, when bandwidth matters, we can apply an +extremely fast Cap'n-Proto-specific compression scheme to remove them. Cap'n Proto calls this +"packing" the message; it achieves similar (better, even) message sizes to protobuf encoding, and +it's still faster. + +When bandwidth really matters, you should apply general-purpose compression, like +[zlib](http://www.zlib.net/) or [LZ4](https://github.com/Cyan4973/lz4), regardless of your +encoding format. + +**_Isn't this all horribly insecure?_** + +No no no! To be clear, we're NOT just casting a buffer pointer to a struct pointer and calling it a day. + +Cap'n Proto generates classes with accessor methods that you use to traverse the message. These accessors validate pointers before following them. If a pointer is invalid (e.g. out-of-bounds), the library can throw an exception or simply replace the value with a default / empty object (your choice). + +Thus, Cap'n Proto checks the structural integrity of the message just like any other serialization protocol would. And, just like any other protocol, it is up to the app to check the validity of the content. + +Cap'n Proto was built to be used in [Sandstorm.io](https://sandstorm.io), where security is a major concern. As of this writing, Cap'n Proto has not undergone a security review, therefore we suggest caution when handling messages from untrusted sources. That said, our response to security issues was once described by security guru Ben Laurie as ["the most awesome response I've ever had."](https://twitter.com/BenLaurie/status/575079375307153409) (Please report all security issues to [security@sandstorm.io](mailto:security@sandstorm.io).) + +**_Are there other advantages?_** + +Glad you asked! + +* **Incremental reads:** It is easy to start processing a Cap'n Proto message before you have + received all of it since outer objects appear entirely before inner objects (as opposed to most + encodings, where outer objects encompass inner objects). +* **Random access:** You can read just one field of a message without parsing the whole thing. +* **mmap:** Read a large Cap'n Proto file by memory-mapping it. The OS won't even read in the + parts that you don't access. +* **Inter-language communication:** Calling C++ code from, say, Java or Python tends to be painful + or slow. With Cap'n Proto, the two languages can easily operate on the same in-memory data + structure. +* **Inter-process communication:** Multiple processes running on the same machine can share a + Cap'n Proto message via shared memory. No need to pipe data through the kernel. Calling another + process can be just as fast and easy as calling another thread. +* **Arena allocation:** Manipulating Protobuf objects tends to be bogged down by memory + allocation, unless you are very careful about object reuse. Cap'n Proto objects are always + allocated in an "arena" or "region" style, which is faster and promotes cache locality. +* **Tiny generated code:** Protobuf generates dedicated parsing and serialization code for every + message type, and this code tends to be enormous. Cap'n Proto generated code is smaller by an + order of magnitude or more. In fact, usually it's no more than some inline accessor methods! +* **Tiny runtime library:** Due to the simplicity of the Cap'n Proto format, the runtime library + can be much smaller. +* **Time-traveling RPC:** Cap'n Proto features an RPC system that implements [time travel](rpc.html) + such that call results are returned to the client before the request even arrives at the server! + + + + +**_Why do you pick on Protocol Buffers so much?_** + +Because it's easy to pick on myself. :) I, Kenton Varda, was the primary author of Protocol Buffers +version 2, which is the version that Google released open source. Cap'n Proto is the result of +years of experience working on Protobufs, listening to user feedback, and thinking about how +things could be done better. + +Note that I no longer work for Google. Cap'n Proto is not, and never has been, affiliated with Google; in fact, it is a property of [Sandstorm.io](https://sandstorm.io), of which I am co-founder. + +**_OK, how do I get started?_** + +To install Cap'n Proto, head over to the [installation page](install.html). If you'd like to help +hack on Cap'n Proto, such as by writing bindings in other languages, let us know on the +[discussion group](https://groups.google.com/group/capnproto). If you'd like to receive e-mail +updates about future releases, add yourself to the +[announcement list](https://groups.google.com/group/capnproto-announce). + +{% include buttons.html %} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/install.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/install.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,171 @@ +--- +layout: page +title: Installation +--- + +# Installation: Tools and C++ Runtime + +The Cap'n Proto tools, including the compiler (which takes `.capnp` files and generates source code +for them), are written in C++. Therefore, you must install the C++ package even if your actual +development language is something else. + +This package is licensed under the [MIT License](http://opensource.org/licenses/MIT). + +## Caveats + +

Cap'n Proto is in BETA

+ + + +As of this writing, Cap'n Proto is in beta. The serialization layer is close to feature-complete +and we don't anticipate any further changes to the wire format. That said, if you want to use it, +you should keep in mind some caveats: + +* **Security:** Cap'n Proto has not yet had a security review. Although Kenton has a background + in security and is not aware of any vulnerabilities in the current code, it's likely that there + are a few, and [some have been found](https://github.com/sandstorm-io/capnproto/tree/master/security-advisories) + in the past. For now, do not accept Cap'n Proto messages from parties you do not trust. +* **API Stability:** The Cap'n Proto programming interface may still change in ways that break + existing code. Such changes are likely to be minor and should not affect the wire format. +* **Performance:** While Cap'n Proto is inherently fast by design, the implementation has not yet + undergone serious profiling and optimization. Currently it only beats Protobufs in realistic-ish + end-to-end benchmarks by around 2x-5x. We can do better. +* **RPC:** The RPC implementation particularly experimental, though it is used heavily by + [Sandstorm.io](https://sandstorm.io). + +If you'd like to hack on Cap'n Proto, you should join the +[discussion group](https://groups.google.com/group/capnproto)! + +If you'd just like to receive updates as things progress, add yourself to the +[announce list](https://groups.google.com/group/capnproto-announce). + +## Prerequisites + +### Supported Compilers + +Cap'n Proto makes extensive use of C++11 language features. As a result, it requires a relatively +new version of a well-supported compiler. The minimum versions are: + +* GCC 4.8 +* Clang 3.3 +* Visual C++ 2015 + +If your system's default compiler is older that the above, you will need to install a newer +compiler and set the `CXX` environment variable before trying to build Cap'n Proto. For example, +after installing GCC 4.8, you could set `CXX=g++-4.8` to use this compiler. + +### Supported Operating Systems + +In theory, Cap'n Proto should work on any POSIX platform supporting one of the above compilers, +as well as on Windows. We test every Cap'n Proto release on the following platforms: + +* Android +* Linux +* Mac OS X +* Windows - Cygwin +* Windows - MinGW-w64 +* Windows - Visual C++ + +**Windows users:** Cap'n Proto requires Visual Studio 2015 Update 3 or newer. All runtime features +of Cap'n Proto -- including serialization and RPC -- are now supported. (It is still not possible to +compile the code generator tool, capnp.exe, using Visual Studio; however, a precompiled copy built +with MinGW is provided in the release zip for your convenience.) + +**Mac OS X users:** You must use at least Xcode 5 with the Xcode command-line +tools (Xcode menu > Preferences > Downloads). Alternatively, the command-line tools +package from [Apple](https://developer.apple.com/downloads/) or compiler builds from +[Macports](http://www.macports.org/), [Fink](http://www.finkproject.org/), or +[Homebrew](http://brew.sh/) are reported to work. + +## Installation: Unix + +**From Release Tarball** + +You may download and install the release version of Cap'n Proto like so: + +
curl -O https://capnproto.org/capnproto-c++-0.6.0.tar.gz
+tar zxf capnproto-c++-0.6.0.tar.gz
+cd capnproto-c++-0.6.0
+./configure
+make -j6 check
+sudo make install
+ +This will install `capnp`, the Cap'n Proto command-line tool. It will also install `libcapnp`, +`libcapnpc`, and `libkj` in `/usr/local/lib` and headers in `/usr/local/include/capnp` and +`/usr/local/include/kj`. + +**From Package Managers** + +Some package managers include Cap'n Proto packages. + +Note: These packages are not maintained by us and are sometimes not up to date with the latest Cap'n Proto release. + +* Debian / Ubuntu: `apt-get install capnproto` +* Homebrew (OSX): `brew install capnp` + +**From Git** + +If you download directly from Git, you will need to have the GNU autotools -- +[autoconf](http://www.gnu.org/software/autoconf/), +[automake](http://www.gnu.org/software/automake/), and +[libtool](http://www.gnu.org/software/libtool/) -- installed. + + git clone https://github.com/sandstorm-io/capnproto.git + cd capnproto/c++ + autoreconf -i + ./configure + make -j6 check + sudo make install + +## Installation: Windows + +**From Release Zip** + +1. Download Cap'n Proto Win32 build: + +
https://capnproto.org/capnproto-c++-win32-0.6.0.zip
+ +2. Find `capnp.exe`, `capnpc-c++.exe`, and `capnpc-capnp.exe` under `capnproto-tools-win32-0.6.0` in + the zip and copy them somewhere. + +If you don't care about C++ support, you can stop here. The compiler exe can be used with plugins +provided by projects implementing Cap'n Proto in other languages. + +If you want to use Cap'n Proto in C++ with Visual Studio, do the following: + +1. Make sure that you are using Visual Studio 2015 or newer, with all updates installed. Cap'n + Proto uses C++11 language features that did not work in previous versions of Visual Studio, + and the updates include many bug fixes that Cap'n Proto requires. + +2. Install [CMake](http://www.cmake.org/) version 3.1 or later. + +3. Use CMake to generate Visual Studio project files under `capnproto-c++-0.6.0` in the zip file. + You can use the CMake UI for this or run this shell command: + + cmake -G "Visual Studio 14 2015" + + (For VS2017, you can use "Visual Studio 15 2017" as the generator name.) + +3. Open the "Cap'n Proto" solution in Visual Studio. + +4. Adjust the project build options (e.g., choice of C++ runtime library, enable/disable exceptions + and RTTI) to match the options of the project in which you plan to use Cap'n Proto. + +5. Build the solution (`ALL_BUILD`). + +6. Build the `INSTALL` project to copy the compiled libraries, tools, and header files into + `CMAKE_INSTALL_PREFIX`. + + Alternatively, find the compiled `.lib` files in the build directory under + `src/{capnp,kj}/{Debug,Release}` and place them somewhere where your project can link against them. + Also add the `src` directory to your search path for `#include`s, or copy all the headers to your + project's include directory. + +Cap'n Proto can also be built with MinGW or Cygwin, using the Unix/autotools build instructions. + +**From Git** + +The C++ sources are located under `c++` directory in the git repository. The build instructions are +otherwise the same as for the release zip. + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/javascripts/main.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/javascripts/main.js Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,133 @@ +function initSidebar() { + var filename = document.location.pathname; + + if (filename.slice(0, 5) == "/next") { + filename = filename.slice(5); + } + + if (filename == "/") { + filename = "/index.html"; + } else if (filename.slice(0, 6) == "/news/") { + filename = "/news/"; + } + + var menu = document.getElementById("menu"); + var setMenuLayout = function() { + if (window.innerWidth < 900) { + document.body.className = "narrow"; + menu.className = ""; + } else { + if (document.body.clientWidth < 1340) { + document.body.className = "normal"; + } else { + document.body.className = "wide"; + } + + var y = (window.pageYOffset !== undefined) ? window.pageYOffset : + (document.documentElement || document.body.parentNode || document.body).scrollTop; + + if (y < 444 || window.innerHeight < menu.clientHeight + 100) { + menu.className = ""; + } else { + menu.className = "floating"; + } + } + }; + setMenuLayout(); + window.onresize = setMenuLayout; + window.onscroll = setMenuLayout; + + var items = menu.getElementsByTagName("li"); + var toc = null; + for (var i = 0; i < items.length; i++) { + var link = items[i].getElementsByTagName("a")[0]; + var href = link.href; + if (href.lastIndexOf(filename) >= 0) { + var parent = link.parentNode; + + while (link.childNodes.length > 0) { + var child = link.childNodes[0]; + link.removeChild(child); + parent.appendChild(child); + } + parent.removeChild(link); + items[i].className = "selected"; + toc = document.createElement("ul"); + toc.id = "toc"; + items[i].appendChild(toc); + } + } + + document.getElementById("main_content").style.minHeight = menu.clientHeight + 100 + "px"; + + return toc; +} + +function setupSidebar() { + var filename = document.location.pathname; + + if (filename.slice(0, 5) == "/next") { + filename = filename.slice(5); + } + + var isNews = filename.slice(0, 6) == "/news/"; + + var toc = initSidebar(); + if (toc) { + var content = document.getElementById("main_content").childNodes; + var headings = []; + + for (var i = 0; i < content.length; i++) { + if (content[i].tagName == "H2" || + (!isNews && (content[i].tagName == "H3" || content[i].tagName == "H4"))) { + headings.push(content[i]); + } + } + + var levels = [toc]; + for (var i in headings) { + var hl = headings[i].tagName.slice(1) - 1; + while (hl > levels.length) { + var parent = levels[levels.length - 1]; + var item = parent.childNodes[parent.childNodes.length - 1]; + var sublist = document.createElement("ul"); + item.appendChild(sublist); + levels.push(sublist); + } + while (hl < levels.length) { + levels.pop(); + } + + var parent = levels[levels.length - 1]; + var item = document.createElement("li"); + var p = document.createElement("p"); + var link = document.createElement("a"); + p.appendChild(document.createTextNode(headings[i].innerText || headings[i].textContent)); + var hlinks = headings[i].getElementsByTagName("a"); + if (hlinks.length == 1) { + link.href = hlinks[0].href; + } else { + link.href = "#" + headings[i].id; + } + link.appendChild(p); + item.appendChild(link); + parent.appendChild(item); + } + } +} + +function setupNewsSidebar(items) { + var toc = initSidebar(); + if (toc) { + for (var i in items) { + var item = document.createElement("li"); + var p = document.createElement("p"); + var link = document.createElement("a"); + p.appendChild(document.createTextNode(items[i].title)); + link.href = items[i].url; + link.appendChild(p); + item.appendChild(link); + toc.appendChild(item); + } + } +} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/language.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/language.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,788 @@ +--- +layout: page +title: Schema Language +--- + +# Schema Language + +Like Protocol Buffers and Thrift (but unlike JSON or MessagePack), Cap'n Proto messages are +strongly-typed and not self-describing. You must define your message structure in a special +language, then invoke the Cap'n Proto compiler (`capnp compile`) to generate source code to +manipulate that message type in your desired language. + +For example: + +{% highlight capnp %} +@0xdbb9ad1f14bf0b36; # unique file ID, generated by `capnp id` + +struct Person { + name @0 :Text; + birthdate @3 :Date; + + email @1 :Text; + phones @2 :List(PhoneNumber); + + struct PhoneNumber { + number @0 :Text; + type @1 :Type; + + enum Type { + mobile @0; + home @1; + work @2; + } + } +} + +struct Date { + year @0 :Int16; + month @1 :UInt8; + day @2 :UInt8; +} +{% endhighlight %} + +Some notes: + +* Types come after names. The name is by far the most important thing to see, especially when + quickly skimming, so we put it up front where it is most visible. Sorry, C got it wrong. +* The `@N` annotations show how the protocol evolved over time, so that the system can make sure + to maintain compatibility with older versions. Fields (and enumerants, and interface methods) + must be numbered consecutively starting from zero in the order in which they were added. In this + example, it looks like the `birthdate` field was added to the `Person` structure recently -- its + number is higher than the `email` and `phones` fields. Unlike Protobufs, you cannot skip numbers + when defining fields -- but there was never any reason to do so anyway. + +## Language Reference + +### Comments + +Comments are indicated by hash signs and extend to the end of the line: + +{% highlight capnp %} +# This is a comment. +{% endhighlight %} + +Comments meant as documentation should appear _after_ the declaration, either on the same line, or +on a subsequent line. Doc comments for aggregate definitions should appear on the line after the +opening brace. + +{% highlight capnp %} +struct Date { + # A standard Gregorian calendar date. + + year @0 :Int16; + # The year. Must include the century. + # Negative value indicates BC. + + month @1 :UInt8; # Month number, 1-12. + day @2 :UInt8; # Day number, 1-30. +} +{% endhighlight %} + +Placing the comment _after_ the declaration rather than before makes the code more readable, +especially when doc comments grow long. You almost always need to see the declaration before you +can start reading the comment. + +### Built-in Types + +The following types are automatically defined: + +* **Void:** `Void` +* **Boolean:** `Bool` +* **Integers:** `Int8`, `Int16`, `Int32`, `Int64` +* **Unsigned integers:** `UInt8`, `UInt16`, `UInt32`, `UInt64` +* **Floating-point:** `Float32`, `Float64` +* **Blobs:** `Text`, `Data` +* **Lists:** `List(T)` + +Notes: + +* The `Void` type has exactly one possible value, and thus can be encoded in zero bits. It is + rarely used, but can be useful as a union member. +* `Text` is always UTF-8 encoded and NUL-terminated. +* `Data` is a completely arbitrary sequence of bytes. +* `List` is a parameterized type, where the parameter is the element type. For example, + `List(Int32)`, `List(Person)`, and `List(List(Text))` are all valid. + +### Structs + +A struct has a set of named, typed fields, numbered consecutively starting from zero. + +{% highlight capnp %} +struct Person { + name @0 :Text; + email @1 :Text; +} +{% endhighlight %} + +Fields can have default values: + +{% highlight capnp %} +foo @0 :Int32 = 123; +bar @1 :Text = "blah"; +baz @2 :List(Bool) = [ true, false, false, true ]; +qux @3 :Person = (name = "Bob", email = "bob@example.com"); +corge @4 :Void = void; +grault @5 :Data = 0x"a1 40 33"; +{% endhighlight %} + +### Unions + +A union is two or more fields of a struct which are stored in the same location. Only one of +these fields can be set at a time, and a separate tag is maintained to track which one is +currently set. Unlike in C, unions are not types, they are simply properties of fields, therefore +union declarations do not look like types. + +{% highlight capnp %} +struct Person { + # ... + + employment :union { + unemployed @4 :Void; + employer @5 :Company; + school @6 :School; + selfEmployed @7 :Void; + # We assume that a person is only one of these. + } +} +{% endhighlight %} + +Additionally, unions can be unnamed. Each struct can contain no more than one unnamed union. Use +unnamed unions in cases where you would struggle to think of an appropriate name for the union, +because the union represents the main body of the struct. + +{% highlight capnp %} +struct Shape { + area @0 :Float64; + + union { + circle @1 :Float64; # radius + square @2 :Float64; # width + } +} +{% endhighlight %} + +Notes: + +* Unions members are numbered in the same number space as fields of the containing struct. + Remember that the purpose of the numbers is to indicate the evolution order of the + struct. The system needs to know when the union fields were declared relative to the non-union + fields. + +* Notice that we used the "useless" `Void` type here. We don't have any extra information to store + for the `unemployed` or `selfEmployed` cases, but we still want the union to distinguish these + states from others. + +* By default, when a struct is initialized, the lowest-numbered field in the union is "set". If + you do not want any field set by default, simply declare a field called "unset" and make it the + lowest-numbered field. + +* You can move an existing field into a new union without breaking compatibility with existing + data, as long as all of the other fields in the union are new. Since the existing field is + necessarily the lowest-numbered in the union, it will be the union's default field. + +**Wait, why aren't unions first-class types?** + +Requiring unions to be declared inside a struct, rather than living as free-standing types, has +some important advantages: + +* If unions were first-class types, then union members would clearly have to be numbered separately + from the containing type's fields. This means that the compiler, when deciding how to position + the union in its containing struct, would have to conservatively assume that any kind of new + field might be added to the union in the future. To support this, all unions would have to + be allocated as separate objects embedded by pointer, wasting space. + +* A free-standing union would be a liability for protocol evolution, because no additional data + can be attached to it later on. Consider, for example, a type which represents a parser token. + This type is naturally a union: it may be a keyword, identifier, numeric literal, quoted string, + etc. So the author defines it as a union, and the type is used widely. Later on, the developer + wants to attach information to the token indicating its line and column number in the source + file. Unfortunately, this is impossible without updating all users of the type, because the new + information ought to apply to _all_ token instances, not just specific members of the union. On + the other hand, if unions must be embedded within structs, it is always possible to add new + fields to the struct later on. + +* When evolving a protocol it is common to discover that some existing field really should have + been enclosed in a union, because new fields being added are mutually exclusive with it. With + Cap'n Proto's unions, it is actually possible to "retroactively unionize" such a field without + changing its layout. This allows you to continue being able to read old data without wasting + space when writing new data. This is only possible when unions are declared within their + containing struct. + +Cap'n Proto's unconventional approach to unions provides these advantages without any real down +side: where you would conventionally define a free-standing union type, in Cap'n Proto you +may simply define a struct type that contains only that union (probably unnamed), and you have +achieved the same effect. Thus, aside from being slightly unintuitive, it is strictly superior. + +### Groups + +A group is a set of fields that are encapsulated in their own scope. + +{% highlight capnp %} +struct Person { + # ... + + # Note: This is a terrible way to use groups, and meant + # only to demonstrate the syntax. + address :group { + houseNumber @8 :UInt32; + street @9 :Text; + city @10 :Text; + country @11 :Text; + } +} +{% endhighlight %} + +Interface-wise, the above group behaves as if you had defined a nested struct called `Address` and +then a field `address :Address`. However, a group is _not_ a separate object from its containing +struct: the fields are numbered in the same space as the containing struct's fields, and are laid +out exactly the same as if they hadn't been grouped at all. Essentially, a group is just a +namespace. + +Groups on their own (as in the above example) are useless, almost as much so as the `Void` type. +They become interesting when used together with unions. + +{% highlight capnp %} +struct Shape { + area @0 :Float64; + + union { + circle :group { + radius @1 :Float64; + } + rectangle :group { + width @2 :Float64; + height @3 :Float64; + } + } +} +{% endhighlight %} + +There are two main reason to use groups with unions: + +1. They are often more self-documenting. Notice that `radius` is now a member of `circle`, so + we don't need a comment to explain that the value of `circle` is its radius. +2. You can add additional members later on, without breaking compatibility. Notice how we upgraded + `square` to `rectangle` above, adding a `height` field. This definition is actually + wire-compatible with the previous version of the `Shape` example from the "union" section + (aside from the fact that `height` will always be zero when reading old data -- hey, it's not + a perfect example). In real-world use, it is common to realize after the fact that you need to + add some information to a struct that only applies when one particular union field is set. + Without the ability to upgrade to a group, you would have to define the new field separately, + and have it waste space when not relevant. + +Note that a named union is actually exactly equivalent to a named group containing an unnamed +union. + +**Wait, weren't groups considered a misfeature in Protobufs? Why did you do this again?** + +They are useful in unions, which Protobufs did not have. Meanwhile, you cannot have a "repeated +group" in Cap'n Proto, which was the case that got into the most trouble with Protobufs. + +### Dynamically-typed Fields + +A struct may have a field with type `AnyPointer`. This field's value can be of any pointer type -- +i.e. any struct, interface, list, or blob. This is essentially like a `void*` in C. + +See also [generics](#generic-types). + +### Enums + +An enum is a type with a small finite set of symbolic values. + +{% highlight capnp %} +enum Rfc3092Variable { + foo @0; + bar @1; + baz @2; + qux @3; + # ... +} +{% endhighlight %} + +Like fields, enumerants must be numbered sequentially starting from zero. In languages where +enums have numeric values, these numbers will be used, but in general Cap'n Proto enums should not +be considered numeric. + +### Interfaces + +An interface has a collection of methods, each of which takes some parameters and return some +results. Like struct fields, methods are numbered. Interfaces support inheritance, including +multiple inheritance. + +{% highlight capnp %} +interface Node { + isDirectory @0 () -> (result :Bool); +} + +interface Directory extends(Node) { + list @0 () -> (list :List(Entry)); + struct Entry { + name @0 :Text; + node @1 :Node; + } + + create @1 (name :Text) -> (file :File); + mkdir @2 (name :Text) -> (directory :Directory); + open @3 (name :Text) -> (node :Node); + delete @4 (name :Text); + link @5 (name :Text, node :Node); +} + +interface File extends(Node) { + size @0 () -> (size :UInt64); + read @1 (startAt :UInt64 = 0, amount :UInt64 = 0xffffffffffffffff) + -> (data :Data); + # Default params = read entire file. + + write @2 (startAt :UInt64, data :Data); + truncate @3 (size :UInt64); +} +{% endhighlight %} + +Notice something interesting here: `Node`, `Directory`, and `File` are interfaces, but several +methods take these types as parameters or return them as results. `Directory.Entry` is a struct, +but it contains a `Node`, which is an interface. Structs (and primitive types) are passed over RPC +by value, but interfaces are passed by reference. So when `Directory.list` is called remotely, the +content of a `List(Entry)` (including the text of each `name`) is transmitted back, but for the +`node` field, only a reference to some remote `Node` object is sent. + +When an address of an object is transmitted, the RPC system automatically manages making sure that +the recipient gets permission to call the addressed object -- because if the recipient wasn't +meant to have access, the sender shouldn't have sent the reference in the first place. This makes +it very easy to develop secure protocols with Cap'n Proto -- you almost don't need to think about +access control at all. This feature is what makes Cap'n Proto a "capability-based" RPC system -- a +reference to an object inherently represents a "capability" to access it. + +### Generic Types + +A struct or interface type may be parameterized, making it "generic". For example, this is useful +for defining type-safe containers: + +{% highlight capnp %} +struct Map(Key, Value) { + entries @0 :List(Entry); + struct Entry { + key @0 :Key; + value @1 :Value; + } +} + +struct People { + byName @0 :Map(Text, Person); + # Maps names to Person instances. +} +{% endhighlight %} + +Cap'n Proto generics work very similarly to Java generics or C++ templates. Some notes: + +* Only pointer types (structs, lists, blobs, and interfaces) can be used as generic parameters, + much like in Java. This is a pragmatic limitation: allowing parameters to have non-pointer types + would mean that different parameterizations of a struct could have completely different layouts, + which would excessively complicate the Cap'n Proto implementation. + +* A type declaration nested inside a generic type may use the type parameters of the outer type, + as you can see in the example above. This differs from Java, but matches C++. If you want to + refer to a nested type from outside the outer type, you must specify the parameters on the outer + type, not the inner. For example, `Map(Text, Person).Entry` is a valid type; + `Map.Entry(Text, Person)` is NOT valid. (Of course, an inner type may declare additional generic + parameters.) + +* If you refer to a generic type but omit its parameters (e.g. declare a field of type `Map` rather + than `Map(T, U)`), it is as if you specified `AnyPointer` for each parameter. Note that such + a type is wire-compatible with any specific parameterization, so long as you interpret the + `AnyPointer`s as the correct type at runtime. + +* Relatedly, it is safe to cast an generic interface of a specific parameterization to a generic + interface where all parameters are `AnyPointer` and vice versa, as long as the `AnyPointer`s are + treated as the correct type at runtime. This means that e.g. you can implement a server in a + generic way that is correct for all parameterizations but call it from clients using a specific + parameterization. + +* The encoding of a generic type is exactly the same as the encoding of a type produced by + substituting the type parameters manually. For example, `Map(Text, Person)` is encoded exactly + the same as: + +
{% highlight capnp %} + struct PersonMap { + # Encoded the same as Map(Text, Person). + entries @0 :List(Entry); + struct Entry { + key @0 :Text; + value @1 :Person; + } + } + {% endhighlight %} +
+ + Therefore, it is possible to upgrade non-generic types to generic types while retaining + backwards-compatibility. + +* Similarly, a generic interface's protocol is exactly the same as the interface obtained by + manually substituting the generic parameters. + +### Generic Methods + +Interface methods may also have "implicit" generic parameters that apply to a particular method +call. This commonly applies to "factory" methods. For example: + +{% highlight capnp %} +interface Assignable(T) { + # A generic interface, with non-generic methods. + get @0 () -> (value :T); + set @1 (value :T) -> (); +} + +interface AssignableFactory { + newAssignable @0 [T] (initialValue :T) + -> (assignable :Assignable(T)); + # A generic method. +} +{% endhighlight %} + +Here, the method `newAssignable()` is generic. The return type of the method depends on the input +type. + +Ideally, calls to a generic method should not have to explicitly specify the method's type +parameters, because they should be inferred from the types of the method's regular parameters. +However, this may not always be possible; it depends on the programming language and API details. + +Note that if a method's generic parameter is used only in its returns, not its parameters, then +this implies that the returned value is appropriate for any parameterization. For example: + +{% highlight capnp %} +newUnsetAssignable @1 [T] () -> (assignable :Assignable(T)); +# Create a new assignable. `get()` on the returned object will +# throw an exception until `set()` has been called at least once. +{% endhighlight %} + +Because of the way this method is designed, the returned `Assignable` is initially valid for any +`T`. Effectively, it doesn't take on a type until the first time `set()` is called, and then `T` +retroactively becomes the type of value passed to `set()`. + +In contrast, if it's the case that the returned type is unknown, then you should NOT declare it +as generic. Instead, use `AnyPointer`, or omit a type's parameters (since they default to +`AnyPointer`). For example: + +{% highlight capnp %} +getNamedAssignable @2 (name :Text) -> (assignable :Assignable); +# Get the `Assignable` with the given name. It is the +# responsibility of the caller to keep track of the type of each +# named `Assignable` and cast the returned object appropriately. +{% endhighlight %} + +Here, we omitted the parameters to `Assignable` in the return type, because the returned object +has a specific type parameterization but it is not locally knowable. + +### Constants + +You can define constants in Cap'n Proto. These don't affect what is sent on the wire, but they +will be included in the generated code, and can be [evaluated using the `capnp` +tool](capnp-tool.html#evaluating-constants). + +{% highlight capnp %} +const pi :Float32 = 3.14159; +const bob :Person = (name = "Bob", email = "bob@example.com"); +const secret :Data = 0x"9f98739c2b53835e 6720a00907abd42f"; +{% endhighlight %} + +Additionally, you may refer to a constant inside another value (e.g. another constant, or a default +value of a field). + +{% highlight capnp %} +const foo :Int32 = 123; +const bar :Text = "Hello"; +const baz :SomeStruct = (id = .foo, message = .bar); +{% endhighlight %} + +Note that when substituting a constant into another value, the constant's name must be qualified +with its scope. E.g. if a constant `qux` is declared nested in a type `Corge`, it would need to +be referenced as `Corge.qux` rather than just `qux`, even when used within the `Corge` scope. +Constants declared at the top-level scope are prefixed just with `.`. This rule helps to make it +clear that the name refers to a user-defined constant, rather than a literal value (like `true` or +`inf`) or an enum value. + +### Nesting, Scope, and Aliases + +You can nest constant, alias, and type definitions inside structs and interfaces (but not enums). +This has no effect on any definition involved except to define the scope of its name. So in Java +terms, inner classes are always "static". To name a nested type from another scope, separate the +path with `.`s. + +{% highlight capnp %} +struct Foo { + struct Bar { + #... + } + bar @0 :Bar; +} + +struct Baz { + bar @0 :Foo.Bar; +} +{% endhighlight %} + +If typing long scopes becomes cumbersome, you can use `using` to declare an alias. + +{% highlight capnp %} +struct Qux { + using Foo.Bar; + bar @0 :Bar; +} + +struct Corge { + using T = Foo.Bar; + bar @0 :T; +} +{% endhighlight %} + +### Imports + +An `import` expression names the scope of some other file: + +{% highlight capnp %} +struct Foo { + # Use type "Baz" defined in bar.capnp. + baz @0 :import "bar.capnp".Baz; +} +{% endhighlight %} + +Of course, typically it's more readable to define an alias: + +{% highlight capnp %} +using Bar = import "bar.capnp"; + +struct Foo { + # Use type "Baz" defined in bar.capnp. + baz @0 :Bar.Baz; +} +{% endhighlight %} + +Or even: + +{% highlight capnp %} +using import "bar.capnp".Baz; + +struct Foo { + baz @0 :Baz; +} +{% endhighlight %} + +The above imports specify relative paths. If the path begins with a `/`, it is absolute -- in +this case, the `capnp` tool searches for the file in each of the search path directories specified +with `-I`. + +### Annotations + +Sometimes you want to attach extra information to parts of your protocol that isn't part of the +Cap'n Proto language. This information might control details of a particular code generator, or +you might even read it at run time to assist in some kind of dynamic message processing. For +example, you might create a field annotation which means "hide from the public", and when you send +a message to an external user, you might invoke some code first that iterates over your message and +removes all of these hidden fields. + +You may declare annotations and use them like so: + +{% highlight capnp %} +# Declare an annotation 'foo' which applies to struct and enum types. +annotation foo(struct, enum) :Text; + +# Apply 'foo' to to MyType. +struct MyType $foo("bar") { + # ... +} +{% endhighlight %} + +The possible targets for an annotation are: `file`, `struct`, `field`, `union`, `enum`, `enumerant`, +`interface`, `method`, `parameter`, `annotation`, `const`. You may also specify `*` to cover them +all. + +{% highlight capnp %} +# 'baz' can annotate anything! +annotation baz(*) :Int32; + +$baz(1); # Annotate the file. + +struct MyStruct $baz(2) { + myField @0 :Text = "default" $baz(3); + myUnion :union $baz(4) { + # ... + } +} + +enum MyEnum $baz(5) { + myEnumerant @0 $baz(6); +} + +interface MyInterface $baz(7) { + myMethod @0 (myParam :Text $baz(9)) -> () $baz(8); +} + +annotation myAnnotation(struct) :Int32 $baz(10); +const myConst :Int32 = 123 $baz(11); +{% endhighlight %} + +`Void` annotations can omit the value. Struct-typed annotations are also allowed. Tip: If +you want an annotation to have a default value, declare it as a struct with a single field with +a default value. + +{% highlight capnp %} +annotation qux(struct, field) :Void; + +struct MyStruct $qux { + string @0 :Text $qux; + number @1 :Int32 $qux; +} + +annotation corge(file) :MyStruct; + +$corge(string = "hello", number = 123); + +struct Grault { + value @0 :Int32 = 123; +} + +annotation grault(file) :Grault; + +$grault(); # value defaults to 123 +$grault(value = 456); +{% endhighlight %} + +### Unique IDs + +A Cap'n Proto file must have a unique 64-bit ID, and each type and annotation defined therein may +also have an ID. Use `capnp id` to generate a new ID randomly. ID specifications begin with `@`: + +{% highlight capnp %} +# file ID +@0xdbb9ad1f14bf0b36; + +struct Foo @0x8db435604d0d3723 { + # ... +} + +enum Bar @0xb400f69b5334aab3 { + # ... +} + +interface Baz @0xf7141baba3c12691 { + # ... +} + +annotation qux @0xf8a1bedf44c89f00 (field) :Text; +{% endhighlight %} + +If you omit the ID for a type or annotation, one will be assigned automatically. This default +ID is derived by taking the first 8 bytes of the MD5 hash of the parent scope's ID concatenated +with the declaration's name (where the "parent scope" is the file for top-level declarations, or +the outer type for nested declarations). You can see the automatically-generated IDs by "compiling" +your file with the `-ocapnp` flag, which echos the schema back to the terminal annotated with +extra information, e.g. `capnp compile -ocapnp myschema.capnp`. In general, you would only specify +an explicit ID for a declaration if that declaration has been renamed or moved and you want the ID +to stay the same for backwards-compatibility. + +IDs exist to provide a relatively short yet unambiguous way to refer to a type or annotation from +another context. They may be used for representing schemas, for tagging dynamically-typed fields, +etc. Most languages prefer instead to define a symbolic global namespace e.g. full of "packages", +but this would have some important disadvantages in the context of Cap'n Proto: + +* Programmers often feel the need to change symbolic names and organization in order to make their + code cleaner, but the renamed code should still work with existing encoded data. +* It's easy for symbolic names to collide, and these collisions could be hard to detect in a large + distributed system with many different binaries using different versions of protocols. +* Fully-qualified type names may be large and waste space when transmitted on the wire. + +Note that IDs are 64-bit (actually, 63-bit, as the first bit is always 1). Random collisions +are possible, but unlikely -- there would have to be on the order of a billion types before this +becomes a real concern. Collisions from misuse (e.g. copying an example without changing the ID) +are much more likely. + +## Evolving Your Protocol + +A protocol can be changed in the following ways without breaking backwards-compatibility, and +without changing the [canonical](encoding.html#canonicalization) encoding of a message: + +* New types, constants, and aliases can be added anywhere, since they obviously don't affect the + encoding of any existing type. + +* New fields, enumerants, and methods may be added to structs, enums, and interfaces, respectively, + as long as each new member's number is larger than all previous members. Similarly, new fields + may be added to existing groups and unions. + +* New parameters may be added to a method. The new parameters must be added to the end of the + parameter list and must have default values. + +* Members can be re-arranged in the source code, so long as their numbers stay the same. + +* Any symbolic name can be changed, as long as the type ID / ordinal numbers stay the same. Note + that type declarations have an implicit ID generated based on their name and parent's ID, but + you can use `capnp compile -ocapnp myschema.capnp` to find out what that number is, and then + declare it explicitly after your rename. + +* Type definitions can be moved to different scopes, as long as the type ID is declared + explicitly. + +* A field can be moved into a group or a union, as long as the group/union and all other fields + within it are new. In other words, a field can be replaced with a group or union containing an + equivalent field and some new fields. + +* A non-generic type can be made [generic](#generic-types), and new generic parameters may be + added to an existing generic type. Other types used inside the body of the newly-generic type can + be replaced with the new generic parameter so long as all existing users of the type are updated + to bind that generic parameter to the type it replaced. For example: + +
{% highlight capnp %} + struct Map { + entries @0 :List(Entry); + struct Entry { + key @0 :Text; + value @1 :Text; + } + } + {% endhighlight %} +
+ + Can change to: + +
{% highlight capnp %} + struct Map(Key, Value) { + entries @0 :List(Entry); + struct Entry { + key @0 :Key; + value @1 :Value; + } + } + {% endhighlight %} +
+ + As long as all existing uses of `Map` are replaced with `Map(Text, Text)` (and any uses of + `Map.Entry` are replaced with `Map(Text, Text).Entry`). + + (This rule applies analogously to generic methods.) + +The following changes are backwards-compatible but may change the canonical encoding of a message. +Apps that rely on canonicalization (such as some cryptographic protocols) should avoid changes in +this list, but most apps can safely use them: + +* A field of type `List(T)`, where `T` is a primitive type, blob, or list, may be changed to type + `List(U)`, where `U` is a struct type whose `@0` field is of type `T`. This rule is useful when + you realize too late that you need to attach some extra data to each element of your list. + Without this rule, you would be stuck defining parallel lists, which are ugly and error-prone. + As a special exception to this rule, `List(Bool)` may **not** be upgraded to a list of structs, + because implementing this for bit lists has proven unreasonably expensive. + +Any change not listed above should be assumed NOT to be safe. In particular: + +* You cannot change a field, method, or enumerant's number. +* You cannot change a field or method parameter's type or default value. +* You cannot change a type's ID. +* You cannot change the name of a type that doesn't have an explicit ID, as the implicit ID is + generated based in part on the type name. +* You cannot move a type to a different scope or file unless it has an explicit ID, as the implicit + ID is based in part on the scope's ID. +* You cannot move an existing field into or out of an existing union, nor can you form a new union + containing more than one existing field. + +Also, these rules only apply to the Cap'n Proto native encoding. It is sometimes useful to +transcode Cap'n Proto types to other formats, like JSON, which may have different rules (e.g., +field names cannot change in JSON). diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/news/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/news/index.html Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,24 @@ +--- +title: News +--- + +{% include header.html %} + + + +

News

+ +{% for post in site.posts %} +

{{ post.title }}

+

+ {{ post.author }} + {% if post.author == 'kentonv' %} + {% endif %} + on {{ post.date | date_to_string }} +

+{{ post.content }} +{% endfor %} + + +{% include footer.html %} diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/otherlang.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/otherlang.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,124 @@ +--- +layout: page +title: Other Languages +--- + +# Other Languages + +Cap'n Proto's reference implementation is in C++. Implementations in other languages are +maintained by respective authors and have not been reviewed by me +([@kentonv](https://github.com/kentonv)). Below are the implementations I'm aware +of. Some of these projects are more "ready" than others; please consult each +project's documentation for details. + +##### Serialization + RPC + +* [C++](cxx.html) by [@kentonv](https://github.com/kentonv) +* [Erlang](http://ecapnp.astekk.se/) by [@kaos](https://github.com/kaos) +* [Go](https://github.com/zombiezen/go-capnproto2) by [@zombiezen](https://github.com/zombiezen) (forked from [@glycerine](https://github.com/glycerine)'s serialization-only version, below) +* [Javascript (Node.js only)](https://github.com/kentonv/node-capnp) by [@kentonv](https://github.com/kentonv) +* [Python](http://jparyani.github.io/pycapnp/) by [@jparyani](https://github.com/jparyani) +* [Rust](https://github.com/dwrensha/capnproto-rust) by [@dwrensha](https://github.com/dwrensha) + +##### Serialization only + +* [C](https://github.com/opensourcerouting/c-capnproto) by [OpenSourceRouting](https://www.opensourcerouting.org/) / [@eqvinox](https://github.com/eqvinox) (originally by [@jmckaskill](https://github.com/jmckaskill)) +* [C#](https://github.com/mgravell/capnproto-net) by [@mgravell](https://github.com/mgravell) +* [Go](https://github.com/glycerine/go-capnproto) by [@glycerine](https://github.com/glycerine) (originally by [@jmckaskill](https://github.com/jmckaskill)) +* [Java](https://github.com/dwrensha/capnproto-java/) by [@dwrensha](https://github.com/dwrensha) +* [Javascript](https://github.com/popham/capnp-js-base) by [@popham](https://github.com/popham) +* [Javascript](https://github.com/jscheid/capnproto-js) (older, abandoned) by [@jscheid](https://github.com/jscheid) +* [Lua](https://github.com/cloudflare/lua-capnproto) by [CloudFlare](http://www.cloudflare.com/) / [@calio](https://github.com/calio) +* [Nim](https://github.com/zielmicha/capnp.nim) by [@zielmicha](https://github.com/zielmicha) +* [OCaml](https://github.com/pelzlpj/capnp-ocaml) by [@pelzlpj](https://github.com/pelzlpj) +* [Ruby](https://github.com/cstrahan/capnp-ruby) by [@cstrahan](https://github.com/cstrahan) +* [Scala](https://github.com/katis/capnp-scala) by [@katis](https://github.com/katis) + +##### Tools + +These are other misc projects related to Cap'n Proto that are not actually implementations in +new languages. + +* [Common Test Framework](https://github.com/kaos/capnp_test) by [@kaos](https://github.com/kaos) +* [Sublime Syntax Highlighting](https://github.com/joshuawarner32/capnproto-sublime) by + [@joshuawarner32](https://github.com/joshuawarner32) +* [Vim Syntax Highlighting](https://github.com/peter-edge/vim-capnp) by [@peter-edge](https://github.com/peter-edge) + (originally by [@cstrahan](https://github.com/cstrahan)) +* [Wireshark Dissector Plugin](https://github.com/kaos/wireshark-plugins) by [@kaos](https://github.com/kaos) + +## Contribute Your Own! + +We'd like to support many more languages in the future! + +If you'd like to own the implementation of Cap'n Proto in some particular language, +[let us know](https://groups.google.com/group/capnproto)! + +**You should e-mail the list _before_ you start hacking.** We don't bite, and we'll probably have +useful tips that will save you time. :) + +**Do not implement your own schema parser.** The schema language is more complicated than it +looks, and the algorithm to determine offsets of fields is subtle. If you reuse the official +parser, you won't risk getting these wrong, and you won't have to spend time keeping your parser +up-to-date. In fact, you can still write your code generator in any language you want, using +compiler plugins! + +### How to Write Compiler Plugins + +The Cap'n Proto tool, `capnp`, does not actually know how to generate code. It only parses schemas, +then hands the parse tree off to another binary -- known as a "plugin" -- which generates the code. +Plugins are independent executables (written in any language) which read a description of the +schema from standard input and then generate the necessary code. The description is itself a +Cap'n Proto message, defined by +[schema.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp). +Specifically, the plugin receives a `CodeGeneratorRequest`, using +[standard serialization](encoding.html#serialization-over-a-stream) +(not packed). (Note that installing the C++ runtime causes schema.capnp to be placed in +`$PREFIX/include/capnp` -- `/usr/local/include/capnp` by default). + +Of course, because the input to a plugin is itself in Cap'n Proto format, if you write your +plugin directly in the language you wish to support, you may have a bootstrapping problem: you +somehow need to generate code for `schema.capnp` before you write your code generator. Luckily, +because of the simplicity of the Cap'n Proto format, it is generally not too hard to do this by +hand. Remember that you can use `capnp compile -ocapnp schema.capnp` to get a dump of the sizes +and offsets of all structs and fields defined in the file. + +`capnp compile` normally looks for plugins in `$PATH` with the name `capnpc-[language]`, e.g. +`capnpc-c++` or `capnpc-capnp`. However, if the language name given on the command line contains +a slash character, `capnp` assumes that it is an exact path to the plugin executable, and does not +search `$PATH`. Examples: + + # Searches $PATH for executable "capnpc-mylang". + capnp compile -o mylang addressbook.capnp + + # Uses plugin executable "myplugin" from the current directory. + capnp compile -o ./myplugin addressbook.capnp + +If the user specifies an output directory, the compiler will run the plugin with that directory +as the working directory, so you do not need to worry about this. + +For examples of plugins, take a look at +[capnpc-capnp](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/compiler/capnpc-capnp.c%2B%2B) +or [capnpc-c++](https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/compiler/capnpc-c%2B%2B.c%2B%2B). + +### Supporting Dynamic Languages + +Dynamic languages have no compile step. This makes it difficult to work `capnp compile` into the +workflow for such languages. Additionally, dynamic languages are often scripting languages that do +not support pointer arithmetic or any reasonably-performant alternative. + +Fortunately, dynamic languages usually have facilities for calling native code. The best way to +support Cap'n Proto in a dynamic language, then, is to wrap the C++ library, in particular the +[C++ dynamic API](cxx.html#dynamic-reflection). This way you get reasonable performance while +still avoiding the need to generate any code specific to each schema. + +To parse the schema files, use the `capnp::SchemaParser` class (defined in `capnp/schema-parser.h`). +This way, schemas are loaded at the same time as all the rest of the program's code -- at startup. +An advanced implementation might consider caching the compiled schemas in binary format, then +loading the cached version using `capnp::SchemaLoader`, similar to the way e.g. Python caches +compiled source files as `.pyc` bytecode, but that's up to you. + +### Testing Your Implementation + +The easiest way to test that you've implemented the spec correctly is to use the `capnp` tool +to [encode](capnp-tool.html#encoding-messages) test inputs and +[decode](capnp-tool.html#decoding-messages) outputs. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/push-site.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/push-site.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,58 @@ +#! /usr/bin/env bash + +set -eu +shopt -s extglob + +if grep 'localhost:4000' *.md _posts/*.md; then + echo "ERROR: Your content has links to localhost:4000!" >&2 + exit 1 +fi + +if [ "x$(git status --porcelain)" != "x" ]; then + echo -n "git repo has uncommited changes. Continue anyway? (y/N) " >&2 + read -n 1 YESNO + echo >&2 + if [ "x$YESNO" != xy ]; then + exit 1 + fi +fi + +case $(git rev-parse --abbrev-ref HEAD) in + master ) + echo "On master branch. Will generate to /next." + CONFIG=_config_next.yml + PREFIX=/next + LABEL="preview site" + FUTURE=--future + ;; + + release-* ) + echo "On release branch. Will generate to /." + CONFIG=_config.yml + PREFIX= + LABEL="site" + FUTURE= + ;; + + * ) + echo "Unrecognized branch." >&2 + exit 1 + ;; +esac + +echo "Regenerating site..." + +rm -rf _site _site.tar.gz + +jekyll build --safe $FUTURE --config $CONFIG + +echo -n "Push now? (y/N)" +read -n 1 YESNO +echo + +if [ "x$YESNO" == "xy" ]; then + echo "Pushing..." + tar cz --xform='s,_site/,,' _site/* | gce-ss ssh fe --command "cd /var/www/capnproto.org$PREFIX && tar xz" +else + echo "Push CANCELED" +fi diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/roadmap.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/roadmap.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,124 @@ +--- +layout: page +title: Road Map +--- + +# Road Map + +This is a list of big ideas we'd like to implement in Cap'n Proto. We don't know in what order +these will actually happen; as always, real work is driven by real-world needs. + +### Language Features + +* **Inline lists:** Lets you define a field composed of a fixed number of elements of the same + type, and have those elements be stored directly within the struct rather than as a separate + object. Useful mainly to avoid the need to validate list lengths when the length should always + be the same. Also saves a pointer's worth of space. +* **Type aliases:** Ability to define a type which is just an alias of some other type, and + have it show up as e.g. a `typedef` in languages that support that. (The current `using` + keyword is intended only for local use and does not affect code generation.) +* **Doc comments:** Harvest doc comments from schema files and use them to generate doc comments + on generated code. Also make them available in the compiled schema so that a documentation + generator could use them. +* **Encapsulated types:** This will allow you to create a hand-written wrapper around a + type which will be automatically injected into the generated code, so that you can provide a + nicer interface which encapsulates the type's inner state. +* **Maps:** Based on encapsulated and parameterized types. + +### RPC Protocol Features + +* **Dynamic schema transmission:** Allow e.g. Python applications to obtain schemas directly from + the RPC server so that they need not have a local copy. Great for interactive debugging. +* **Three-way introductions (level 3 RPC):** Allow RPC interactions between more than two parties, + with new connections formed automatically as needed. +* **Bulk and Realtime**: Add features that make it easier to design Cap'n Proto APIs for bulk + data transfers (with flow control) and realtime communications (where it's better to drop + messages than to deliver them late). +* **UDP transport**: Cap'n Proto RPC could benefit from implementing a UDP transport, in order + to achieve zero-round-trip three-party introductions and to implement "realtime" APIs (see + "bulk and realtime", above). +* **Encrypted transport**: Cap'n Proto RPC should support an encrypted transport which uses + capability-based authorization (not PKI), can accomplish zero-round-trip three-party + introductions (via a pre-shared key from the introducer) and based on modern crypto. TLS is + not designed for this, but we don't want to invent new crypto; we intend to build on + [libsodium](https://github.com/jedisct1/libsodium) and the + [Noise Protocol Framework](http://noiseprotocol.org/) as much as possible. + +### C++ Cap'n Proto API Features + +* **Plain Old C Structs:** The code generator should also generate a POCS type corresponding + to each struct type. The POCS type would use traditional memory allocation, thus would not + support zero-copy, but would support a more traditional and easy-to-use C++ API, including + the ability to mutate the object over time without convoluted memory management. POCS types + could be extracted from an inserted into messages with a single copy, allowing them to be + used easily in non-performance-critical code. +* **Multi-threading:** It should be made easy to assign different Cap'n Proto RPC objects + to different threads and have them be able to safely call each other. Each thread would still + have an anyschronous event loop serving the objects that belong to it. +* **Shared memory RPC:** Zero-copy inter-process communication. +* **JSON codec customization:** Extend the JSON library to support customizing the JSON + representation using annotations. For example, a field could be given a different name in + JSON than it is in Cap'n Proto. The goal of these features would be to allow any reasonable + pre-existing JSON schema to be representable as a Cap'n Proto type definition, so that + servers implementing JSON APIs can use Cap'n Proto exclusively on the server side. +* **LZ4 integration:** Integrate LZ4 compression into the API to further reduce bandwidth needs + with minimal CPU overhead. +* **Annotations API:** For each annotation definition, generate code which assists in extracting + that annotation from schema objects in a type-safe way. + +### C++ KJ API Features + +KJ is a framework library that is bundled with Cap'n Proto, but is broadly applicable to C++ +applications even if they don't use Cap'n Proto serialization. + +* **Fiber-based concurrency:** The C++ runtime's event loop concurrency model will be augmented + with support for fibers, which are like threads except that context switches happen only at + well-defined points (thus avoiding the need for mutex locking). Fibers essentially provide + syntax sugar on top of the event loop model. +* **TLS bindings:** Write bindings for e.g. OpenSSL to make it easy to integrate with the KJ + I/O framework, Cap'n Proto RPC, and the KJ HTTP library. +* **Modern crypto bindings:** A thin wrapper around + [libsodium](https://github.com/jedisct1/libsodium) with a nice C++ API, e.g. representing + keys using fixed-size, trivially-copyable classes. +* **Event loop integrations:** We should provide off-the-shelf integrations with popular event + loop libraries, such as libuv, libev, libevent, boost::asio, and others, so that it's easier + to use Cap'n Proto RPC in applications that already use another event framework. + +### Storage + +* **ORM interface:** Define a standard interface for capabilities that represent remotely-stored + objects, with get, put, publish, and subscribe methods. Ideally, parameterize this interface + on the stored type. +* **mmap-friendly mutable storage format:** Define a standard storage format that is friendly + to mmap-based use while allowing modification. (With the current serialization format, mmap + is only useful for read-only structures.) Possibly based on the ORM interface, updates only + possible at the granularity of a whole ORM entry. + +### Tools + +* **Schema compatibility checker:** Add a `capnp` command which, given two schemas, verifies + that the latter is a compatible upgrade from the former. This could be used as a git hook + to prevent submission of schema changes that would break wire compatibility. +* **RPC debugger:** Add a `capnp` command which sends an RPC from the command line and prints + the result. Useful for debugging RPC servers. + +## Quality Assurance + +These things absolutely must happen before any 1.0 release. Note that it's not yet decided when +a 1.0 release would happen nor how many 0.x releases might precede it. + +* **Expand test coverage:** There are lots of tests now, but some important scenarios, such as + handling invalid of invalid input, need better testing. +* **Performance review:** Performance is already very good compared to competitors, but at some + point we need to break out the profiler and really hone down on the details. +* **Security review:** We need a careful security review to make sure malicious input cannot + crash an application or corrupt memory. + +### Infrastructure + +Note: These are very large projects. + +* **JSON-HTTP proxy:** Develop a web server which can expose a Cap'n Proto RPC backend as a + JSON-over-HTTP protocol. +* **Database:** A fast storage database based on Cap'n Proto which implements the ORM interface + on top of the mmap storage format. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/rpc.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/rpc.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,256 @@ +--- +layout: page +title: RPC Protocol +--- + +# RPC Protocol + +## Introduction + +### Time Travel! _(Promise Pipelining)_ + + + +Cap'n Proto RPC employs TIME TRAVEL! The results of an RPC call are returned to the client +instantly, before the server even receives the initial request! + +There is, of course, a catch: The results can only be used as part of a new request sent to the +same server. If you want to use the results for anything else, you must wait. + +This is useful, however: Say that, as in the picture, you want to call `foo()`, then call `bar()` +on its result, i.e. `bar(foo())`. Or -- as is very common in object-oriented programming -- you +want to call a method on the result of another call, i.e. `foo().bar()`. With any traditional RPC +system, this will require two network round trips. With Cap'n Proto, it takes only one. In fact, +you can chain any number of such calls together -- with diamond dependencies and everything -- and +Cap'n Proto will collapse them all into one round trip. + +By now you can probably imagine how it works: if you execute `bar(foo())`, the client sends two +messages to the server, one saying "Please execute foo()", and a second saying "Please execute +bar() on the result of the first call". These messages can be sent together -- there's no need +to wait for the first call to actually return. + +To make programming to this model easy, in your code, each call returns a "promise". Promises +work much like Javascript promises or promises/futures in other languages: the promise is returned +immediately, but you must later call `wait()` on it, or call `then()` to register an asynchronous +callback. + +However, Cap'n Proto promises support an additional feature: +[pipelining](http://www.erights.org/elib/distrib/pipeline.html). The promise +actually has methods corresponding to whatever methods the final result would have, except that +these methods may only be used for the purpose of calling back to the server. Moreover, a +pipelined promise can be used in the parameters to another call without waiting. + +**_But isn't that just syntax sugar?_** + +OK, fair enough. In a traditional RPC system, we might solve our problem by introducing a new +method `foobar()` which combines `foo()` and `bar()`. Now we've eliminated the round trip, without +inventing a whole new RPC protocol. + +The problem is, this kind of arbitrary combining of orthogonal features quickly turns elegant +object-oriented protocols into ad-hoc messes. + +For example, consider the following interface: + +{% highlight capnp %} +# A happy, object-oriented interface! + +interface Node {} + +interface Directory extends(Node) { + list @0 () -> (list: List(Entry)); + struct Entry { + name @0 :Text; + file @1 :Node; + } + + create @1 (name :Text) -> (node :Node); + open @2 (name :Text) -> (node :Node); + delete @3 (name :Text); + link @4 (name :Text, node :Node); +} + +interface File extends(Node) { + size @0 () -> (size: UInt64); + read @1 (startAt :UInt64, amount :UInt64) -> (data: Data); + write @2 (startAt :UInt64, data :Data); + truncate @3 (size :UInt64); +} +{% endhighlight %} + +This is a very clean interface for interacting with a file system. But say you are using this +interface over a satellite link with 1000ms latency. Now you have a problem: simply reading the +file `foo` in directory `bar` takes four round trips! + +{% highlight python %} +# pseudocode +bar = root.open("bar"); # 1 +foo = bar.open("foo"); # 2 +size = foo.size(); # 3 +data = foo.read(0, size); # 4 +# The above is four calls but takes only one network +# round trip with Cap'n Proto! +{% endhighlight %} + +In such a high-latency scenario, making your interface elegant is simply not worth 4x the latency. +So now you're going to change it. You'll probably do something like: + +* Introduce a notion of path strings, so that you can specify "foo/bar" rather than make two + separate calls. +* Merge the `File` and `Directory` interfaces into a single `Filesystem` interface, where every + call takes a path as an argument. + +{% highlight capnp %} +# A sad, singleton-ish interface. + +interface Filesystem { + list @0 (path :Text) -> (list :List(Text)); + create @1 (path :Text, data :Data); + delete @2 (path :Text); + link @3 (path :Text, target :Text); + + fileSize @4 (path :Text) -> (size: UInt64); + read @5 (path :Text, startAt :UInt64, amount :UInt64) + -> (data :Data); + readAll @6 (path :Text) -> (data: Data); + write @7 (path :Text, startAt :UInt64, data :Data); + truncate @8 (path :Text, size :UInt64); +} +{% endhighlight %} + +We've now solved our latency problem... but at what cost? + +* We now have to implement path string manipulation, which is always a headache. +* If someone wants to perform multiple operations on a file or directory, we now either have to + re-allocate resources for every call or we have to implement some sort of cache, which tends to + be complicated and error-prone. +* We can no longer give someone a specific `File` or a `Directory` -- we have to give them a + `Filesystem` and a path. + * But what if they are buggy and have hard-coded some path other than the one we specified? + * Or what if we don't trust them, and we really want them to access only one particular `File` or + `Directory` and not have permission to anything else. Now we have to implement authentication + and authorization systems! Arrgghh! + +Essentially, in our quest to avoid latency, we've resorted to using a singleton-ish design, and +[singletons are evil](http://www.object-oriented-security.org/lets-argue/singletons). + +**Promise Pipelining solves all of this!** + +With pipelining, our 4-step example can be automatically reduced to a single round trip with no +need to change our interface at all. We keep our simple, elegant, singleton-free interface, we +don't have to implement path strings, caching, authentication, or authorization, and yet everything +performs as well as we can possibly hope for. + +#### Example code + +[The calculator example](https://github.com/sandstorm-io/capnproto/blob/master/c++/samples/calculator-client.c++) +uses promise pipelining. Take a look at the client side in particular. + +### Distributed Objects + +As you've noticed by now, Cap'n Proto RPC is a distributed object protocol. Interface references -- +or, as we more commonly call them, capabilities -- are a first-class type. You can pass a +capability as a parameter to a method or embed it in a struct or list. This is a huge difference +from many modern RPC-over-HTTP protocols that only let you address global URLs, or other RPC +systems like Protocol Buffers and Thrift that only let you address singleton objects exported at +startup. The ability to dynamically introduce new objects and pass around references to them +allows you to use the same design patterns over the network that you use locally in object-oriented +programming languages. Many kinds of interactions become vastly easier to express given the +richer vocabulary. + +**_Didn't CORBA prove this doesn't work?_** + +No! + +CORBA failed for many reasons, with the usual problems of design-by-committee being a big one. + +However, the biggest reason for CORBA's failure is that it tried to make remote calls look the +same as local calls. Cap'n Proto does NOT do this -- remote calls have a different kind of API +involving promises, and accounts for the presence of a network introducing latency and +unreliability. + +As shown above, promise pipelining is absolutely critical to making object-oriented interfaces work +in the presence of latency. If remote calls look the same as local calls, there is no opportunity +to introduce promise pipelining, and latency is inevitable. Any distributed object protocol which +does not support promise pipelining cannot -- and should not -- succeed. Thus the failure of CORBA +(and DCOM, etc.) was inevitable, but Cap'n Proto is different. + +### Handling disconnects + +Networks are unreliable. Occasionally, connections will be lost. When this happens, all +capabilities (object references) served by the connection will become disconnected. Any further +calls addressed to these capabilities will throw "disconnected" exceptions. When this happens, the +client will need to create a new connection and try again. All Cap'n Proto applications with +long-running connections (and probably short-running ones too) should be prepared to catch +"disconnected" exceptions and respond appropriately. + +On the server side, when all references to an object have been "dropped" (either because the +clients explicitly dropped them or because they became disconnected), the object will be closed +(in C++, the destructor is called; in GC'd languages, a `close()` method is called). This allows +servers to easily allocate per-client resources without having to clean up on a timeout or risk +leaking memory. + +### Security + +Cap'n Proto interface references are +[capabilities](http://en.wikipedia.org/wiki/Capability-based_security). That is, they both +designate an object to call and confer permission to call it. When a new object is created, only +the creator is initially able to call it. When the object is passed over a network connection, +the receiver gains permission to make calls -- but no one else does. In fact, it is impossible +for others to access the capability without consent of either the host or the receiver because +the host only assigns it an ID specific to the connection over which it was sent. + +Capability-based design patterns -- which largely boil down to object-oriented design patterns -- +work great with Cap'n Proto. Such patterns tend to be much more adaptable than traditional +ACL-based security, making it easy to keep security tight and avoid confused-deputy attacks while +minimizing pain for legitimate users. That said, you can of course implement ACLs or any other +pattern on top of capabilities. + +For an extended discussion of what capabilities are and why they are often easier and more powerful +than ACLs, see Mark Miller's +["An Ode to the Granovetter Diagram"](http://www.erights.org/elib/capability/ode/index.html) and +[Capability Myths Demolished](http://zesty.ca/capmyths/usenix.pdf). + +## Protocol Features + +Cap'n Proto's RPC protocol has the following notable features. Since the protocol is complicated, +the feature set has been divided into numbered "levels", so that implementations may declare which +features they have covered by advertising a level number. + +* **Level 1:** Object references and promise pipelining, as described above. +* **Level 2:** Persistent capabilities. You may request to "save" a capability, receiving a + persistent token which can be used to "restore" it in the future (on a new connection). Not + all capabilities can be saved; the host app must implement support for it. Building this into + the protocol makes it possible for a Cap'n-Proto-based data store to transparently save + structures containing capabilities without knowledge of the particular capability types or the + application built on them, as well as potentially enabling more powerful analysis and + visualization of stored data. +* **Level 3:** Three-way interactions. A network of Cap'n Proto vats (nodes) can pass object + references to each other and automatically form direct connections as needed. For instance, if + Alice (on machine A) sends Bob (on machine B) a reference to Carol (on machine C), then machine B + will form a new connection to machine C so that Bob can call Carol directly without proxying + through machine A. +* **Level 4:** Reference equality / joining. If you receive a set of capabilities from different + parties which should all point to the same underlying objects, you can verify securely that they + in fact do. This is subtle, but enables many security patterns that rely on one party being able + to verify that two or more other parties agree on something (imagine a digital escrow agent). + See [E's page on equality](http://erights.org/elib/equality/index.html). + +## Encryption + +At this time, Cap'n Proto does not specify an encryption scheme, but as it is a simple byte +stream protocol, it can easily be layered on top of SSL/TLS or other such protocols. + +## Specification + +The Cap'n Proto RPC protocol is defined in terms of Cap'n Proto serialization schemas. The +documentation is inline. See +[rpc.capnp](https://github.com/sandstorm-io/capnproto/blob/master/c++/src/capnp/rpc.capnp). + +Cap'n Proto's RPC protocol is based heavily on +[CapTP](http://www.erights.org/elib/distrib/captp/index.html), the distributed capability protocol +used by the [E programming language](http://www.erights.org/index.html). Lots of useful material +for understanding capabilities can be found at those links. + +The protocol is complex, but the functionality it supports is conceptually simple. Just as TCP +is a complex protocol that implements the simple concept of a byte stream, Cap'n Proto RPC is a +complex protocol that implements the simple concept of objects with callable methods. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/stylesheets/pygment_trac.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/stylesheets/pygment_trac.css Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,75 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f3f3; } +.highlight .c { color: #808080; font-style: italic } /* Comment */ +.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ +.highlight .k { color: #000099; font-weight: bold } /* Keyword */ +.highlight .o { color: #555555 } /* Operator */ +.highlight .cm { color: #808080; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #009999 } /* Comment.Preproc */ +.highlight .c1 { color: #808080; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ +.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ +.highlight .go { color: #AAAAAA } /* Generic.Output */ +.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #99CC66 } /* Generic.Traceback */ +.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #006699 } /* Keyword.Pseudo */ +.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #FF6600 } /* Literal.Number */ +.highlight .s { color: #CC3300 } /* Literal.String */ +.highlight .na { color: #330099 } /* Name.Attribute */ +.highlight .nb { color: #336666 } /* Name.Builtin */ +.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ +.highlight .no { color: #336600 } /* Name.Constant */ +.highlight .nd { color: #9999FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #CC00FF } /* Name.Function */ +.highlight .nl { color: #9999FF } /* Name.Label */ +.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #003333 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #FF6600 } /* Literal.Number.Float */ +.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ +.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ +.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ +.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ +.highlight .sc { color: #CC3300 } /* Literal.String.Char */ +.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #CC3300 } /* Literal.String.Double */ +.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ +.highlight .si { color: #AA0000 } /* Literal.String.Interpol */ +.highlight .sx { color: #CC3300 } /* Literal.String.Other */ +.highlight .sr { color: #33AAAA } /* Literal.String.Regex */ +.highlight .s1 { color: #CC3300 } /* Literal.String.Single */ +.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ +.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #003333 } /* Name.Variable.Class */ +.highlight .vg { color: #003333 } /* Name.Variable.Global */ +.highlight .vi { color: #003333 } /* Name.Variable.Instance */ +.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } + +.highlight .language-capnp .nd { color: #0099FF; font-weight: normal; } /* @N */ +.highlight .language-capnp .l { color: #003399; } /* = value */ +.highlight .language-capnp .nc { color: #009900; font-weight: normal; } /* :Type */ +.highlight .language-capnp .na { color: #999900; font-weight: normal; } /* $x */ diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/doc/stylesheets/stylesheet.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/doc/stylesheets/stylesheet.css Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,711 @@ +/******************************************************************************* +Site Design by @kentonv and @sailorhg. + +Originally based on Slate Theme for GitHub Pages +by Jason Costello, @jsncostello +*******************************************************************************/ + +@import url(pygment_trac.css); + +/******************************************************************************* +MeyerWeb Reset +*******************************************************************************/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +ol, ul { + list-style: none; +} + +blockquote, q { +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +a:focus { + outline: none; +} + +/******************************************************************************* +Theme Styles +*******************************************************************************/ + +body { + box-sizing: border-box; + color:#373737; + background: #212121; + font-size: 16px; + font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +h1, h2, h3, h4, h5, h6 { + margin: 10px 0; + font-weight: 700; + color:#222222; + font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; + letter-spacing: -1px; +} + +.hmargin { + margin: 10px 0 0 0; +} + +h1 { + font-size: 36px; + font-weight: 700; +} + +h2 { + padding-bottom: 10px; + font-size: 28px; + background: url('../images/bg_hr.png') repeat-x bottom; +} + +h3 { + font-size: 24px; +} + +h4 { + font-size: 21px; +} + +h5 { + font-size: 18px; +} + +h6 { + font-size: 16px; +} + +p { + margin: 10px 0 15px 0; +} + +footer p { + color: #f2f2f2; +} + +a { + text-decoration: none; + color: #007edf; + text-shadow: none; + + transition: color 0.5s ease; + transition: text-shadow 0.5s ease; + -webkit-transition: color 0.5s ease; + -webkit-transition: text-shadow 0.5s ease; + -moz-transition: color 0.5s ease; + -moz-transition: text-shadow 0.5s ease; + -o-transition: color 0.5s ease; + -o-transition: text-shadow 0.5s ease; + -ms-transition: color 0.5s ease; + -ms-transition: text-shadow 0.5s ease; +} + +#main_content a:hover { + color: #0069ba; +} + +footer a:hover { + color: #43adff; + text-shadow: #0090ff 0px 0px 2px; +} + +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +img { + position: relative; + margin: 0 auto; + max-width: 739px; +} + +img.gittip { + width: 51px; + height: 10px; +} + +img.gittip15 { + width: 77px; + height: 15px; +} + +pre, code { + width: 100%; + color: #222; + background-color: #fff; + + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 14px; + + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +h1>code { + font-size: 30px; +} + +pre { + width: -moz-calc(100% - 20px); + width: -webkit-calc(100% - 20px); + width: calc(100% - 20px); + padding: 10px; + box-shadow: 0 0 10px rgba(0,0,0,.1); + overflow: auto; +} + +code { + padding: 3px; + margin: 0 3px; + box-shadow: 0 0 10px rgba(0,0,0,.1); +} + +pre code { + display: block; + box-shadow: none; +} + +blockquote { + color: #666; + margin-bottom: 20px; + padding: 0 0 0 20px; + border-left: 3px solid #bbb; +} + +ul, ol, dl { + margin-bottom: 15px; + padding-left: 30px; +} + +ul li { + list-style: outside; +} + +ol li { + list-style: decimal outside; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + height: 1px; + margin-bottom: 5px; + border: none; + background: url('../images/bg_hr.png') repeat-x center; +} + +table { + border: 1px solid #373737; + margin-bottom: 20px; + text-align: left; + } + +th { + font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; + padding: 10px; + background: #373737; + color: #fff; + } + +td { + padding: 10px; + border: 1px solid #373737; + } + +form { + background: #f2f2f2; + padding: 20px; +} + +img { + width: 100%; + max-width: 100%; +} + +p.author { + margin: -1em 0 0 0; + padding: 0; + font-size: 80%; + color: #888; +} + +h1>a, h2>a { + color: black; +} + +/******************************************************************************* +Full-Width Styles +*******************************************************************************/ + +.outer { + width: 100%; +} + +.inner { + position: relative; + max-width: 640px; + padding: 20px 10px; + margin: 0 auto; +} + +body.normal #main_content.inner { + margin: 0 auto 0 340px; +} + +#discuss_banner { + display: block; + position: absolute; + top:0; + right: 10px; + width: 147px; + z-index: 10; + padding: 10px 50px 10px 10px; + color: #fff; + background: url('../images/groups-logo.png') #333 no-repeat 95% 50%; + font-weight: 700; + box-shadow: 0 0 10px rgba(0,0,0,.5); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +#forkme_banner { + display: ; + position: absolute; + top:0; + right: 230px; + z-index: 10; + padding: 10px 50px 10px 10px; + color: #fff; + background: url('../images/blacktocat.png') #333 no-repeat 95% 50%; + font-weight: 700; + box-shadow: 0 0 10px rgba(0,0,0,.5); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +.groups_link { + display: inline-block; + z-index: 10; + padding: 10px 50px 10px 10px; + margin: 5px; + color: #fff; + background: url('../images/groups-logo.png') #0090ff no-repeat 95% 50%; + background-color: #0090ff; + font-weight: 700; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +.github_link { + display: inline-block; + z-index: 10; + padding: 10px 50px 10px 10px; + margin: 5px; + color: #fff; + background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; + background-color: #0090ff; + font-weight: 700; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +.twitter_link { + display: inline-block; + z-index: 10; + padding: 10px 50px 10px 10px; + margin: 5px; + color: #fff; + background: url('../images/twitter.svg') #0090ff no-repeat 95% 50%; + background-color: #0090ff; + font-weight: 700; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +.block_link { + display: inline-block; + z-index: 10; + padding: 10px; + margin: 5px; + color: #fff; + background-color: #0090ff; + font-weight: 700; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +#header_wrap { + background: #C42727; +} + +#header_wrap .inner { + padding: 50px 10px 30px 10px; +} + +#next_banner { + position: absolute; + left: 100px; + right: 100px; + top: 100px; + z-index: 100; + border: 2px solid black; + background-color: rgba(196, 196, 196, 0.9); + text-align: center; + color: black; + padding: 30px; +} + +#next_banner h1 { + color: black; + font-size: 750%; +} + +#next_banner p { + margin: 1em 100px; +} + +#project_title { + margin: 0; + color: #fff; + font-size: 42px; + font-weight: 700; + text-shadow: #111 0px 0px 10px; +} + +#project_tagline { + color: #fff; + font-size: 24px; + font-weight: 300; + background: none; + text-shadow: #111 0px 0px 10px; +} + +#downloads { + position: absolute; + width: 210px; + z-index: 10; + top: 50px; + right: 0px; + background: url('../images/icon_download.png') no-repeat 0% 90%; +} + +.zip_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom left; +} + +.tar_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom right; + margin-left: 10px; +} + +.zip_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top left; +} + +.tar_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top right; +} + +#main_content_wrap { + background: #f2f2f2; + border-top: 1px solid #111; + border-bottom: 1px solid #111; +} + +#main_content { + padding-top: 40px; +} + +#footer_wrap { + background: #212121; +} + + + +/******************************************************************************* +Small Device Styles +*******************************************************************************/ + +@media screen and (max-width: 480px) { + body { + font-size:14px; + } + + #downloads { + display: none; + } + + .inner { + min-width: 320px; + max-width: 480px; + } + + #project_title { + font-size: 32px; + } + + h1 { + font-size: 28px; + } + + h2 { + font-size: 24px; + } + + h3 { + font-size: 21px; + } + + h4 { + font-size: 18px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + code, pre { + font-size: 11px; + } + + #forkme_banner { + right: 215px; + } + + #discuss_banner { + width: 132px; + } +} + +#infinitely_faster img{ + position: absolute; + left: 600px; + top: 266px; + z-index: 10; + max-width:222px; +} + +body.narrow #infinitely_faster{ + display:none; +} + +body.wide #corner_hack, body.normal #corner_hack { + position: absolute; + left: 0px; + top: 209px; + right: 0px; + height: 10px; + background: #212121; +} + +body.wide #corner_hack>div, body.normal #corner_hack>div { + margin-left: 249px; + height: 10px; + border-radius: 10px 0px 0px 0px; + background: #f2f2f2; + border-top: 1px solid #111; + border-left: 1px solid #111; +} + +body.wide #menu, body.normal #menu { + position: absolute; + left: 50px; + top: 494px; + width: 250px; + z-index: 10; +} + +body.wide #menu.floating, body.normal #menu.floating { + position: fixed; + top: 50px; +} + +body.narrow #menu { + position: relative; + max-width: 640px; + padding: 50px 10px 0px 10px; + margin: 0 auto; +} + +@media screen and (max-width: 480px) { + body.narrow #menu { + min-width: 320px; + max-width: 480px; + } +} + +#menu ul { + padding: 0; + margin: 0; +} + +#menu li { + margin: 0; + list-style-type: none; + background-color: #212121; +} +#menu>ul>li>a, #menu>ul>li.selected { + display: block; + padding: 10px 15px 10px 15px; +} +#menu>ul>li { + border-right: 1px solid #111; +} + +body.wide #menu>ul>li:last-child, body.normal #menu>ul>li:last-child { + border-radius: 0px 0px 10px 10px; + border-bottom: 1px solid #111; +} + +body.wide #menu>ul>li:first-child, body.normal #menu>ul>li:first-child { + border-radius: 10px 10px 0px 0px; + border-top: 1px solid #111; +} + +body.narrow #menu>ul>li:first-child { + border-radius: 10px 10px 0px 0px; +} + +body.narrow #menu>ul>li:last-child { + border-radius: 0px 0px 10px 10px; +} + +#menu a { + color: #aaa; +} + +#menu li.selected { + background-color: #2a2a2a; + color: #fff; +} + +#menu li.selected a { + color: #fff; +} + +#menu>ul>li:hover { + background-color: #2a2a2a; + cursor: pointer; +} + +#menu>ul>li.selected:hover { + background-color: #2a2a2a; + cursor: auto; +} + +#menu>ul>li.selected:hover { + cursor: auto; +} + +#menu>ul>li:hover a { + color: #eee; +} + +#menu>ul>li.selected:hover a { + color: #fff; +} + +ul#toc { + background-color: #2a2a2a; + margin: 0; + font-size: 80%; +} + +#toc ul { + margin: 0; + padding: 0; +} + +#toc li { + padding: 0 0 0 15px; + background-color: #2a2a2a; +} + +#menu p { + padding: 2px 0 2px 15px; + margin: 0; + text-indent: -15px; +} +#menu p:hover { + background-color: #313131; + cursor: pointer; +} + +table.pass-fail td { text-align: center; vertical-align: middle; } +table.pass-fail td:first-child { text-align: left; } +table.pass-fail td.pass { background-color: #8f8; } +table.pass-fail td.fail { background-color: #f88; } +table.pass-fail td.warn { background-color: #ff8; } + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/highlighting/emacs/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/highlighting/emacs/README.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,13 @@ +Syntax Coloring for Emacs +========================= + +How to use: + +Add this to your .emacs file (altering the path to wherever your +capnproto directory lives): + +```elisp +(add-to-list 'load-path "~/src/capnproto/highlighting/emacs") +(require 'capnp-mode) +(add-to-list 'auto-mode-alist '("\\.capnp\\'" . capnp-mode)) +``` diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/highlighting/emacs/capnp-mode.el --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/highlighting/emacs/capnp-mode.el Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,75 @@ +;;; capnp-mode.el --- major mode for editing Capn' Proto Files + +;; This is free and unencumbered software released into the public domain. + +;; Author: Brian Taylor +;; Version: 1.0.0 + +;;; Commentary: + +;; Provides basic syntax highlighting for capnp files. +;; +;; To use: +;; +;; Add something like this to your .emacs file: +;; +;; (add-to-list 'load-path "~/src/capnproto/highlighting/emacs") +;; (require 'capnp-mode) +;; (add-to-list 'auto-mode-alist '("\\.capnp\\'" . capnp-mode)) +;; + +;;; Code: + +;; command to comment/uncomment text +(defun capnp-comment-dwim (arg) + "Comment or uncomment current line or region in a smart way. +For detail, see `comment-dwim'." + (interactive "*P") + (require 'newcomment) + (let ( + (comment-start "#") (comment-end "") + ) + (comment-dwim arg))) + +(defvar capnp--syntax-table + (let ((syn-table (make-syntax-table))) + + ;; bash style comment: “# …” + (modify-syntax-entry ?# "< b" syn-table) + (modify-syntax-entry ?\n "> b" syn-table) + + syn-table) + "Syntax table for `capnp-mode'.") + +(defvar capnp--keywords + '("struct" "enum" "interface" "union" "import" + "using" "const" "annotation" "extends" "in" + "of" "on" "as" "with" "from" "fixed") + "Keywords in `capnp-mode'.") + +(defvar capnp--types + '("union" "group" "Void" "Bool" "Int8" "Int16" + "Int32" "Int64" "UInt8" "UInt16" "UInt32" + "UInt64" "Float32" "Float64" "Text" "Data" + "AnyPointer" "AnyStruct" "Capability" "List") + "Types in `capnp-mode'.") + +(defvar capnp--font-lock-keywords + `( + (,(regexp-opt capnp--keywords 'words) . font-lock-keyword-face) + (,(regexp-opt capnp--types 'words) . font-lock-type-face) + ("@\\w+" . font-lock-constant-face)) + "Font lock definitions in `capnp-mode'.") + +;;;###autoload +(define-derived-mode capnp-mode prog-mode + "capn-mode is a major mode for editing capnp protocol files" + :syntax-table capnp--syntax-table + + (setq font-lock-defaults '((capnp--font-lock-keywords))) + + + (setq mode-name "capnp") + (define-key capnp-mode-map [remap comment-dwim] 'capnp-comment-dwim)) + +(provide 'capnp-mode) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/highlighting/qtcreator/capnp.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/highlighting/qtcreator/capnp.xml Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,132 @@ + + + + + + + + + struct + enum + interface + union + import + using + const + annotation + extends + in + of + on + as + with + from + fixed + + + union + group + Void + Bool + Int8 + Int16 + Int32 + Int64 + UInt8 + UInt16 + UInt32 + UInt64 + Float32 + Float64 + Text + Data + AnyPointer + AnyStruct + Capability + List + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/mega-test-kenton-home.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/mega-test-kenton-home.cfg Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,6 @@ +linux-gcc-4.9 9717 ./super-test.sh tmpdir capnp-gcc-4.9 -j8 gcc-4.9 +linux-gcc 9720 ./super-test.sh tmpdir capnp-gcc -j8 +linux-clang-3.5 9855 ./super-test.sh tmpdir capnp-clang-3.5 -j8 compiler clang++-3.5 +linux-clang-5.0 9858 ./super-test.sh tmpdir capnp-clang-5.0 -j8 compiler clang++-5.0 +mac 7037 ./super-test.sh remote beat caffeinate +cygwin 8465 ./super-test.sh remote Kenton@flashman diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/mega-test-kenton-work.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/mega-test-kenton-work.cfg Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,5 @@ +linux-gcc-5 9717 ./super-test.sh tmpdir capnp-gcc-5 compiler g++-5 +linux-gcc-6 9710 ./super-test.sh tmpdir capnp-gcc-6 compiler g++-6 +linux-clang-3 9855 ./super-test.sh tmpdir capnp-clang-3 compiler clang++-3.8 +linux-clang-5 9858 ./super-test.sh tmpdir capnp-clang-5 compiler clang++-5.0 +exotic 4759 ./super-test.sh tmpdir capnp-exotic exotic diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/mega-test-quick.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/mega-test-quick.cfg Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,5 @@ +linux-gcc-4.9 950 ./super-test.sh tmpdir capnp-gcc-4.9 quick gcc-4.9 +linux-gcc-4.8 950 ./super-test.sh tmpdir capnp-gcc-4.8 quick gcc-4.8 +linux-clang 980 ./super-test.sh tmpdir capnp-clang quick clang +mac 905 ./super-test.sh remote beat caffeinate quick +cygwin 945 ./super-test.sh remote Kenton@flashman quick diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/mega-test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/mega-test.py Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,144 @@ +#! /usr/bin/env python + +# MEGA TEST +# +# usage: mega-test.py +# +# This runs several tests in parallel and shows progress bars for each, based on a config file. +# +# is a file containing a list of commands to run along with the expected number of lines +# they will output (to stdout and stderr combined), which is how the progress bar is calculated. +# The format of the file is simply one test per line, with the line containing the test name, +# the number of output lines expected, and the test command. Example: +# +# mytest 1523 ./my-test --foo bar +# another 862 ./another-test --baz +# +# Each command is interpreted by `sh -euc`, therefore it is acceptable to use environment +# variables and other shell syntax. +# +# After all tests complete, the config file will be rewritten to update the line counts to the +# actual number of lines seen for all passing tests (failing tests are not updated). + +import sys +import re +import os +from errno import EAGAIN +from fcntl import fcntl, F_GETFL, F_SETFL +from select import poll, POLLIN, POLLHUP +from subprocess import Popen, PIPE, STDOUT + +CONFIG_LINE = re.compile("^([^ ]+) +([0-9]+) +(.*)$") + +if len(sys.argv) != 2: + sys.stderr.write("Wrong number of arguments.\n"); + sys.exit(1) + +if not os.access("/tmp/test-output", os.F_OK): + os.mkdir("/tmp/test-output") + +config = open(sys.argv[1], 'r') + +tests = [] + +class Test: + def __init__(self, name, command, lines): + self.name = name + self.command = command + self.lines = lines + self.count = 0 + self.done = False + + def start(self, poller): + self.proc = Popen(["sh", "-euc", test.command], stdin=dev_null, stdout=PIPE, stderr=STDOUT) + fd = self.proc.stdout.fileno() + flags = fcntl(fd, F_GETFL) + fcntl(fd, F_SETFL, flags | os.O_NONBLOCK) + poller.register(self.proc.stdout, POLLIN) + self.log = open("/tmp/test-output/" + self.name + ".log", "w") + + def update(self): + try: + while True: + text = self.proc.stdout.read() + if text == "": + self.proc.wait() + self.done = True + self.log.close() + return True + self.count += text.count("\n") + self.log.write(text) + except IOError as e: + if e.errno == EAGAIN: + return False + raise + + def print_bar(self): + percent = self.count * 100 / self.lines + status = "(%3d%%)" % percent + + color_on = "" + color_off = "" + + if self.done: + if self.proc.returncode == 0: + color_on = "\033[0;32m" + status = "PASS" + else: + color_on = "\033[0;31m" + status = "FAIL: /tmp/test-output/%s.log" % self.name + color_off = "\033[0m" + + print "%s%-16s |%-25s| %6d/%6d %s%s " % ( + color_on, self.name, '=' * min(percent / 4, 25), self.count, self.lines, status, color_off) + + def passed(self): + return self.proc.returncode == 0 + +for line in config: + if len(line) > 0 and not line.startswith("#"): + match = CONFIG_LINE.match(line) + if not match: + sys.stderr.write("Invalid config syntax: %s\n" % line); + sys.exit(1) + test = Test(match.group(1), match.group(3), int(match.group(2))) + tests.append(test) + +config.close() + +dev_null = open("/dev/null", "rw") +poller = poll() +fd_map = {} + +for test in tests: + test.start(poller) + fd_map[test.proc.stdout.fileno()] = test + +active_count = len(tests) + +def print_bars(): + for test in tests: + test.print_bar() + +print_bars() + +while active_count > 0: + for (fd, event) in poller.poll(): + if fd_map[fd].update(): + active_count -= 1 + poller.unregister(fd) + sys.stdout.write("\033[%dA\r" % len(tests)) + print_bars() + +new_config = open(sys.argv[1], "w") +for test in tests: + if test.passed(): + new_config.write("%-16s %6d %s\n" % (test.name, test.count, test.command)) + else: + new_config.write("%-16s %6d %s\n" % (test.name, test.lines, test.command)) + +for test in tests: + if not test.passed(): + sys.exit(1) + +sys.exit(0) diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/release.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/release.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,345 @@ +#! /usr/bin/env bash + +set -euo pipefail + +if [ "$1" != "package" ]; then + if (grep -r KJ_DBG c++/src | egrep -v '/debug(-test)?[.]' | grep -v 'See KJ_DBG\.$'); then + echo '*** Error: There are instances of KJ_DBG in the code.' >&2 + exit 1 + fi + + if (egrep -r 'TODO\((now|soon)\)' *); then + echo '*** Error: There are release-blocking TODOs in the code.' >&2 + exit 1 + fi +fi + +doit() { + echo "@@@@ $@" + "$@" +} + +get_version() { + local VERSION=$(grep AC_INIT c++/configure.ac | sed -e 's/^[^]]*],\[\([^]]*\)].*$/\1/g') + if [[ ! "$VERSION" =~ $1 ]]; then + echo "Couldn't parse version: $VERSION" >&2 + exit 1 + fi + echo "$VERSION" +} + +get_release_version() { + get_version '^[0-9]+[.][0-9]+[.][0-9]+(-rc[0-9]+|[.][0-9]+)?$' +} + +update_version() { + local OLD=$1 + local NEW=$2 + local BRANCH_DESC=$3 + + local OLD_REGEX=${OLD//./[.]} + doit sed -i -e "s/$OLD_REGEX/$NEW/g" c++/configure.ac + doit sed -i -e "s/set(VERSION.*)/set(VERSION $NEW)/g" c++/CMakeLists.txt + + local NEW_NOTAG=${NEW%%-*} + declare -a NEW_ARR=(${NEW_NOTAG//./ }) + doit sed -i -re " + s/^#define CAPNP_VERSION_MAJOR [0-9]+\$/#define CAPNP_VERSION_MAJOR ${NEW_ARR[0]}/g; + s/^#define CAPNP_VERSION_MINOR [0-9]+\$/#define CAPNP_VERSION_MINOR ${NEW_ARR[1]}/g; + s/^#define CAPNP_VERSION_MICRO [0-9]+\$/#define CAPNP_VERSION_MICRO ${NEW_ARR[2]:-0}/g" \ + c++/src/capnp/common.h + + local NEW_COMBINED=$(( ${NEW_ARR[0]} * 1000000 + ${NEW_ARR[1]} * 1000 + ${NEW_ARR[2]:-0 })) + doit sed -i -re "s/^#if CAPNP_VERSION != [0-9]*\$/#if CAPNP_VERSION != $NEW_COMBINED/g" \ + c++/src/*/*.capnp.h c++/src/*/*/*.capnp.h + + doit git commit -a -m "Set $BRANCH_DESC version to $NEW." +} + +build_packages() { + local VERSION=$1 + local VERSION_BASE=${VERSION%%-*} + + echo "=========================================================================" + echo "Building C++ package..." + echo "=========================================================================" + + # make dist tarball and move into .. + cd c++ + doit autoreconf -i + doit ./configure + doit make -j6 distcheck + doit mv capnproto-c++-$VERSION.tar.gz .. + doit make distclean + + # build windows executables + doit ./configure --host=i686-w64-mingw32 --with-external-capnp \ + --disable-shared CXXFLAGS='-static-libgcc -static-libstdc++' + doit make -j6 capnp.exe capnpc-c++.exe capnpc-capnp.exe + doit i686-w64-mingw32-strip capnp.exe capnpc-c++.exe capnpc-capnp.exe + doit mkdir capnproto-tools-win32-$VERSION + doit mv capnp.exe capnpc-c++.exe capnpc-capnp.exe capnproto-tools-win32-$VERSION + doit make maintainer-clean + + # repack dist tarball and win32 tools into win32 zip, with DOS line endings + doit tar zxf ../capnproto-c++-$VERSION.tar.gz + find capnproto-c++-$VERSION -name '*.c++' -o -name '*.h' -o -name '*.capnp' -o -name '*.md' -o -name '*.txt' | grep -v testdata | doit xargs unix2dos + doit zip -r ../capnproto-c++-win32-$VERSION.zip capnproto-c++-$VERSION capnproto-tools-win32-$VERSION + + rm -rf capnproto-c++-$VERSION capnproto-tools-win32-$VERSION + cd .. +} + +cherry_pick() { + shift + if [ $# -gt 0 ]; then + echo "=========================================================================" + echo "Cherry-picking fixes" + echo "=========================================================================" + doit git cherry-pick "$@" + fi +} + +done_banner() { + local VERSION=$1 + local PUSH=$2 + local FINAL=$3 + echo "=========================================================================" + echo "Done" + echo "=========================================================================" + echo "Ready to release:" + echo " capnproto-c++-$VERSION.tar.gz" + echo " capnproto-c++-win32-$VERSION.zip" + echo "Don't forget to push changes:" + echo " git push origin $PUSH" + + read -s -n 1 -p "Shall I push to git and upload to capnproto.org now? (y/N)" YESNO + + echo + case "$YESNO" in + y | Y ) + doit git push origin $PUSH + doit gce-ss copy-files capnproto-c++-$VERSION.tar.gz capnproto-c++-win32-$VERSION.zip \ + fe:/var/www/capnproto.org + + if [ "$FINAL" = yes ]; then + echo "=========================================================================" + echo "Publishing docs" + echo "=========================================================================" + cd doc + doit ./push-site.sh + cd .. + echo "=========================================================================" + echo "Really done" + echo "=========================================================================" + fi + + echo "Release is available at:" + echo " http://capnproto.org/capnproto-c++-$VERSION.tar.gz" + ;; + * ) + echo "OK, do it yourself then." + ;; + esac +} + +BRANCH=$(git rev-parse --abbrev-ref HEAD) + +case "${1-}:$BRANCH" in + # ====================================================================================== + candidate:master ) + echo "New major release." + + if [ $# -gt 1 ]; then + echo "Cannot cherry-pick when starting from master. Do it yourself." >&2 + exit 1 + fi + + HEAD_VERSION=$(get_version '^[0-9]+[.][0-9]+-dev$') + RELEASE_VERSION=${HEAD_VERSION%%-dev}.0 + + echo "Version: $RELEASE_VERSION" + + echo "=========================================================================" + echo "Creating release branch..." + echo "=========================================================================" + doit git checkout -b release-$RELEASE_VERSION + + update_version $HEAD_VERSION $RELEASE_VERSION-rc1 "release branch" + + build_packages $RELEASE_VERSION-rc1 + + echo "=========================================================================" + echo "Updating version in master branch..." + echo "=========================================================================" + + doit git checkout master + declare -a VERSION_ARR=(${RELEASE_VERSION//./ }) + NEXT_VERSION=${VERSION_ARR[0]}.$((VERSION_ARR[1] + 1)) + + update_version $HEAD_VERSION $NEXT_VERSION-dev "mainlaine" + + done_banner $RELEASE_VERSION-rc1 "master release-$RELEASE_VERSION" no + ;; + + # ====================================================================================== + candidate:release-* ) + echo "New release candidate." + OLD_VERSION=$(get_release_version) + + if [[ $OLD_VERSION == *-rc* ]]; then + # New release candidate for existing release. + + RC=${OLD_VERSION##*-rc} + BRANCH_VERSION=${OLD_VERSION%%-rc*} + RC_VERSION=$BRANCH_VERSION-rc$(( RC + 1 )) + + echo "Version: $RC_VERSION" + else + # New micro release. + + declare -a VERSION_ARR=(${OLD_VERSION//./ }) + BRANCH_VERSION=${VERSION_ARR[0]}.${VERSION_ARR[1]}.$((VERSION_ARR[2] + 1)) + + RC_VERSION=$BRANCH_VERSION-rc1 + echo "Version: $RC_VERSION" + + echo "=========================================================================" + echo "Creating new release branch..." + echo "=========================================================================" + + doit git checkout -b release-$BRANCH_VERSION + fi + + echo "=========================================================================" + echo "Updating version number to $RC_VERSION..." + echo "=========================================================================" + + update_version $OLD_VERSION $RC_VERSION "release branch" + + cherry_pick "$@" + + build_packages $RC_VERSION + + done_banner $RC_VERSION release-$BRANCH_VERSION no + ;; + + # ====================================================================================== + final:release-* ) + echo "Final release." + OLD_VERSION=$(get_release_version) + + if [[ $OLD_VERSION != *-rc* ]]; then + echo "Current version is already a final release. You need to create a new candidate first." >&2 + exit 1 + fi + + if [ $# -gt 1 ]; then + echo "Cannot cherry-pick into final release. Make another candidate." >&2 + exit 1 + fi + + RC=${OLD_VERSION##*-rc} + NEW_VERSION=${OLD_VERSION%%-rc*} + + echo "Version: $NEW_VERSION" + + echo "=========================================================================" + echo "Updating version number to $NEW_VERSION..." + echo "=========================================================================" + + doit sed -i -re "s/capnproto-c[+][+]-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-$NEW_VERSION/g" doc/install.md + doit sed -i -re "s/capnproto-c[+][+]-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-win32-$NEW_VERSION/g" doc/install.md + doit sed -i -re "s/capnproto-tools-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-tools-win32-$NEW_VERSION/g" doc/install.md + update_version $OLD_VERSION $NEW_VERSION "release branch" + + doit git tag v$NEW_VERSION + + build_packages $NEW_VERSION + + done_banner $NEW_VERSION "v$NEW_VERSION release-$NEW_VERSION" yes + ;; + + # ====================================================================================== + security:release-* ) + echo "Security release." + OLD_VERSION=$(get_release_version) + + if [[ $OLD_VERSION == *-rc* ]]; then + echo "Security releases don't have candidates." >&2 + exit 1 + fi + + declare -a VERSION_ARR=(${OLD_VERSION//./ } 0) + NEW_VERSION=${VERSION_ARR[0]}.${VERSION_ARR[1]}.${VERSION_ARR[2]}.$((VERSION_ARR[3] + 1)) + + echo "Version: $NEW_VERSION" + + echo "=========================================================================" + echo "Updating version number to $NEW_VERSION..." + echo "=========================================================================" + + doit sed -i -re "s/capnproto-c[+][+]-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-$NEW_VERSION/g" doc/install.md + doit sed -i -re "s/capnproto-c[+][+]-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-c++-win32-$NEW_VERSION/g" doc/install.md + doit sed -i -re "s/capnproto-tools-win32-[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?\>/capnproto-tools-win32-$NEW_VERSION/g" doc/install.md + update_version $OLD_VERSION $NEW_VERSION "release branch" + + cherry_pick "$@" + + doit git tag v$NEW_VERSION + + build_packages $NEW_VERSION + + done_banner $NEW_VERSION "v$NEW_VERSION release-$NEW_VERSION" yes + ;; + + # ====================================================================================== + retry:release-* ) + echo "Retrying release." + OLD_VERSION=$(get_release_version) + echo "Version: $OLD_VERSION" + + if [[ $OLD_VERSION == *-rc* ]]; then + # We can add more cherry-picks when retrying a candidate. + cherry_pick "$@" + else + if [ $# -gt 1 ]; then + echo "Cannot cherry-pick into final release. Make another candidate." >&2 + exit 1 + fi + fi + + OLD_VERSION=$(get_release_version) + build_packages $OLD_VERSION + + if [[ $OLD_VERSION == *-rc* ]]; then + BRANCH_VERSION=${OLD_VERSION%%-rc*} + done_banner $OLD_VERSION release-$BRANCH_VERSION no + else + doit git tag v$OLD_VERSION + done_banner $OLD_VERSION "v$OLD_VERSION release-$OLD_VERSION" no + fi + ;; + + # ====================================================================================== + package:* ) + echo "Just building a package." + build_packages $(get_version '.*') + ;; + + # ====================================================================================== + *:master ) + echo "Invalid command for mainline branch. Only command is 'candidate'." >&2 + exit 1 + ;; + + *:release-* ) + echo "Invalid command for release branch. Commands are 'candidate', 'final', and 'retry'." >&2 + exit 1 + ;; + + * ) + echo "Not a master or release branch." >&2 + exit 1 + ;; +esac diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/2015-03-02-0-c++-integer-overflow.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/2015-03-02-0-c++-integer-overflow.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,102 @@ +Problem +======= + +Integer overflow in pointer validation. + +Discovered by +============= + +Ben Laurie <ben@links.org> using [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/) + +Announced +========= + +2015-03-02 + +CVE +=== + +CVE-2015-2310 + +Impact +====== + +- Remotely segfault a peer by sending it a malicious message. +- Possible exfiltration of memory, depending on application behavior. + +Fixed in +======== + +- git commit [f343f0dbd0a2e87f17cd74f14186ed73e3fbdbfa][0] +- release 0.5.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz + - Windows: https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip +- release 0.4.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz +- release 0.6 (future) + +[0]: https://github.com/sandstorm-io/capnproto/commit/f343f0dbd0a2e87f17cd74f14186ed73e3fbdbfa + +Details +======= + +*The following text contains speculation about the exploitability of this +bug. This is provided for informational purposes, but as such speculation is +often shown to be wrong, you should not rely on the accuracy of this +section for the safety of your service. Please update your library.* + +A specially-crafted pointer could escape bounds checking by triggering an +integer overflow in the check. This causes the message to appear as if it +contains an extremely long list (over 2^32 bytes), stretching far beyond the +memory actually allocated to the message. If the application reads that list, +it will likely segfault, but if it manages to avoid a segfault (e.g. because +it has mapped a very large contiguous block of memory following the message, +or because it only reads some parts of the list and not others), it could end +up treating arbitrary parts of memory as input. If the application happens to +pass that data back to the user in some way, this problem could lead to +exfiltration of secrets. + +The pointer is transitively read-only, therefore it is believed that this +vulnerability on its own CANNOT lead to memory corruption nor code execution. + +This vulnerability is NOT a Sandstorm sandbox breakout. A Sandstorm app's +Cap'n Proto communications pass through a supervisor process which performs a +deep copy of the structure. As the supervisor has a very small heap, this +will always lead to a segfault, which has the effect of killing the app, but +does not affect any other app or the system at large. If somehow the copy +succeeds, the copied message will no longer contain an invalid pointer and +so will not harm its eventual destination, and the supervisor itself has no +secrets to steal. These mitigations are by design. + +Preventative measures +===================== + +In order to gain confidence that this is a one-off bug rather than endemic, +and to help prevent new bugs from being added, we have taken / will take the +following preventative measures going forward: + +1. A fuzz test of each pointer type has been added to the standard unit test + suite. This test was confirmed to find the vulnerability in question. +2. We will additionally add fuzz testing with American Fuzzy Lop to our + extended test suite. AFL was used to find the original vulnerability. Our + current tests with AFL show only one other (less-critical) vulnerability + which will be reported separately ([2015-03-02-2][2]). +3. In parallel, we will extend our use of template metaprogramming for + compile-time unit analysis (kj::Quantity in kj/units.h) to also cover + overflow detection (by tracking the maximum size of an integer value across + arithmetic expressions and raising an error when it overflows). Preliminary + work with this approach successfully detected the vulnerability reported + here as well as one other vulnerability ([2015-03-02-1][3]). + [See the blog post][4] for more details. +4. We will continue to require that all tests (including the new fuzz test) run + cleanly under Valgrind before each release. +5. We will commission a professional security review before any 1.0 release. + Until that time, we continue to recommend against using Cap'n Proto to + interpret data from potentially-malicious sources. + +I am pleased that measures 1, 2, and 3 all detected this bug, suggesting that +they have a high probability of catching any similar bugs. + +[1]: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-all-cpu-amplification.md +[2]: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-1-c++-integer-underflow.md +[3]: https://capnproto.org/news/2015-03-02-security-advisory-and-integer-overflow-protection.html diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/2015-03-02-1-c++-integer-underflow.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/2015-03-02-1-c++-integer-underflow.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,110 @@ +Problem +======= + +Integer underflow in pointer validation. + +Discovered by +============= + +Kenton Varda <kenton@sandstorm.io> + +Announced +========= + +2015-03-02 + +CVE +=== + +CVE-2015-2311 + +Impact +====== + +- Remotely segfault a peer by sending it a malicious message. +- Possible exfiltration of memory, depending on application behavior. +- If the application performs a sequence of operations that "probably" no + application does (see below), possible memory corruption / code execution. + +Fixed in +======== + +- git commit [26bcceda72372211063d62aab7e45665faa83633][0] +- release 0.5.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz + - Windows: https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip +- release 0.4.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz +- release 0.6 (future) + +[0]: https://github.com/sandstorm-io/capnproto/commit/26bcceda72372211063d62aab7e45665faa83633 + +Details +======= + +*The following text contains speculation about the exploitability of this +bug. This is provided for informational purposes, but as such speculation is +often shown to be wrong, you should not rely on the accuracy of this +section for the safety of your service. Please update your library.* + +A `Text` pointer, when non-null, must point to a NUL-terminated string, meaning +it must have a size of at least 1. Under most circumstances, Cap'n Proto will +reject zero-size text objects. However, if an application performs the +following sequence, they may hit a code path that was missing a check: + +1. Receive a message containing a `Text` value, but do not actually look at + that value. +2. Copy the message into a `MessageBuilder`. +3. Call the `get()` method for the `Text` value within the `MessageBuilder`, + obtaining a `Text::Builder` for the *copy*. + +In this case, the `Text::Builder` will appear to point at a string with size +2^32-1, starting at a location within the Cap'n Proto message. + +The `Text::Builder` is writable. If the application decided to overwrite the +text in-place, it could overwrite arbitrary memory in the next 4GB of virtual +address space. However, there are several reasons to believe this is unusual: + +- Usually, when an application `get()`s a text field, it only intends to + read it. Overwriting the text in-place is unusual. +- Calling `set()` on the field -- the usual way to overwrite text -- will + create an all-new text object and harmlessly discard the old, invalid + pointer. + +Note that even if an application does overwrite the text, it would still be +hard for the attacker to exploit this for code execution unless the attacker +also controls the data that the application writes into the field. + +This vulnerability is somewhat more likely to allow exfiltration of memory. +However, this requires the app to additionally echo the text back to the +attacker. To do this without segfaulting, the app would either need to attempt +to read only a subset of the text, or would need to have 2^32 contiguous bytes +of virtual memory mapped into its address space. + +A related problem, also fixed in this change, occurs when a `Text` value +has non-zero size but lacks a NUL terminator. Again, if an application +performs the series of operations described above, the NUL terminator check +may be bypassed. If the app then passes the string to an API that assumes +NUL-terminated strings, the contents of memory after the text blob may be +interpreted as being part of the string, up to the next zero-valued byte. +This again could lead to exfiltration of data, this time without the high +chance of segfault, although only up to the next zero-valued byte, which +are typically quite common. + +Preventative measures +===================== + +This problem was discovered through preventative measures implemented after +the security problem discussed in the [previous advisory][1]. Specifically, this +problem was found by using template metaprogramming to implement integer +bounds analysis in order to effectively "prove" that there are no integer +overflows in the core pointer validation code (capnp/layout.c++). +Tentatively, I believe that this analysis exhaustively covers this file. +The instrumentation has not been merged into master yet as it requires some +cleanup, but [check the Cap'n Proto blog for an in-depth discussion][2]. + +This problem is also caught by capnp/fuzz-test.c++, which *has* been +merged into master but likely doesn't have as broad coverage. + +[1]: https://github.com/sandstorm-io/capnproto/tree/master/security-advisories/2015-03-02-0-c++-integer-overflow.md +[2]: https://capnproto.org/news/2015-03-02-security-advisory-and-integer-overflow-protection.html diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/2015-03-02-2-all-cpu-amplification.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/2015-03-02-2-all-cpu-amplification.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,74 @@ +Problem +======= + +CPU usage amplification attack. + +Discovered by +============= + +Ben Laurie <ben@links.org> using [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/) + +Announced +========= + +2015-03-02 + +CVE +=== + +CVE-2015-2312 + +Impact +====== + +- Remotely cause a peer to use excessive CPU time and other resources to + process a very small message, possibly enabling a DoS attack. + +Fixed in +======== + +- git commit [104870608fde3c698483fdef6b97f093fc15685d][0] +- release 0.5.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.5.1.1.tar.gz + - Windows: https://capnproto.org/capnproto-c++-win32-0.5.1.1.zip +- release 0.4.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.4.1.1.tar.gz +- release 0.6 (future) + +[0]: https://github.com/sandstorm-io/capnproto/commit/104870608fde3c698483fdef6b97f093fc15685d + +Details +======= + +The Cap'n Proto list pointer format allows encoding a list whose elements are +claimed each to have a size of zero. Such a list could claim to have up to +2^29-1 elements while only taking 8 or 16 bytes on the wire. The receiving +application may expect, say, a list of structs. A zero-size struct is a +perfectly legal (and, in fact, canonical) encoding for a struct whose fields +are all set to their default values. Therefore, the application may notice +nothing wrong and proceed to iterate through and handle each element in the +list, potentially taking a lot of time and resources to do so. + +Note that this kind of vulnerability is very common in other systems. Any +system which accepts compressed input can allow an attacker to deliver an +arbitrarily large uncompressed message using very little compressed bandwidth. +Applications should do their own validation to ensure that lists and blobs +inside a message have reasonable size. However, Cap'n Proto takes the +philosophy that any security mistake that is likely to be common in +naively-written application code is in fact a bug in Cap'n Proto -- we should +provide defenses so that the application developer doesn't have to. + +To fix the problem, this change institutes the policy that, for the purpose of +the "message traversal limit", a list of zero-sized elements will be counted as +if each element were instead one word wide. The message traversal limit is an +existing anti-amplification measure implemented by Cap'n Proto; see: + +https://capnproto.org/encoding.html#amplification-attack + +Preventative measures +===================== + +This problem was discovered through fuzz testing using American Fuzzy Lop, +which identified the problem as a "hang", although in fact the test case just +took a very long time to complete. We are incorporating testing with AFL into +our release process going forward. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/2015-03-05-0-c++-addl-cpu-amplification.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/2015-03-05-0-c++-addl-cpu-amplification.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,67 @@ +Problem +======= + +CPU usage amplification attack, similar to previous vulnerability +[2015-03-02-2][1]. + +Discovered by +============= + +David Renshaw <david@sandstorm.io> + +Announced +========= + +2015-03-05 + +CVE +=== + +CVE-2015-2313 + +Impact +====== + +- Remotely cause a peer to execute a tight `for` loop counting from 0 to + 2^29, possibly repeatedly, by sending it a small message. This could enable + a DoS attack by consuming CPU resources. + +Fixed in +======== + +- git commit [80149744bdafa3ad4eedc83f8ab675e27baee868][0] +- release 0.5.1.2: + - Unix: https://capnproto.org/capnproto-c++-0.5.1.2.tar.gz + - Windows: https://capnproto.org/capnproto-c++-win32-0.5.1.2.zip +- release 0.4.1.1: + - Unix: https://capnproto.org/capnproto-c++-0.4.1.2.tar.gz +- release 0.6 (future) + +[0]: https://github.com/sandstorm-io/capnproto/commit/80149744bdafa3ad4eedc83f8ab675e27baee868 + +Details +======= + +Advisory [2015-03-02-2][1] described a bug allowing a remote attacker to +consume excessive CPU time or other resources using a specially-crafted message. +The present advisory is simply another case of the same bug which was initially +missed. + +The new case occurs only if the application invokes the `totalSize()` method +on an object reader. + +The new case is somewhat less severe, in that it only spins in a tight `for` +loop that doesn't call any application code. Only CPU time is possibly +consumed, not RAM or other resources. However, it is still possible to create +significant delays for the receiver with a specially-crafted message. + +[1]: https://github.com/sandstorm-io/capnproto/blob/master/security-advisories/2015-03-02-2-all-cpu-amplification.md + +Preventative measures +===================== + +Our fuzz test actually covered this case, but we didn't notice the problem +because the loop actually completes in less than a second. We've added a new +test case which is more demanding, and will make sure that when we do extended +testing with American Fuzzy Lop, we treat unexpectedly long run times as +failures. diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/2017-04-17-0-apple-clang-elides-bounds-check.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/2017-04-17-0-apple-clang-elides-bounds-check.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,147 @@ +Problem +======= + +Some bounds checks are elided by Apple's compiler and possibly others, leading +to a possible attack especially in 32-bit builds. + +Although triggered by a compiler optimization, this is a bug in Cap'n Proto, +not the compiler. + +Discovered by +============= + +Kenton Varda <kenton@cloudflare.com> <kenton@sandstorm.io> + +Announced +========= + +2017-04-17 + +CVE +=== + +CVE-2017-7892 + +Impact +====== + +- Remotely segfault a 32-bit application by sending it a malicious message. +- Exfiltration of memory from such applications **might** be possible, but our + current analysis indicates that other checks would cause any such attempt to + fail (see below). +- At present I've only reproduced the problem on Mac OS using Apple's + compiler. Other compilers and platforms do not seem to apply the problematic + optimization. + +Fixed in +======== + +- git commit [52bc956459a5e83d7c31be95763ff6399e064ae4][0] +- release 0.5.3.1: + - Unix: https://capnproto.org/capnproto-c++-0.5.3.1.tar.gz + - Windows: https://capnproto.org/capnproto-c++-win32-0.5.3.1.zip +- release 0.6 (future) + +[0]: https://github.com/sandstorm-io/capnproto/commit/52bc956459a5e83d7c31be95763ff6399e064ae4 + +Details +======= + +*The following text contains speculation about the exploitability of this +bug. This is provided for informational purposes, but as such speculation is +often shown to be wrong, you should not rely on the accuracy of this +section for the safety of your service. Please update your library.* + +During regular testing in preparation for a release, it was discovered that +when Cap'n Proto is built using the current version of Apple's Clang compiler +in 32-bit mode with optimizations enabled, it is vulnerable to attack via +specially-crafted malicious input, causing the application to read from an +invalid memory location and crash. + +Specifically, a malicious message could contain a [far pointer][1] pointing +outside of the message. Cap'n Proto messages are broken into segments of +continuous memory. A far pointer points from one segment into another, +indicating both the segment number and an offset within that segment. If a +malicious far pointer contained an offset large enough to overflow the pointer +arithmetic (wrapping around to the beginning of memory), then it would escape +bounds checking, in part because the compiler would elide half of the bounds +check as an optimization. + +That is, the code looked like (simplification): + + word* target = segmentStart + farPointer.offset; + if (target < segmentStart || target >= segmentEnd) { + throwBoundsError(); + } + doSomething(*target); + +To most observers, this code would appear to be correct. However, as it turns +out, pointer arithmetic that overflows is undefined behavior under the C +standard. As a result, the compiler is allowed to assume that the addition on +the first line never overflows. Since `farPointer.offset` is an unsigned +number, the compiler is able to conclude that `target < segmentStart` always +evaluates false. Thus, the compiler removes this part of the check. +Unfortunately, in the case of overflow, this is exactly the part of the check +that we need. + +Based on both fuzz testing and logical analysis, I believe that the far pointer +bounds check is the only check affected by this optimization. If true, then it +is not possible to exfiltrate memory through this vulnerability: the target of +a far pointer is always expected to be another pointer, which in turn points to +the final object. That second pointer will go through its own bounds checking, +which will fail (unless it somehow happens to point back into the message +bounds, in which case no harm is done). + +I believe this bug does not affect any common 64-bit platform because the +maximum offset expressible by a far pointer is 2^32 bytes. In order to trigger +the bug in a 64-bit address space, the message location would have to begin +with 0xFFFFFFFF (allocated in the uppermost 4GB of address space) and the +target would have to begin with 0x00000000 (allocated in the lowermost 4GB of +address space). Typically, on 64-bit architectures, the upper half of the +address space is reserved for the OS kernel, thus a message could not possibly +be located there. + +I was not able to reproduce this bug on other platforms, perhaps because the +compiler optimization is not applied by other compilers. On Linux, I tested GCC +4.9, 5.4, and 6.3, as well as Clang 3.6, 3.8, and 4.0. None were affected. +Nevertheless, the compiler behavior is technically allowed, thus it should be +assumed that it can happen on other platforms as well. + +The specific compiler version which was observed to be affected is: + + $ clang++ --version + Apple LLVM version 8.1.0 (clang-802.0.41) + Target: x86_64-apple-darwin16.5.0 + Thread model: posix + InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin + +(Note: Despite being Clang-based, Apple's compiler version numbers have no +apparent relationship to Clang version numbers.) + +[1]: https://capnproto.org/encoding.html#inter-segment-pointers + +Preventative measures +===================== + +The problem was caught by running Cap'n Proto's standard fuzz tests in this +configuration. These tests are part of the Cap'n Proto test suite which runs +when you invoke `make check`, which Cap'n Proto's installation instructions +suggest to all users. + +However, these fuzz tests were introduced after the 0.5.x release branch, +hence are not currently present in release versions of Cap'n Proto, only in +git. A 0.6 release will come soon, fixing this. + +The bugfix commit forces the compiler to perform all checks by casting the +relevant pointers to `uintptr_t`. According to the standard, unsigned integers +implement modulo arithmetic, rather than leaving overflow undefined, thus the +compiler cannot make the assumptions that lead to eliding the check. This +change has been shown to fix the problem in practice. However, this quick fix +does not technically avoid undefined behavior, as the code still computes +pointers that point to invalid locations before they are checked. A +technically-correct solution has been implemented in the next commit, +[2ca8e41140ebc618b8fb314b393b0a507568cf21][2]. However, as this required more +extensive refactoring, it is not appropriate for cherry-picking, and will +only land in versions 0.6 and up. + +[2]: https://github.com/sandstorm-io/capnproto/commit/2ca8e41140ebc618b8fb314b393b0a507568cf21 diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/security-advisories/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/security-advisories/README.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,11 @@ +# Security Advisories + +This directory contains security advisories issued for Cap'n Proto. + +Each advisory explains not just the bug that was fixed, but measures we are taking to avoid the class of bugs in the future. + +Note that Cap'n Proto has not yet undergone formal security review and therefore should not yet be trusted for reading possibly-malicious input. Even so, Cap'n Proto intends to be secure and we treat security bugs no less seriously than we would had security review already taken place. + +## Reporting Bugs + +Please report security bugs to [security@sandstorm.io](mailto:security@sandstorm.io). diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/style-guide.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/style-guide.md Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,624 @@ +# KJ Style + +This document describes how to write C++ code in KJ style. It may be compared to the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html). + +KJ style is used by KJ (obviously), [Cap'n Proto](https://capnproto.org), [Sandstorm.io](https://sandstorm.io), and possibly other projects. When submitting code to these projects, you should follow this guide. + +**Table of Contents** + +- [Rule #1: There are no rules](#rule-1-there-are-no-rules) +- [Design Philosophy](#design-philosophy) + - [Value Types vs. Resource Types](#value-types-vs-resource-types) + - [RAII (Resource Acquisition Is Initialization)](#raii-resource-acquisition-is-initialization) + - [Ownership](#ownership) + - [No Singletons](#no-singletons) + - [Exceptions](#exceptions) + - [Threads vs. Event Loops](#threads-vs-event-loops) + - [Lazy input validation](#lazy-input-validation) + - [Premature optimization fallacy](#premature-optimization-fallacy) + - [Text is always UTF-8](#text-is-always-utf-8) +- [C++ usage](#c-usage) + - [Use C++11 (or later)](#use-c11-or-later) + - [Heap allocation](#heap-allocation) + - [Pointers, references](#pointers-references) + - [Constness](#constness) + - [Inheritance](#inheritance) + - [Exceptions Usage](#exceptions-usage) + - [Template Metaprogramming](#template-metaprogramming) + - [Global Constructors](#global-constructors) + - [`dynamic_cast`](#dynamic_cast) + - [Use of Standard libraries](#use-of-standard-libraries) + - [Compiler warnings](#compiler-warnings) + - [Tools](#tools) +- [Irrelevant formatting rules](#irrelevant-formatting-rules) + - [Naming](#naming) + - [Spacing and bracing](#spacing-and-bracing) + - [Comments](#comments) + - [File templates](#file-templates) + +## Rule #1: There are no rules + +This guide contains suggestions, not rules. + +If you wish to submit code to a project following KJ style, you should follow the guide so long as there is no good reason not to. You should not break rules just because you feel like it -- consistency is important for future maintainability. But, if you have a good, pragmatic reason to break a rule, do it. Do not ask permission. Just do it. + +## Design Philosophy + +This section contains guidelines on software design that aren't necessarily C++-specific (though KJ's preferences here are obviously influenced by C++). + +### Value Types vs. Resource Types + +There are two kinds of types: values and resources. Value types are simple data structures; they serve no purpose except to represent pure data. Resource types represent live objects with state and behavior, and often represent resources external to the program. + +* Value types make sense to copy (though they don't necessarily have copy constructors). Resource types are not copyable. +* Value types always have move constructors (and sometimes copy constructors). Resource types are not movable; if ownership transfer is needed, the resource must be allocated on the heap. +* Value types almost always have implicit destructors. Resource types may have an explicit destructor. +* Value types should only be compared by value, not identity. Resource types can only be compared by identity. +* Value types make sense to serialize. Resource types fundamentally cannot be serialized. +* Value types rarely use inheritance and never have virtual methods. Resource types commonly do. +* Value types generally use templates for polymorphism. Resource types generally use virtual methods / abstract interfaces. +* You might even say that value types are used in functional programming style while resource types are used in object-oriented style. + +In Cap'n Proto there is a very clear distinction between values and resources: interfaces are resource types whereas everything else is a value. + +### RAII (Resource Acquisition Is Initialization) + +KJ code is RAII-strict. Whenever it is the case that "this block of code cannot exit cleanly without performing operation X", then X *must* be performed in a destructor, so that X will happen regardless of how the block is exited (including by exception). + +Use the macros `KJ_DEFER`, `KJ_ON_SCOPE_SUCCESS`, and `KJ_ON_SCOPE_FAILURE` to easily specify some code that must be executed on exit from the current scope, without the need to define a whole class with a destructor. + +Be careful when writing complicated destructors. If a destructor performs multiple cleanup actions, you generally need to make sure that the latter actions occur even if the former ones throw an exception. For this reason, a destructor should generally perform no more than one cleanup action. If you need to clean up multiple things, have you class contain multiple members representing the different things that need cleanup, each with its own destructor. This way, if one member's destructor throws, the others still run. + +### Ownership + +Every object has an "owner". The owner may be another object, or it may be a stack frame (which is in turn owned by its parent stack frame, and so on up to the top frame, which is owned by the thread, which itself is an object which is owned by something). + +The owner decides when to destroy an object. If the owner itself is destroyed, everything it owns must be transitively destroyed. This should be accomplished through RAII style. + +The owner specifies the lifetime of the object and how the object may be accessed. This specification may be through documented convention or actually enforced through the type system; the latter is preferred when possible. + +An object can never own itself, including transitively. + +When declaring a pointer to an object which is owned by the scope, always use `kj::Own`. Regular C++ pointers and references always point to objects that are *not* owned. + +When passing a regular C++ pointer or reference as a parameter or return value of a function, care must be taken to document assumptions about the lifetime of the object. In the absence of documentation, make the following assumptions: + +* A pointer or reference passed as a constructor parameter must remain valid for the lifetime of the constructed object. +* A pointer or reference passed as a function or method parameter must remain valid until the function returns. In the case that the function returns a promise, then the object must remain live until the promise completes or is canceled. +* A pointer or reference returned by a method remains valid at least until the object whose method was called is destroyed. +* A pointer or reference returned by a stand-alone function likely refers to content of one of the function's parameters, and remains valid until that parameter is destroyed. + +Note that ownership isn't just about memory management -- it matters even in languages that implement garbage collection! Unless an object is 100% immutable, you need to keep track of who is allowed to modify it, and that generally requires declaring an owner. Moreover, even with GC, resource types commonly need `close()` method that acts very much like a C++ destructor, leading to all the same considerations. It is therefore completely wrong to believe garbage collection absolves you of thinking about ownership -- and this misconception commonly leads to huge problems in large-scale systems written in GC languages. + +#### Reference Counting + +Reference counting is allowed, in which case an object will have multiple owners. + +When using reference counting, care must be taken to ensure that there is a clear contract between all owners about how the object shall be accessed. In general, this should mean one of the following: + +* Reference-counted value types should be immutable. +* Reference-counted resource types should have an interface which clearly specifies how multiple clients should coordinate. + +Care must also be taken to avoid cyclic references (which would constitute self-ownership, and would cause a memory leak). Think carefully about what the object ownership graph looks like. + +Avoid reference counting when it is not absolutely necessary. + +Keep in mind that atomic (thread-safe) reference counting can be extremely slow. Consider non-atomic reference counting if it is feasible under your threading philosophy (under KJ's philosophy, non-atomic reference counting is OK). + +### No Singletons + +A "singleton" is any mutable object or value that is globally accessible. "Globally accessible" means that the object is declared as a global variable or static member variable, or that the object can be found by following pointers from such variables. + +Never use singletons. Singletons cause invisible and unexpected dependencies between components of your software that appear unrelated. Worse, the assumption that "there should only be one of this object per process" is almost always wrong, but its wrongness only becomes apparent after so much code uses the singleton that it is infeasible to change. Singleton interfaces ofter turn into unusable monstrosities in an attempt to work around the fact that they should never have been a singleton in the first place. + +See ["Singletons Considered Harmful"](http://www.object-oriented-security.org/lets-argue/singletons) for a complete discussion. + +#### Global registries are singletons + +An all-too-common-pattern in modular frameworks is to design a way to register named components via global-scope macros. For example: + + // BAD BAD BAD + REGISTER_PLUGIN("foo", fooEntryPoint); + +This global registry is a singleton, and has many of the same problems as singletons. Don't do this. Again, see ["Singletons Considered Harmful"](http://www.object-oriented-security.org/lets-argue/singletons) for discussion. + +#### What to do instead + +High-level code (such as your `main()` function) should explicitly initialize the components the program needs. If component Foo depends on component Bar, then Foo's constructor should take a pointer to Bar as a parameter; the high-level code can then point each component at its dependencies explicitly. + +For example, instead of a global registry, have high-level code construct a registry object and explicitly call some `register()` method to register each component that should be available through it. This way, when you read your `main()` function it's easy to see what components your program is using. + +#### Working around OS singletons + +Unfortunately, operating system APIs are traditionally singleton-heavy. The most obvious example is, of course, the filesystem. + +In order to use these APIs while avoiding the problems of singletons, try to encapsulate OS singletons inside non-singleton interfaces as early on as possible in your program. For example, you might define an abstract interface called `Directory` with an implementation `DiskDirectory` representing a directory on disk. In your `main()` function, create two `DiskDirectory`s representing the root directory and the current working directory. From then on, have all of your code operate in terms of `Directory`. Pass the original `DiskDirectory` pointers into the components that need it. + +### Exceptions + +An exception represents something that "should never happen", assuming everything is working as expected. Of course, things that "should never happen" in fact happen all the time. But, a program should never be written in such a way that it _expects_ an exception under normal circumstances. + +Put another way, exceptions are a way to achieve _fault tolerance_. Throwing an exception is a less-disruptive alternative to aborting the process. Exceptions are a _logistical_ construct, as opposed to a semantic one: an exception should never be part of your "business logic". + +For example, exceptions may indicate conditions like: + +* Logistics of software development: + * There is a bug in the code. + * The requested method is not implemented. +* Logistics of software usage: + * There is an error in the program's configuration. + * The input is invalid. +* Logistics of distributed systems: + * A network connection was reset. + * An optimistic transaction was aborted due to concurrent modification. +* Logistics of physical computation: + * The system's resources are exhausted (e.g. out of memory, out of disk space). + * The system is overloaded and must reject some requests to avoid long queues. + +#### Business logic should never catch + +If you find that callers of your interface need to catch and handle certain kinds of exceptions in order to operate correctly, then you must change your interface (or overload it) such that those conditions can be handled without an exception ever being thrown. For example, if you have a method `Own open(StringPtr name)` that opens a file, you may also want to offer `Maybe> openIfExists(StringPtr name)` that returns null rather than throwing an exception if the file is not found. (But you should probably keep `open()` as well, for the convenience of the common case where the caller will just throw an exception anyway.) + +Note that with this exception philosophy, Java-style "checked exceptions" (exceptions which are explicitly declared to be thrown by an interface) make no sense. + +#### How to handle an exception + +In framework and logistical code, you may catch exceptions and try to handle them. Given the nature of exceptions, though, there are only a few things that are reasonable to do when receiving an exception: + +* On network disconnect or transaction failures, back up and start over from the beginning (restore connections and state, redo operations). +* On resources exhausted / overloaded, retry again later, with exponential back-off. +* On unimplemented methods, retry with a different implementation strategy, if there is one. +* When no better option is available, report the problem to a human (the user and/or the developer). + +#### Exceptions can happen anywhere (including destructors) + +Any piece of code may contain a bug. Therefore, an exception can happen anywhere. This includes destructors. It doesn't matter how much you argue that destructors should not throw exceptions, because that is equivalent to arguing that code should not have bugs. We all wish our code never had bugs, but nevertheless it happens. + +Unfortunately, C++ made the awful decision that an exception thrown from a destructor that itself is called during stack unwind due to some other exception should cause the process to abort. This is an error in the language specification. Apparently, the committee could not agree on any other behavior, so they chose the worst possible behavior. + +If exceptions are merely a means to fault tolerance, then it is perfectly clear what should happen in the case that a second exception is thrown while unwinding due to a first: the second exception should merely be discarded, or perhaps attached to the first as a supplementary note. The catching code usually does not care about the exception details anyway; it's just going to report that something went wrong, then maybe try to continue executing other, unrelated parts of the program. In fact, in most cases discarding the secondary exception makes sense, because it is often simply a side-effect of the fact that the code didn't complete normally, and so provides no useful additional information. + +Alas, C++ is what it is. So, in KJ, we work around the problem in a couple ways: + +* `kj::UnwindDetector` may be used to detect when a destructor is called during unwind and squelch secondary exceptions. +* The `KJ_ASSERT` family of macros -- from which most exceptions are thrown in the first place -- implement a concept of "recoverable" exceptions, where it is safe to continue execution without throwing in cases where throwing would be bad. Assert macros in destructors must always be recoverable. + +#### Allowing `-fno-exceptions` + +KJ and Cap'n Proto are designed to function even when compiled with `-fno-exceptions`. In this case, throwing an exception behaves differently depending on whether the exception is "fatal" or "recoverable". Fatal exceptions abort the process. On a recoverable exception, on the other hand, execution continues normally, perhaps after replacing invalid data with some safe default. The exception itself is stored in a thread-local variable where code up the stack can check for it later on. + +This compromise is made only so that C++ applications which eschew exceptions are still able to use Cap'n Proto. We do NOT recommend disabling exceptions if you have a choice. Moreover, code following this style guide (other than KJ and Cap'n Proto) is not required to be `-fno-exceptions`-safe, and in fact we recommend against it. + +### Threads vs. Event Loops + +Threads are hard, and synchronization between threads is slow. Even "lock-free" data structures usually require atomic operations, which are costly, and such algorithms are notoriously difficult to get right. Fine-grained synchronization will therefore be expensive at best and highly unstable at worst. + +KJ instead prefers event loop concurrency. In this model, each event callback is effectively a transaction; it does not need to worry about concurrent modification within the body of the function. + +Multiple threads may exist, but each one has its own event loop and is treated as sort of a lightweight process with shared memory. Every object in the process either belongs to a specific thread (who is allowed to read and modify it) or is transitively immutable (in which case all threads can safely read it concurrently). Threads communicate through asynchronous message-passing. In fact, the only big difference between KJ-style threads compared to using separate processes is that threads may transfer ownership of in-memory objects as part of a message send. + +Note that with hardware transactional memory, it may become possible to execute a single event loop across multiple CPU cores while behaving equivalently to a single thread, by executing each event callback as a hardware transaction. If so, this will be implemented as part of KJ's event loop machinery, transparently to apps. + +### Lazy input validation + +As we all know, you should always validate your input. + +But, when should you validate it? There are two plausible answers: + +* Upfront, on receipt. +* Lazily, on use. + +Upfront validation occasionally makes sense for the purpose of easier debugging of problems: if an error is reported earlier, it's easier to find where it came from. + +However, upfront validation has some big problems. + +* It is inefficient, as it requires a redundant pass over the data. Lazy validation, in contrast, occurs at a time when you have already loaded the data for the purpose of using it. Extra passes are often cache-unfriendly and/or entail redundant I/O operations. + +* It encourages people to skip validation at time of use, on the assumption that it was already validated earlier. This is dangerous, as it entails a non-local assumption. E.g. are you really sure that there is no way to insert data into your database without having validated it? Are you really sure that the data hasn't been corrupted? Are you really sure that your code will never be called in a new situation where validation hasn't happened? Are you sure the data cannot have been modified between validation and use? In practice, you should be validating your input at time of use _even if_ you know it has already been checked previously. + +* The biggest problem: Upfront validation tends not to match actual usage, because the validation site is far away from the usage site. Over time, as the usage code changes, the validator can easily get out-of-sync. Note that this could mean the code itself is out-of-sync, or it could be that running servers are out-of-sync, because they have different update schedules. Or, the validator may be written with incorrect assumptions in the first place. The consequences of this can be severe. Protocol Buffers' concept of "required fields" is essentially an upfront validation check that [has been responsible for outages of Google Search, GMail, and others](https://capnproto.org/faq.html#how-do-i-make-a-field-required-like-in-protocol-buffers). + +We recommend, therefore, that validation occur at time of use. Code should be written to be tolerant of validation failures. For example, most code dealing with UTF-8 text should treat it as a blob of bytes, not worrying about invalid byte sequences. When you actually need to decode the code points -- such as to display them -- you should do something reasonable with invalid sequences -- such as display the Unicode replacement character. + +With that said, when storing data in a database long-term, it can make sense to perform an additional validation check at time of storage, in order to more directly notify the caller that their input was invalid. This validation should be considered optional, since the data will be validated again when it is read from storage and used. + +### Premature optimization fallacy + +_"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."_ -- Donald Knuth + +_"The improvement in speed from Example 2 to Example 2a is only about 12%, and many people would pronounce that insignificant. The conventional wisdom shared by many of today’s software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by penny-wise- and-pound-foolish programmers, who can’t debug or maintain their “optimized” programs. In established engineering disciplines a 12% improvement, easily obtained, is never considered marginal; and I believe the same viewpoint should prevail in software engineering. Of course I wouldn’t bother making such optimizations on a one-shot job, but when it’s a question of preparing quality programs, I don’t want to restrict myself to tools that deny me such efficiencies."_ -- Donald Knuth, **in the same paper**. + +(Credit: [Stop Misquoting Donald Knuth!](http://www.joshbarczak.com/blog/?p=580)) + +You should not obsess over optimization or write unmaintainable code for the sake of speed. + +However, you _should_ be thinking about efficiency of all the code you write. When writing efficient code is not much harder and not much uglier than inefficient code, you should be writing efficient code. If the efficient approach to a problem would take _much_ longer than the inefficient way then go ahead and code the inefficient way first, but in many cases it's not that stark. Rewriting your code later is _much_ more expensive than writing it correctly the first time, because by then you'll have lost context. + +You should be constantly aware of whether the code you are writing is low-level (called frequently) or high-level (called infrequently). You should consider optimizations relative to the code's level. In low-level code, optimizations like avoiding heap allocations may make sense. In high-level code you should not worry about heap, but you may still want to think about expensive operations like disk I/O or contacting remote servers (things that low-level code should never do in the first place, of course). + +Programmers who ignore efficiency until they have no choice inevitably end up shipping slow, bloated software. Their code's speed is always pushing the boundary of bearability, because they only do anything about it when it becomes unbearable. But programs which are "bearable" can still make users intensely unhappy due to their slowness. + +### Text is always UTF-8 + +Always encode text as UTF-8. Always assume text is encoded as UTF-8. + +(Do not, however, assume text is _valid_ UTF-8; see the section on lazy validation.) + +Do not write code that tries to distinguish characters. Unless you are writing code to render text to a display, you probably don't care about characters. Besides, Unicode itself contains code points which act as modifiers to previous characters; it's futile for you to handle these. Most code only really cares about bytes. + +Note that even parsers for machine-readable text-based languages (config languages, programming languages, other DSLs) do not really care about "characters" in the Unicode sense because such languages are almost always pure-ASCII. They may allow arbitrary UTF-8 in, say, string literals, but only ASCII code points have any special meaning to the language. Therefore, they still only care about bytes (since ASCII characters are single-byte, and multi-byte UTF-8 codepoints never contain individual bytes in the ASCII range). + +## C++ usage + +This section contains guidelines for usage of C++ language features. + +### Use C++11 (or later) + +C++11 completely transformed the way the C++ language is used. New code should take heavy advantage of the new features, especially rvalue references (move semantics) and lambda expressions. + +KJ requires C++11. Application code (not used as a library) may consider requiring C++14, or even requiring a specific compiler and tracking the latest language features implemented by it. + +### Heap allocation + +* Never write `new` or `delete` explicitly. Use `kj::heap` to allocate single objects or `kj::heapArray` for arrays; these return "owned" pointers (`kj::Own` or `kj::Array`, respectively) which enforce RAII/ownership semantics. You may transfer ownership of these pointers via move semantics, but otherwise the objects will be automatically deleted when they go out of scope. This makes memory leaks very rare in KJ code. +* Only allocate objects on the heap when you actually need to be able to move them. Otherwise, avoid a heap allocation by declaring the object directly on the stack or as a member of some other object. +* If a class's copy constructor would require memory allocation, consider providing a `clone()` method instead and deleting the copy constructor. Allocation in implicit copies is a common source of death-by-1000-cuts performance problems. `kj::String`, for example, is movable but not copyable. + +### Pointers, references + +* Pointers and references always point to things that are owned by someone else. Take care to think about the lifetime of that object compared to the lifetime of the pointer. +* Always use `kj::ArrayPtr` rather than `T*` to point to an array. +* Always use `kj::StringPtr` rather than `const char*` to point to a NUL-terminated string. +* Always use `kj::Maybe` rather than `T*` when a pointer can be null. This forces the user to check for null-ness. +* In other cases, prefer references over pointers. Note, though, that members of an assignable type cannot be references, so you'll need to use pointers in that case (darn). + +**Rationale:** There is an argument that says that references should always be const and pointers mutable, because then when you see `foo(&bar)` you know that the function modifies `bar`. This is a nice theory, but in practice real C++ code is rarely so consistent that you can use this as a real signal. We prefer references because they make it unambiguous that the value cannot be null. + +### Constness + +* Treat `const`-ness as transitive. So, if you have a const instance of a struct which in turn contains a pointer (or reference), treat that pointer as pointing to const even if it is not declared as such. To enforce this, copyable classes which contain pointer fields should declare their copy constructor as `T(T& other)` rather than `T(const T& other)` (and similarly for assignment operators) in order to prevent escalating a transitively-const pointer to non-const via copy. You may inherit `kj::DisallowConstCopy` to force the implicit copy constructor and assignment operator to be declared this way. +* Try to treat const/non-const pointers like shared/exclusive locks. So, when a new const pointer to an object is created, all other pointers should also be considered const at least until the new pointer is destroyed. When a new non-const pointer is created, all other pointers should be considered not dereferenceable until the non-const pointer is destroyed. In theory, these rules help keep different objects from interfering with each other by modifying some third object in incompatible ways. Note that these rules are (as I understand it) enforceable by the Rust type system. +* `const` methods are safe to call on the same object from multiple threads simultaneously. Conversely, it is unsafe to call a non-`const` method if any other thread might be calling methods on that object concurrently. Note that KJ defines synchronization primitives including `kj::Mutex` which integrate nicely with this rule. + +### Inheritance + +A class is either an interface or an implementation. Interfaces have no fields. Implementations have no non-final virtual methods. You should not mix these: a class with state should never have virtual methods, as this leads to fragile base class syndrome. + +Interfaces should NOT declare a destructor, because: + +* That destructor is never called anyway (because we don't use `delete`, and `kj::Own` has a different mechanism for dispatching the destructor). +* Declaring destructors for interfaces is tedious. +* If you declare a destructor but do not declare it `noexcept(false)`, C++11 will (regrettably) decide that it is `noexcept` and that all derived classes must also have a `noexcept` destructor, which is wrong. (See the exceptions philosophy section for discussion on exceptions in destructors.) + +Multiple inheritance is allowed and encouraged, keeping in mind that you are usually inheriting interfaces. + +You should think carefully about whether to use virtual inheritance; it's not often needed, and it is relatively inefficient, but in complex inheritance hierarchies it becomes critical. + +Implementation inheritance (that is, inheriting an implementation class) is allowed as a way to compose classes without requiring extra allocations. For example, Cap'n Proto's `capnp::InputStreamMessageReader` implements the `capnp::MessageReader` interface by reading from a `kj::InputStream`, which is itself an interface. One implementation of `kj::InputStream` is `kj::FdInputStream`, which reads from a unix file descriptor. As a convenience, Cap'n Proto defines `capnp::StreamFdMessageReader` which multiply-inherits `capnp::InputStreamMessageReader` and `kj::FdInputStream` -- that is, it inherits two implementations, and even inherits the latter privately. Many style guides would consider this taboo. The benefit, though, is that people can declare this composed class on the stack as one unit, with no heap allocation, and end up with something that they can directly treat as a `capnp::MessageReader`; any other solution would lose one of these benefits. + +### Exceptions Usage + +KJ's exception philosophy is described earlier in this document. Here we describe only how to actually use exceptions in code. + +Never use `throw` explicitly. Almost all exceptions should originate from the `KJ_ASSERT`, `KJ_REQUIRE`, and `KJ_SYSCALL` macros (see `kj/debug.h`). These macros allow you to easily attach useful debug information to the exception message without spending time on string formatting. + +Never declare anything `noexcept`. As explained in the philosophy section, whether you like it or not, bugs can happen anywhere and therefore exceptions can happen anywhere. `noexcept` causes the process to abort on exceptions. Aborting is _never_ the right answer. + +Explicit destructors must always be declared `noexcept(false)`, to work around C++11's regrettable decision that destructors should be `noexcept` by default. In destructors, always use `kj::UnwindDetector` or make all your asserts recoverable in order to ensure that an exception is not thrown during unwind. + +Do not fret too much about recovering into a perfectly consistent state after every exception. That's not the point. The point is to be able to recover at all -- to _improve_ reliability, but not to make it perfect. So, write your code to do a reasonable thing in most cases. + +For example, if you are implementing a data structure like a vector, do not worry about whether move constructors might throw. In practice, it is extraordinarily rare for move constructors to contain any code that could throw. So just assume they don't. Do NOT do what the C++ standard library does and require that all move constructors be explicitly `noexcept`, because people will not remember to mark their move constructors `noexcept`, and you'll just be creating a huge headache for everyone with _no practical benefit_. + +### Template Metaprogramming + +#### Reducing Verbosity + +Before C++11, it was common practice to write "template functions" in the form of a templated struct which contained a single member representing the output of the function. For example, you might see `std::is_integral::value` to check if `int` is integral. This pattern is excessively verbose, especially when composed into complex expressions. + +In C++11, we can do better. Where before you would have declared a struct named `Foo` with a single member as described above, in C++11 you should: + +1. Define the struct as before, but with the name `Foo_`. +2. Define a template `Foo` which directly aliases the single member of `Foo_`. If the output is a type, use a template `using`, whereas if the output is a value, use a `constexpr` function. + +Example: + + template struct IsConst_ { static constexpr bool value = false; }; + template struct IsConst_ { static constexpr bool value = true; }; + template constexpr bool isConst() { return IsConst_::value; } + // Return true if T is const. + +Or: + + template struct UnConst_ { typedef T Type; }; + template struct UnConst_ { typedef T Type; }; + template using UnConst = typename UnConst_::Type; + // If T is const, return the underlying non-const type. + // Otherwise, just return T. + +Now people can use your template metafunction without the pesky `::Type` or `::value` suffix. + +#### Other hints + +* To explicitly disable a template under certain circumstances, bind an unnamed template parameter to `kj::EnableIf`: + + template ())> + void mutate(T& ptr); + // T must not be const. + +* Say you're writing a template type with a constructor function like so: + + template + Wrapper makeWrapper(T&& inner); + // Wraps `inner` and returns the wrapper. + + Should `inner` be taken by reference or by value here? Both might be useful, depending on the use case. The right answer is actually to support both: if the input is an lvalue, take it by reference, but if it's an rvalue, take it by value (move). And as it turns out, if you write your declaration exactly as shown above, this is exactly what you get, because if the input is an lvalue, `T` will implicitly bind to a reference type, whereas if the input is an rvalue or rvalue reference, T will not be a reference. + + In general, you should assume KJ code in this pattern uses this rule, so if you are passing in an lvalue but don't actually want it wrapped by reference, wrap it in `kj::mv()`. + +* Never use function or method pointers. Prefer templating across functors (like STL does), or for non-templates use `kj::Function` (which will handle this for you). + +### Global Constructors + +Do not declare global or static variables with dynamic constructors. Global constructors disproportionately hurt startup time because they force code to be paged in before it is really needed. They also are usually only needed by singletons, which you should not be using in general (see philosophy section). + +You can have global constants of non-trivial class type as long as they are declared `constexpr`. If you want to declare complex data structures as constants, try to declare all the pieces as separate globals that reference each other, so that nothing has to be heap allocated and everything can be `constexpr`. + +Use Clang's `-Wglobal-constructors` warning to catch mistakes. + +### `dynamic_cast` + +Do not use `dynamic_cast` as a way to implement polymorphism. That is, do not write long blocks of if/else statements each trying to cast an object to a different derived class to handle in a different way. Instead, extend the base class's interface to cover the functionality you need. + +With that said, `dynamic_cast` is not always bad. It is fine to use `dynamic_cast` for "logistical" improvements, such as optimization. As a rule of thumb, imagine if `dynamic_cast` were replaced with a function that always returned null. Would your code still be correct (if, perhaps, slower, or with less detailed logging, etc.)? If so, then your use of `dynamic_cast` is fine. + +#### `-fno-rtti` + +The KJ and Cap'n Proto libraries are designed to function correctly when compiled with `-fno-rtti`. To that end, `kj::dynamicCastIfAvailable` is a version of `dynamic_cast` that, when compiled with `-fno-rtti`, always returns null, and KJ and Cap'n Proto code always uses this version. + +We do NOT recommend disabling RTTI in your own code. + +### Lambdas + +Lamba capture lists must never use `=` to specify "capture all by value", because this makes it hard to review the capture list for possible lifetime issues. + +Capture lists *may* use `&` ("capture all by reference") but *only* in cases where it is known that the lambda will not outlive the current stack frame. In fact, they generally *should* use `&` in this case, to make clear that there are no lifetime issues to think about. + +### Use of Standard libraries + +#### C++ Standard Library + +The C++ standard library is old and full of a lot of cruft. Many APIs are designed in pre-C++11 styles that are no longer ideal. Mistakes like giving copy constructors to objects that own heap space (because in the absence of move semantics, it was needed for usability) and atomically-reference-counted strings (intended as an optimization to avoid so much heap copying, but actually a pessimization) are now baked into the library and cannot change. The `iostream` library was designed before anyone knew how to write good C++ code and is absolutely awful by today's standards. Some parts of the library, such as ``, are over-engineered, designed by committees more interested in theoretical perfection than practicality. To add insult to injury, the library's naming style does not distinguish types from values. + +For these reasons and others, KJ aims to be a replacement for the C++ standard libraries. + +It is not there yet. As of this writing, the biggest missing piece is that KJ provides no implementation of maps or sets, nor a `sort()` function. + +We recommend that KJ code use KJ APIs where available, falling back to C++ standard types when necessary. To avoid breaking clients later, avoid including C++ standard library headers from other headers; only include them from source files. + +All users of the KJ library should familiarize themselves at least with the declarations in the following files, as you will use them all the time: + +* `kj/common.h` +* `kj/memory.h` +* `kj/array.h` +* `kj/string.h` +* `kj/vector.h` +* `kj/debug.h` + +#### C Library + +As a general rule of thumb, C library functions documented in man section 3 should be treated with skepticism. + +Do not use the C standard I/O functions -- your code should never contain `FILE*`. For formatting strings, `kj::str()` is much safer and easier than `sprintf()`. For debug logging, `KJ_DBG()` will produce more information with fewer keystrokes compared to `printf()`. For parsing, KJ's parser combinator library is cleaner and more powerful than `scanf()`. `fread()` and `fwrite()` imply buffering that you usually don't want; use `kj/io.h` instead, or raw file descriptors. + +### Compiler warnings + +Use the following warning settings with Clang or GCC: + +* `-Wall -Wextra`: Enable most warnings. +* `-Wglobal-constructors`: (Clang-only) This catches global variables with constructors, which KJ style disallows (see above). You will, however, want to disable this warning in tests, since test frameworks use global constructors and are excepted from the style rule. +* `-Wno-sign-compare`: While comparison between signed and unsigned values could be a serious bug, we find that in practice this warning is almost always spurious. +* `-Wno-unused-parameter`: This warning is always spurious. I have never seen it find a real bug. Worse, it encourages people to delete parameter names which harms readability. + +For development builds, `-Werror` should also be enabled. However, this should not be on by default in open source code as not everyone uses the same compiler or compiler version and different compiler versions often produce different warnings. + +### Tools + +We use: + +* Clang for compiling. +* `KJ_DBG()` for simple debugging. +* Valgrind for complicated debugging. +* [Ekam](https://github.com/sandstorm-io/ekam) for a build system. +* Git for version control. + +## Irrelevant formatting rules + +Many style guides dwell on formatting. We mention it only because it's vaguely nice to have some formatting consistency, but know that this section is the *least* relevant section of the document. + +As a code reviewer, when you see a violation of formatting rules, think carefully about whether or not it really matters that you point it out. If you believe the author may be unfamiliar with the rules, it may be worth letting them know to read this document, if only so that they can try to be consistent in the future. However, it is NOT worth the time to comment on every misplaced whitespace. As long as the code is readable, move on. + +### Naming + +* Type names: `TitleCase` +* Variable, member, function, and method names: `camelCase` +* Constant and enumerant names: `CAPITAL_WITH_UNDERSCORES` +* Macro names: `CAPITAL_WITH_UNDERSCORES`, with an appropriate project-specific prefix like `KJ_` or `CAPNP_`. +* Namespaces: `oneword`. Namespaces should be kept short, because you'll have to type them a lot. The name of KJ itself was chosen for the sole purpose of making the namespace easy to type (while still being sufficiently unique). Use a nested namespace called `_` to contain package-private declarations. +* Files: `module-name.c++`, `module-name.h`, `module-name-test.c++` + +**Rationale:** There has never been broad agreement on C++ naming style. The closest we have is the C++ standard library. Unfortunately, the C++ standard library made the awful decision of naming types and values in the same style, losing a highly useful visual cue that makes programming more pleasant, and preventing variables from being named after their type (which in many contexts is perfectly appropriate). + +Meanwhile, the Java style, which KJ emulates, has been broadly adopted to varying degrees in other languages, from Javascript to Haskell. Using a similar style in KJ code makes it less jarring to switch between C++ and those other languages. Being consistent with Javascript is especially useful because it is the one language that everyone pretty much has to use, due to its use in the web platform. + +There has also never been any agreement on C++ file extensions, for some reason. The extension `.c++`, though not widely used, is accepted by all reasonable tools and is clearly the most precise choice. + +### Spacing and bracing + +* Indents are two spaces. +* Never use tabs. +* Maximum line length is 100 characters. +* Indent a continuation line by four spaces, *or* line them up nicely with the previous line if it makes it easier to read. +* Place a space between a keyword and an open parenthesis, e.g.: `if (foo)` +* Do not place a space between a function name and an open parenthesis, e.g.: `foo(bar)` +* Place an opening brace at the end of the statement which initiates the block, not on its own line. +* Place a closing brace on a new line indented the same as the parent block. If there is post-brace code related to the block (e.g. `else` or `while`), place it on the same line as the closing brace. +* Always place braces around a block *unless* the block is so short that it can actually go on the same line as the introductory `if` or `while`, e.g.: `if (done) return;`. +* `case` statements are indented within the `switch`, and their following blocks are **further** indented (so the actual statements in a case are indented four spaces more than the `switch`). +* `public:`, `private:`, and `protected:` are reverse-indented by one stop. +* Statements inside a `namespace` are **not** indented unless the namespace is a short block that is just forward-declaring things at the top of a file. +* Set your editor to strip trailing whitespace on save, otherwise other people who use this setting will see spurious diffs when they edit a file after you. + + + if (foo) { + bar(); + } else if (baz) { + qux(quux); + } else { + corge(); + } + + if (done) return; + + switch (grault) { + case GARPLY: + print("mew"); + break; + case WALDO: { // note: needs braces due to variable + Location location = findWaldo(); + print(location); + break; + } + } + +
+ + namespace external { + class Forward; + class Declarations; + namespace nested { + class More; + } + } + + namespace myproj { + + class Fred { + public: + Fred(); + ~Fred(); + private: + int plugh; + }; + + } // namespace myproj + +**Rationale:** Code which is inconsistently or sloppily formatted gives the impression that the author is not observant or simply doesn't care about quality, and annoys other people trying to read your code. + +Other than that, there is absolutely no good reason to space things one way or another. + +### Comments + +* Always use line comments (`//`). Never use block comments (`/**/`). + + **Rationale:** Block comments don't nest. Block comments tend to be harder to re-arrange, whereas a group of line comments can be moved easily. Also, typing `*` is just way harder than typing `/` so why would you want to? + +* Write comments that add useful information that the reader might not already know. Do NOT write comments which say things that are already blatantly obvious from the code. For example, for a function `void frob(Bar bar)`, do not write a comment `// Frobs the Bar.`; that's already obvious. It's better to have no comment. + +* Doc comments go **after** the declaration. If the declaration starts a block, the doc comment should go inside the block at the top. A group of related declarations can have a single group doc comment after the last one as long as there are no black lines between the declarations. + + int foo(); + // This is documentation for foo(). + + class Bar { + // This is documentation for Bar. + public: + Bar(); + + inline int baz() { return 5; } + inline int qux() { return 6; } + // This is documentation for baz() and qux(). + }; + + **Rationale:** When you start reading a doc comment, the first thing you want to know is *what the heck is being documented*. Having to scroll down through a long comment to see the declaration, then back up to read the docs, is bad. Sometimes, people actually repeat the declaration at the top of the comment just so that it's visible. This is silly. Let's just put the comment after the declaration. + +* TODO comments are of the form `// TODO(type): description`, where `type` is one of: + * `now`: Do before next `git push`. + * `soon`: Do before next stable release. + * `someday`: A feature that might be nice to have some day, but no urgency. + * `perf`: Possible performance enhancement. + * `security`: Possible security concern. (Used for low-priority issues. Obviously, code with serious security problems should never be written in the first place.) + * `cleanup`: An improvement to maintainability with no user-visible effects. + * `port`: Things to do when porting to a new platform. + * `test`: Something that needs better testing. + * `msvc`: Something to revisit when the next, hopefully less-broken version of Microsoft Visual Studio becomes available. + * others: Additional TODO types may be defined for use in certain contexts. + + **Rationale:** Google's guide suggests that TODOs should bear the name of their author ("the person to ask for more information about the comment"), but in practice there's no particular reason why knowing the author is more useful for TODOs than for any other comment (or, indeed, code), and anyway that's what `git blame` is for. Meanwhile, having TODOs classified by type allows for useful searches, so that e.g. release scripts can error out if release-blocking TODOs are present. + +### File templates + +Generally, a "module" should consist of three files: `module.h`, `module.c++`, and `module-test.c++`. One or more of these can be omitted if it would otherwise be empty. Use the following templates when creating new files. + +Headers: + + // Project Name - Project brief description + // Copyright (c) 2015 Primary Author and contributors + // + // Licensed under the Whatever License blah blah no warranties. + + #ifndef HEADER_PATH_FILENAME_H_ + #define HEADER_PATH_FILENAME_H_ + // Documentation for file. + + #include + + namespace myproject { + + // declarations + + namespace _ { // private + + // private declarations + + } // namespace _ (private) + + } // namespace myproject + + #endif // HEADER_PATH_FILENAME_H_ + +Source code: + + // Project Name - Project brief description + // Copyright (c) 2015 Primary Author and contributors + // + // Licensed under the Whatever License blah blah no warranties. + + #include "this-module.h" + #include + + namespace myproject { + + // definitions + + } // namespace myproject + +Test: + + // Project Name - Project brief description + // Copyright (c) 2015 Primary Author and contributors + // + // Licensed under the Whatever License blah blah no warranties. + + #include "this-module.h" + #include + + namespace myproject { + namespace { + + // KJ_TESTs + + } // namespace + } // namespace myproject + +Note that in both the source and test files, you should *always* include the corresponding header first, in order to ensure that it is self-contained (does not secretly require including some other header before it). diff -r 206f0eb279b8 -r 45360b968bf4 src/capnproto-0.6.0/super-test.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/capnproto-0.6.0/super-test.sh Mon May 22 10:01:37 2017 +0100 @@ -0,0 +1,429 @@ +#! /usr/bin/env bash + +set -euo pipefail + +doit() { + echo "@@@@ $@" + "$@" +} + +QUICK= + +PARALLEL=$(nproc 2>/dev/null || echo 1) + +while [ $# -gt 0 ]; do + case "$1" in + -j* ) + PARALLEL=${1#-j} + ;; + test ) + ;; # nothing + quick ) + QUICK=quick + ;; + caffeinate ) + # Re-run preventing sleep. + shift + exec caffeinate -ims $0 $@ + ;; + tmpdir ) + # Clone to a temp directory. + if [ "$#" -lt 2 ]; then + echo "usage: $0 tmpdir NAME [COMMAND]" >&2 + exit 1 + fi + DIR=/tmp/$2 + shift 2 + if [ -e $DIR ]; then + if [ "${DIR/*..*}" = "" ]; then + echo "NO DO NOT PUT .. IN THERE IT'S GOING TO GO IN /tmp AND I'M GONNA DELETE IT" >&2 + exit 1 + fi + if [ ! -e "$DIR/super-test.sh" ]; then + echo "$DIR exists and it doesn't look like one of mine." >&2 + exit 1 + fi + # make distcheck leaves non-writable files when it fails, so we need to chmod to be safe. + chmod -R +w $DIR + rm -rf $DIR + fi + git clone . $DIR + cd $DIR + exec ./super-test.sh "$@" + ;; + remote ) + if [ "$#" -lt 2 ]; then + echo "usage: $0 remote HOST [COMMAND]" >&2 + exit 1 + fi + HOST=$2 + shift 2 + echo "=========================================================================" + echo "Pushing code to $HOST..." + echo "=========================================================================" + BRANCH=$(git rev-parse --abbrev-ref HEAD) + ssh $HOST '(chmod -fR +w tmp-test-capnp || true) && rm -rf tmp-test-capnp && mkdir tmp-test-capnp && git init tmp-test-capnp' + git push ssh://$HOST/~/tmp-test-capnp "$BRANCH:test" + ssh $HOST "cd tmp-test-capnp && git checkout test" + exec ssh $HOST "cd tmp-test-capnp && ./super-test.sh $@ && cd .. && rm -rf tmp-test-capnp" + ;; + compiler ) + if [ "$#" -lt 2 ]; then + echo "usage: $0 compiler CXX_NAME" >&2 + exit 1 + fi + export CXX="$2" + shift + ;; + clang ) + export CXX=clang++ + ;; + gcc-4.9 ) + export CXX=g++-4.9 + ;; + gcc-4.8 ) + export CXX=g++-4.8 + ;; + gcc-4.7 ) + export CXX=g++-4.7 + ;; + mingw ) + if [ "$#" -ne 2 ]; then + echo "usage: $0 mingw CROSS_HOST" >&2 + exit 1 + fi + CROSS_HOST=$2 + + cd c++ + test -e configure || doit autoreconf -i + test ! -e Makefile || (echo "ERROR: Directory unclean!" >&2 && false) + + export WINEPATH='Z:\usr\'"$CROSS_HOST"'\lib;Z:\usr\lib\gcc\'"$CROSS_HOST"'\6.3-win32;Z:'"$PWD"'\.libs' + + doit ./configure --host="$CROSS_HOST" --disable-shared CXXFLAGS='-static-libgcc -static-libstdc++' + + doit make -j$PARALLEL check + doit make distclean + rm -f *-mingw.exe + exit 0 + ;; + android ) + # To install Android SDK: + # - Download command-line tools: https://developer.android.com/studio/index.html#command-tools + # - Run $SDK_HOME/tools/bin/sdkmanager platform-tools 'platforms;android-25' 'system-images;android-25;google_apis;armeabi-v7a' emulator 'build-tools;25.0.2' ndk-bundle + # - Run $SDK_HOME/tools/bin/avdmanager create avd -n capnp -k 'system-images;android-25;google_apis;armeabi-v7a' -b google_apis/armeabi-v7a + # - Run $SDK_HOME/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm --api 24 --install-dir $TOOLCHAIN_HOME + if [ "$#" -ne 4 ]; then + echo "usage: $0 android SDK_HOME TOOLCHAIN_HOME CROSS_HOST" >&2 + exit 1 + fi + SDK_HOME=$2 + TOOLCHAIN_HOME=$3 + CROSS_HOST=$4 + + cd c++ + test -e configure || doit autoreconf -i + test ! -e Makefile || (echo "ERROR: Directory unclean!" >&2 && false) + doit ./configure --disable-shared + doit make -j$PARALLEL capnp capnpc-c++ + + cp capnp capnp-host + cp capnpc-c++ capnpc-c++-host + + export PATH="$TOOLCHAIN_HOME/bin:$PATH" + doit make distclean + doit ./configure --host="$CROSS_HOST" --with-external-capnp --disable-shared CXXFLAGS='-pie -fPIE' CAPNP=./capnp-host CAPNPC_CXX=./capnpc-c++-host + + doit make -j$PARALLEL + doit make -j$PARALLEL capnp-test + + echo "Starting emulator..." + trap 'kill $(jobs -p)' EXIT + # TODO(someday): Speed up with KVM? Then maybe we won't have to skip fuzz tests? + $SDK_HOME/emulator/emulator -avd capnp -no-window & + $SDK_HOME/platform-tools/adb 'wait-for-device' + echo "Waiting for localhost to be resolvable..." + doit $SDK_HOME/platform-tools/adb shell 'while ! ping -c 1 localhost > /dev/null 2>&1; do sleep 1; done' + # TODO(cleanup): With 'adb shell' I find I cannot put files anywhere, so I'm using 'su' a + # lot here. There is probably a better way. + doit $SDK_HOME/platform-tools/adb shell 'su 0 tee /data/capnp-test > /dev/null' < capnp-test + doit $SDK_HOME/platform-tools/adb shell 'su 0 chmod a+rx /data/capnp-test' + doit $SDK_HOME/platform-tools/adb shell 'cd /data && CAPNP_SKIP_FUZZ_TEST=1 su 0 /data/capnp-test && echo ANDROID_""TESTS_PASSED' | tee android-test.log + grep -q ANDROID_TESTS_PASSED android-test.log + + doit make distclean + rm -f capnp-host capnpc-c++-host + exit 0 + ;; + cmake ) + cd c++ + rm -rf cmake-build + mkdir cmake-build + cd cmake-build + doit cmake -G "Unix Makefiles" .. + doit make -j$PARALLEL check + exit 0 + ;; + exotic ) + echo "=========================================================================" + echo "MinGW 64-bit" + echo "=========================================================================" + "$0" mingw x86_64-w64-mingw32 + echo "=========================================================================" + echo "MinGW 32-bit" + echo "=========================================================================" + "$0" mingw i686-w64-mingw32 + echo "=========================================================================" + echo "Android" + echo "=========================================================================" + "$0" android /home/kenton/android-sdk-linux /home/kenton/android-24 arm-linux-androideabi + echo "=========================================================================" + echo "CMake" + echo "=========================================================================" + "$0" cmake + exit 0 + ;; + clean ) + rm -rf tmp-staging + cd c++ + if [ -e Makefile ]; then + doit make maintainer-clean + fi + rm -f capnproto-*.tar.gz samples/addressbook samples/addressbook.capnp.c++ \ + samples/addressbook.capnp.h + exit 0 + ;; + help ) + echo "usage: $0 [COMMAND]" + echo "commands:" + echo " test Runs tests (the default)." + echo " clang Runs tests using Clang compiler." + echo " gcc-4.7 Runs tests using gcc-4.7." + echo " gcc-4.8 Runs tests using gcc-4.8." + echo " gcc-4.9 Runs tests using gcc-4.9." + echo " remote HOST Runs tests on HOST via SSH." + echo " mingw Cross-compiles to MinGW and runs tests using WINE." + echo " android Cross-compiles to Android and runs tests using emulator." + echo " clean Delete temporary files that may be left after failure." + echo " help Prints this help text." + exit 0 + ;; + * ) + echo "unknown command: $1" >&2 + echo "try: $0 help" >&2 + exit 1 + ;; + esac + shift +done + +# Build optimized builds because they catch more problems, but also enable debugging macros. +# Enable lots of warnings and make sure the build breaks if they fire. Disable strict-aliasing +# because GCC warns about code that I know is OK. Disable sign-compare because I've fixed more +# sign-compare warnings than probably all other warnings combined and I've never seen it flag a +# real problem. Disable unused parameters because it's stupidly noisy and never a real problem. +# Enable expensive release-gating tests. +export CXXFLAGS="-O2 -DDEBUG -Wall -Wextra -Werror -Wno-strict-aliasing -Wno-sign-compare -Wno-unused-parameter -DCAPNP_EXPENSIVE_TESTS=1" + +STAGING=$PWD/tmp-staging + +rm -rf "$STAGING" +mkdir "$STAGING" +mkdir "$STAGING/bin" +mkdir "$STAGING/lib" +export PATH=$STAGING/bin:$PATH +export LD_LIBRARY_PATH=$STAGING/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} +export PKG_CONFIG_PATH=$STAGING/lib/pkgconfig + +if [ "$QUICK" = quick ]; then + echo "************************** QUICK TEST ***********************************" +fi + +echo "=========================================================================" +echo "Building c++" +echo "=========================================================================" + +# Apple now aliases gcc to clang, so probe to find out what compiler we're really using. +if (${CXX:-g++} -dM -E -x c++ /dev/null 2>&1 | grep -q '__clang__'); then + IS_CLANG=yes + DISABLE_OPTIMIZATION_IF_GCC= +else + IS_CLANG=no + DISABLE_OPTIMIZATION_IF_GCC=-O0 +fi + +if [ $IS_CLANG = yes ]; then + # Don't fail out on this ridiculous "argument unused during compilation" warning. + export CXXFLAGS="$CXXFLAGS -Wno-error=unused-command-line-argument" +else + # GCC emits uninitialized warnings all over and they seem bogus. We use valgrind to test for + # uninitialized memory usage later on. GCC 4 also emits strange bogus warnings with + # -Wstrict-overflow, so we disable it. + CXXFLAGS="$CXXFLAGS -Wno-maybe-uninitialized -Wno-strict-overflow" +fi + +cd c++ +doit autoreconf -i +doit ./configure --prefix="$STAGING" +doit make -j$PARALLEL check + +if [ $IS_CLANG = no ]; then + # Verify that generated code compiles with pedantic warnings. Make sure to treat capnp headers + # as system headers so warnings in them are ignored. + doit ${CXX:-g++} -isystem src -std=c++11 -fno-permissive -pedantic -Wall -Wextra -Werror \ + -c src/capnp/test.capnp.c++ -o /dev/null +fi + +echo "=========================================================================" +echo "Testing c++ install" +echo "=========================================================================" + +doit make install + +test "x$(which capnp)" = "x$STAGING/bin/capnp" +test "x$(which capnpc-c++)" = "x$STAGING/bin/capnpc-c++" + +cd samples + +doit capnp compile -oc++ addressbook.capnp -I"$STAGING"/include --no-standard-import +doit ${CXX:-g++} -std=c++11 addressbook.c++ addressbook.capnp.c++ -o addressbook \ + $CXXFLAGS $(pkg-config --cflags --libs capnp) +echo "@@@@ ./addressbook (in various configurations)" +./addressbook write | ./addressbook read +./addressbook dwrite | ./addressbook dread +rm addressbook addressbook.capnp.c++ addressbook.capnp.h + +doit capnp compile -oc++ calculator.capnp -I"$STAGING"/include --no-standard-import +doit ${CXX:-g++} -std=c++11 calculator-client.c++ calculator.capnp.c++ -o calculator-client \ + $CXXFLAGS $(pkg-config --cflags --libs capnp-rpc) +doit ${CXX:-g++} -std=c++11 calculator-server.c++ calculator.capnp.c++ -o calculator-server \ + $CXXFLAGS $(pkg-config --cflags --libs capnp-rpc) +rm -f /tmp/capnp-calculator-example-$$ +./calculator-server unix:/tmp/capnp-calculator-example-$$ & +sleep 0.1 +./calculator-client unix:/tmp/capnp-calculator-example-$$ +kill %+ +wait %+ || true +rm calculator-client calculator-server calculator.capnp.c++ calculator.capnp.h /tmp/capnp-calculator-example-$$ + +cd .. + +if [ "$QUICK" = quick ]; then + doit make maintainer-clean + rm -rf "$STAGING" + exit 0 +fi + +echo "=========================================================================" +echo "Testing --with-external-capnp" +echo "=========================================================================" + +doit make distclean +doit ./configure --prefix="$STAGING" --disable-shared \ + --with-external-capnp CAPNP=$STAGING/bin/capnp +doit make -j$PARALLEL check + +echo "=========================================================================" +echo "Testing --disable-reflection" +echo "=========================================================================" + +doit make distclean +doit ./configure --prefix="$STAGING" --disable-shared --disable-reflection \ + --with-external-capnp CAPNP=$STAGING/bin/capnp +doit make -j$PARALLEL check +doit make distclean + +# Test 32-bit build now while we have $STAGING available for cross-compiling. +if [ "x`uname -m`" = "xx86_64" ]; then + echo "=========================================================================" + echo "Testing 32-bit build" + echo "=========================================================================" + + if [[ "`uname`" =~ CYGWIN ]]; then + # It's just not possible to run cygwin32 binaries from within cygwin64. + + # Build as if we are cross-compiling, using the capnp we installed to $STAGING. + doit ./configure --prefix="$STAGING" --disable-shared --host=i686-pc-cygwin \ + --with-external-capnp CAPNP=$STAGING/bin/capnp + doit make -j$PARALLEL + doit make -j$PARALLEL capnp-test.exe + + # Expect a cygwin32 sshd to be listening at localhost port 2222, and use it + # to run the tests. + doit scp -P 2222 capnp-test.exe localhost:~/tmp-capnp-test.exe + doit ssh -p 2222 localhost './tmp-capnp-test.exe && rm tmp-capnp-test.exe' + + doit make distclean + + elif [ "x${CXX:-g++}" != "xg++-4.8" ]; then + doit ./configure CXX="${CXX:-g++} -m32" --disable-shared + doit make -j$PARALLEL check + doit make distclean + fi +fi + +echo "=========================================================================" +echo "Testing c++ uninstall" +echo "=========================================================================" + +doit ./configure --prefix="$STAGING" +doit make uninstall + +echo "=========================================================================" +echo "Testing c++ dist" +echo "=========================================================================" + +doit make -j$PARALLEL distcheck +doit make distclean +rm capnproto-*.tar.gz + +if [ "x`uname`" = xLinux ]; then + echo "=========================================================================" + echo "Testing generic Unix (no Linux-specific features)" + echo "=========================================================================" + + doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -DKJ_USE_FUTEX=0 -DKJ_USE_EPOLL=0" + doit make -j$PARALLEL check + doit make distclean +fi + +echo "=========================================================================" +echo "Testing with -fno-rtti and -fno-exceptions" +echo "=========================================================================" + +# GCC miscompiles capnpc-c++ when -fno-exceptions and -O2 are specified together. The +# miscompilation happens in one specific inlined call site of Array::dispose(), but this method +# is inlined in hundreds of other places without issue, so I have no idea how to narrow down the +# bug. Clang works fine. So, for now, we disable optimizations on GCC for -fno-exceptions tests. + +doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-rtti" +doit make -j$PARALLEL check +doit make distclean +doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-exceptions $DISABLE_OPTIMIZATION_IF_GCC" +doit make -j$PARALLEL check +doit make distclean +doit ./configure --disable-shared CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions $DISABLE_OPTIMIZATION_IF_GCC" +doit make -j$PARALLEL check + +# Valgrind is currently "experimental and mostly broken" on OSX and fails to run the full test +# suite, but I have it installed because it did manage to help me track down a bug or two. Anyway, +# skip it on OSX for now. +if [ "x`uname`" != xDarwin ] && which valgrind > /dev/null; then + doit make distclean + + echo "=========================================================================" + echo "Testing with valgrind" + echo "=========================================================================" + + doit ./configure --disable-shared CXXFLAGS="-g" + doit make -j$PARALLEL + doit make -j$PARALLEL capnp-test + # Running the fuzz tests under Valgrind is a great thing to do -- but it takes + # some 40 minutes. So, it needs to be done as a separate step of the release + # process, perhaps along with the AFL tests. + CAPNP_SKIP_FUZZ_TEST=1 doit valgrind --leak-check=full --track-fds=yes --error-exitcode=1 ./capnp-test +fi + +doit make maintainer-clean + +rm -rf "$STAGING"